Repository navigation
C7b build-ahead: os migrate organization-ownership --apply and E5's pure row→definition mappers in core (drafts from main; the --apply PR lands after #15204 stage 8) #22937
Copy link
Copy link
Open
Labels
domain:enginepm:dispatchedpriority:p1High: required for production / M2High: required for production / M2target:v18
Description
Part of #15211
Handed out of the #15194 epic subtree to the domain:engine lane. The epic PM (session_01Rerax7QTjKMPCUZxQUtPFR, marchtian) did this at the maintainer's request in its session on 2026-10-12: clear next-step work that can be built ahead goes to lane PMs, and the maintainer's tasks are high priority (priority:p1). This card is the lane's claim surface. #15211 stays open and blocked for its landing gate; this card carries no Blocked-by:, because building ahead is not landing.
Why now
- feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211 is release-cut condition (b) of the final v18 release (6102862135). The
nextprerelease is exempt (maintainer ruling 6117174845). - feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211's
Blocked-by: #15196/#15204gate its landing. Building ahead follows the epic's rule: "Development runs ahead of landing" (6095755866). - On
main(06cc45dc36),os migrate organization-ownershipalready exists as a read-only plan (packages/cli/src/commands/migrate/organization-ownership.ts,utils/organization-ownership-plan.ts,utils/organization-ownership-inventory.ts). The--applyhalf of feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211's scope is not built.
Scope (read #15211's body in full first; it governs)
- E5's mappers, in core. Seat answer 6110777865 (E5 → A), and its note on feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211, 6110790598.
- Add pure functions beside
convertPositionBindingRows(packages/core/src/security/position-binding-conversion.ts:90), each with pins:- a permission-set row → definition, the logic of
permissionSetBodyFromRow(packages/plugins/plugin-security/src/permission-set-projection.ts:409); - a position row → definition, the mapping in
position-environment-backfill.ts.
- a permission-set row → definition, the logic of
- Use new files in core only. ⛔ Do not edit
packages/plugins/plugin-security/**. Those files belong to refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204: stage 8 (session_01MGoWgeE8rhsrig77V4oUZn, building now) and 7a/7b, which will switch to these functions and delete their copies. - This PR changes no behaviour, and may land when green.
- Add pure functions beside
--apply, per feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211's scope:- the explicit backup acknowledgement;
- the fate order attribution → verified id→name rewrite → mirror deletion → column drops;
- idempotent, and resumable from a recorded checkpoint;
- an operator ceremony, ⛔ never a boot step.
- The id→name rewrite:
sys_user_permission_set.permission_set_id→permission_set. The column stays until C7b (refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 stage-8 refresh 6116546399, E3): stage 8 redeclares it asField.text, keeping its stored ids, the unique index (user_id,permission_set_id,organization_id) and the(permission_set_id)index. C7b drops the column and both indexes, and judges whether the unique index still means anything once new grants write NULL there. - Mirror deletion stays behind fate 2's own gate: C2's rewrite report shows every reference resolves by name.
- The inventory's
authoredcategories convert through step 1's mappers (6110790598). - It absorbs
sys_business_unit_memberis unadjudicated inPLATFORM_OBJECT_TENANCY, so seed-replayed and system-written membership rows land organization-less #14570 and plugin-sharing: after the #15030 revert, 17.x still cannot reach a NULL-org-seeded business unit from an org-stamped rule — and #14547, its only tracker, is closed #15086, as feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211 says. - This PR stays a draft until refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write under
singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204's stage 8 is onmain. Then mergemain, re-run, and land.
- feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211's acceptance: a fixture database carrying every fate.
Boundaries
- ⛔ No stacked PRs; every PR is based on
main. - ⛔ Never touch
content/docs/releases/orCHANGELOG.md. - ⛔ Never edit plugin-security files or
content/docs/permissions/system-context.mdxhere. - Coordination: post on this card. Post one pointer on refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write under
singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 when a PR opens, so the epic seat can align stage 8 and 7a/7b with it. Questions go here, and the epic seat answers here. - Re-verify on
mainbefore building that no branch or PR already does this (the maintainer's 「不要重复开发」).
Refs
#15211 · ADR-0131 D10, D4 · seat answers 6110777865 and 6116546399 · seat note 6110790598 · release-cut record 6102862135 · ruling 6117174845.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
domain:enginepm:dispatchedpriority:p1High: required for production / M2High: required for production / M2target:v18
Activity
objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 1 · 2026-10-12T04:05Z · PR 1 of 2 (the core mappers)
Session:
session_01ADzJtzYTLUfgrRZHxkagkXAccount:
os-steve(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-22937-core-row-definition-mappersWorktree:
objectstack-issue-22937Domain:
domain:engineSeat:
domain:engine#2(seat post #20966); the lane's only seated PMPriority: dispatched out of order, beyond the seat's default batch of 3 (4 in flight, inside the ceiling of 5), on the maintainer's order in this session: 「objectstack#22937 插队,现在就派」.
File surface for PR 1 (read on
origin/main1bd612bd68; stop on a breach and explain it in the report). ⛔ Classes, positions and functions only, in every artefact.packages/core/src/security/, besideposition-binding-conversion.ts. They hold two pure functions, each with pins:permissionSetBodyFromRow(packages/plugins/plugin-security/src/permission-set-projection.ts);packages/plugins/plugin-security/src/position-environment-backfill.ts.packages/core/src/security/index.ts: export the two, asconvertPositionBindingRowsis exported.packages/plugins/plugin-security/**(refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 stage 8 and 7a/7b own those files and switch to these functions later). ⛔ Notcontent/docs/permissions/system-context.mdx, notcontent/docs/releases/, notCHANGELOG.md.--applyinpackages/cli, cross-lanedomain:cli) is claimed after PR 1 lands, based onmain, and stays a draft until refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 stage 8 is onmain(card body).Container & model:
M,mode:subagent,model: default(dispatch-gates --tier: no path-derived mandate)Clause-②: yes
@objectstack/core's published surface (.re-exports./security/index.js). So the changeset ships@objectstack/coreminor, and PR 1 owes one contract-tier review before the queue.Responsibility: n/a — not a defect card (a build-ahead execution card, part of feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211)
Thread-read: none
Serial constraints cleared: no open PR touches
packages/core/src/security/or theorganization-ownershipfiles inpackages/cli. No branch or PR builds these mappers or--apply(checked at claim, per the card's 「不要重复开发」). refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 stage 8 (session_01MGoWgeE8rhsrig77V4oUZn) is building inplugin-security, which is disjoint. This seat's in-flight [Decision] security(objectql): a validation rule that reads one hop through a master-detail FK still reads the header elevated, so an unreadable header's answer varies with its stored state after ruling A #22892, [finding] email_template: a Studio save of the same template in a second locale replaces the first locale's overlay at the next boot (sys_metadata keeps one overlay row per type and name) #22877 and finding: a multi-valued reference field (lookup/userwithmultiple: true) admits an element of the wrong shape: REST stores an embedded record[{ id }]with 201, where the single-valued field refuses itinvalid_type(ADR-0104 D1) #22908 sit inobjectqlandmetadata-*, also disjoint.objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{ "issue": 22937, "status": "done", "branch": "claude/issue-22937-core-row-definition-mappers", "pr": "https://github.com/objectstack-ai/objectstack/pull/22959", "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent; the parent PM session)", "premise_still_valid": true, "summary": "PR 1 of 2 (draft #22959, base main, head e975c410bc): two pure functions in @objectstack/core beside convertPositionBindingRows, each in a new file with pins and exported from security/index.ts. permissionSetDefinitionFromRow reproduces plugin-security's permissionSetBodyFromRow (parseMaybeJson and the PermissionSetSchema-shape key filter copied into core); positionDefinitionFromRow reproduces the backfill's mapping, positionBodyFromRow (it lives in position-write-through.ts, not position-environment-backfill.ts). Byte-for-behaviour equivalence with both originals was measured once over 60,244 and 20,737 generated rows with 0 differences and a positive control that does differ; core cannot import plugin-security without a new dependency, so the permanent pins assert the documented outputs. No behaviour change, no plugin-security edit, no new dependency; Section 2's premises held (the export path, purity, core already imports @objectstack/spec/security values). No duplicate: no branch or open PR builds these mappers at start (the #15204 branches were read; S8 only deletes core's row-active.ts). CI not awaited (in progress at report time); contract-tier review is owed (Clause-2 yes).", "tests": "At final head e975c410bc: pnpm --filter @objectstack/core test -> Test Files 96 passed, Tests 2402 passed (both new files listed by vitest list --project local); pnpm --filter @objectstack/core typecheck -> exit 0, check:test-typecheck OK 4 files / 4 errors held, none in the new files (they are in tsconfig.test.json's --listFiles program). New pins: permission-set-row-definition.test.ts 12 tests, position-row-definition.test.ts 9 tests, green. Equivalence (one-time, scratch, not committed): tsx imports the plugin-security originals and the core functions from source and compares with util.isDeepStrictEqual plus key order plus JSON.stringify plus thrown errors -> permission sets 60244 rows 0 differing, positions 20737 rows 0 differing; positive control with mutated variants -> 7174 and 1152 differing. Ablation (fix committed first; subject imported by relative path, so no dist leg): scripts/ablation-replace.mjs WRAP inside a script with an absolute-path trap restore. Leg 1 label fallback 'label: row?.label ?? row?.name,' -> 'label: row?.label,' (anchor 1->0, replacement 0->1, blob f4e53ca6a2cb -> 549050ec1563) -> 2 of 12 failed (label rule, defaults row); restored, blob f4e53ca6a2cb == HEAD, git diff HEAD empty. Leg 2 delegatable \"row.delegatable === '1'\" -> \"row.delegatable === 'one'\" (blob b998eca94d1a -> 45a6a73356db) -> 1 of 9 failed (delegatable rule); restored, blob b998eca94d1a == HEAD, diff empty. Direction observed: red, as expected. Builds: CJS and ESM dist of core both export the two functions; both .d.ts declare them. Lint narrowed and proven: eslint over the 5 changed TS files, 0/0; population read from eslint.config.mjs (all 5 inside, none ignored); invariance: no type-aware linting and the local plugins are per-file AST rules, so no untouched file's verdict can move; full pnpm lint is CI's.", "mcp_calls": "0", "api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, via scripts/pm/with-fleet.sh --via dispatch and scripts/pm/post-stamped.mjs), executed as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (draft #22959), POST /repos/objectstack-ai/objectstack/issues/22959/assignees (os-steve), POST /repos/objectstack-ai/objectstack/issues/22937/comments (this report). Not REST: 3 git push of the branch (empty probe, WIP commit, doc commit plus merge of origin/main). Label writes: none.", "open_questions": [], "out_of_scope_findings": [ "carrier: PR 2 of #22937 and #15204's 7b · the backfill's two decisions around the mapping stay in plugin-security, by the card's row-to-definition scope: the door's position-name grammar (metadataDoorAcceptsPositionName) and the rows-of-one-name-must-agree check. 7b's deletion of position-write-through.ts removes the predicate; PR 2 can rely on the metadata door's own refusal or move the predicate into core then. The core mapping's key order is pinned so a serialized comparison of two rows' definitions stays meaningful · noted in the PR's Acceptance notes, not filed", "carrier: #15204 S8 (session_01MGoWgeE8rhsrig77V4oUZn) · S8 deletes packages/core/src/security/row-active.ts and its export block in security/index.ts; this PR adds its block after convertPositionBindingRows, a different hunk, and neither new file imports row-active.ts · noted, not filed", "carrier: none needed · @objectstack/runtime and @objectstack/plugin-hono-server export * from @objectstack/core, so they re-export the two functions; git grep finds the four new names only in core, no collision · noted in Acceptance notes, not filed" ], "gates": [ "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0", "node scripts/check-adr-0087-registration.mjs --self-test :: exit 0", "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0", "node scripts/check-changeset-no-major.mjs --self-test :: exit 0", "node scripts/check-ci-filter-parity.mjs :: exit 0", "node scripts/check-closing-keyword-parity.mjs :: exit 0", "node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0", "node scripts/check-comment-mask-adoption.mjs :: exit 0", "node scripts/check-comment-mask-adoption.mjs --self-test :: exit 0", "node scripts/check-comment-mask-corpus.mjs :: exit 0", "node scripts/check-dev-prereqs.mjs --self-test :: exit 0", "node scripts/check-dts-emitted.mjs --self-test :: exit 0", "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0", "node scripts/check-empty-changeset.mjs --self-test :: exit 0", "node scripts/check-issue-citations.mjs :: exit 0", "node scripts/check-keyed-text-bounds.mjs :: exit 0", "node scripts/check-keyed-text-bounds.mjs --self-test :: exit 0", "node scripts/check-platform-object-tenancy-census.mjs :: exit 0", "node scripts/check-platform-object-tenancy-census.mjs --self-test :: exit 0", "node scripts/check-plugin-teardown-shape.mjs :: exit 0", "node scripts/check-plugin-teardown-shape.mjs --self-test :: exit 0", "node scripts/check-registry-log-declared.mjs :: exit 0", "node scripts/check-registry-log-declared.mjs --self-test :: exit 0", "node scripts/check-rest-log-spy-declared.mjs :: exit 0", "node scripts/check-rest-log-spy-declared.mjs --self-test :: exit 0", "node scripts/check-system-context-census.mjs :: exit 0", "node scripts/check-system-context-census.mjs --self-test :: exit 0", "node scripts/check-undeclared-dep-imports.mjs :: exit 0", "node scripts/check-undeclared-dep-imports.mjs --self-test :: exit 0", "node scripts/docs-audit/check-affected-docs.mjs :: exit 0", "node scripts/docs-audit/check-drift-comment.mjs :: exit 0", "node scripts/pm/release-rehearsal-clone.mjs --self-test :: exit 0", "node scripts/release-pending-publish.mjs --self-test :: exit 0", "pnpm --filter @objectstack/spec run check:duration-unit-keys :: exit 0", "pnpm check:changeset-gate-self-tests :: exit 0", "pnpm check:cross-package-test-inputs :: exit 0", "pnpm check:doc-authoring :: exit 0", "pnpm check:driver-memory-census :: exit 0", "pnpm check:dts-closure :: exit 0", "pnpm check:dual-build-cjs-loads :: exit 0", "pnpm check:engine-double-contract :: exit 0", "pnpm check:gitlink-declared :: exit 0", "pnpm check:issue-citations :: exit 0", "pnpm check:kernel-hook-pairs :: exit 0", "pnpm check:lean-entry-closure :: exit 0", "pnpm check:logger-receiver-detach :: exit 0", "pnpm check:nul-bytes :: exit 0", "pnpm check:objectql-double-limit :: exit 0", "pnpm check:objectui-changeset :: exit 0", "pnpm check:org-identifier :: exit 0", "pnpm check:page-declaration-shape :: exit 0", "pnpm check:pm-changeset-deadline-census :: exit 0", "pnpm check:published-files :: exit 0", "pnpm check:query-options-erasure :: exit 0", "pnpm check:refd-timer-probe :: exit 0", "pnpm check:slot-lookup :: exit 0", "pnpm check:sourcemap-no-sources-content :: exit 0", "pnpm check:test-source-alias :: exit 0", "pnpm check:tier-file-adoption :: exit 0", "pnpm check:type-check-coverage :: exit 0", "pnpm check:type-check-debt :: exit 0", "pnpm check:watch-hint-literal :: exit 0", "pnpm check:where-matcher :: exit 0", "pnpm --filter @objectstack/core test :: exit 0", "pnpm --filter @objectstack/core typecheck :: exit 0", "OS_VERIFY_LOCK_SLOT=issue-22937-build os-verify-lock.sh -c 'pnpm turbo run build --filter=@objectstack/core --concurrency=2' :: exit 0 (VERDICT command-exit 0; 4 tasks, 3 cached; two earlier attempts exit 99 queue-timeout and one exit 2 filter-matches-nothing, nothing ran)", "os-verify-lock.sh -c 'pnpm turbo run build --filter=@objectstack/objectql --concurrency=2 && pnpm --filter @objectstack/core exec vitest run --maxWorkers=2 (3 files)' at e975c410bc :: exit 0 (14 tasks, 8 cached; 3 files / 28 tests)", "pnpm --filter @objectstack/core exec vitest run --maxWorkers=2 src/security/permission-set-row-definition.test.ts src/security/position-row-definition.test.ts :: exit 0 (2 files / 21 tests)", "tsx equivalence.mts (scratch, one-time) at e975c410bc :: exit 0 (permission sets 60244 rows 0 differing; positions 20737 rows 0 differing)", "tsx equivalence-control.mts (mutated variants) :: exit 1 as expected (7174 and 1152 differing)", "ablate.sh permission-set leg (ablation-replace WRAP) :: wrapped vitest exit 1 as expected (2 of 12 failed); restore proven", "ablate.sh position leg (ablation-replace WRAP) :: wrapped vitest exit 1 as expected (1 of 9 failed); restore proven", "eslint --no-inline-config --format json (5 changed TS files) :: exit 0 (5 files, 0 errors, 0 warnings)", "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran.txt :: exit 0 (63 derived, 63 run, 0 NOT-MEASURED derived, 0 UNRUN)" ], "line_budget": "483 (PR additions 483 + deletions 0, 6 files; no generated files)", "deviations": [ "My first dispatch-gates re-derivation ran in the shared checkout /home/user/objectstack, because a trailing & backgrounded the whole cd-chain. It was read-only (exit 2, nothing written), and I re-derived from the worktree.", "Battery 1 at e5c8727332: check:type-check-debt hit my own 400s per-command timeout (exit 124, NOT MEASURED there), and three dist gates exited 3 (no dist, NOT MEASURED). The final union at e975c410bc supersedes it: all 63 exit 0, the dist gates measured real populations (72 / 66 / 15 packages), and check:type-check-debt finished green.", "Those dist populations exist because check:type-check-debt's re-measure builds the closure it type-checks. Between the tree it built (e5c8727332) and e975c410bc, only comment edits in my two core files touched packages/, and core's dist carries the final wording.", "Equivalence with plugin-security was measured once in a scratch script, not as a permanent test, because core cannot import plugin-security without a new dependency (the PM's route allows this).", "I merged origin/main once before opening the PR (AGENTS.md section 10). The incoming 5 commits touch docs, workflows and docs-audit scripts only.", "Commit trailers use AGENTS.md's model-free pair (Claude-Session plus the bare Co-authored-by: Claude), not the harness reminder's model-named Co-Authored-By. The PR footer uses AGENTS.md's session-URL footer, not the reminder's emoji line. The reminder yields to CLAUDE.md and AGENTS.md by its own precedence sentence.", "PR body line 2 is 'Clause-②: yes', verbatim from the claim. The changeset carries 'Clause-②: yes (widening)', following the sibling core changeset convention. These are not a conflict.", "No conflict found between the dispatch and .claude/agents/os-dev.md." ], "files_changed": [ ".changeset/22937-core-row-definition-mappers.md", "packages/core/src/security/index.ts", "packages/core/src/security/permission-set-row-definition.ts", "packages/core/src/security/permission-set-row-definition.test.ts", "packages/core/src/security/position-row-definition.ts", "packages/core/src/security/position-row-definition.test.ts" ] }objectstack-fleet commentedon Oct 12, 2026
os-dev-report
patch round 1
{ "issue": 22937, "status": "done", "branch": "claude/issue-22937-core-row-definition-mappers", "pr": "https://github.com/objectstack-ai/objectstack/pull/22959", "head": "d477e5fbef0f89677a44b55eb93ec1e170497987", "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent; the parent PM session)", "premise_still_valid": true, "summary": "Patch round 1, wording only. One commit d477e5fbef on the branch (new head; parent e975c410bc; no merge of main, since the PR reads mergeable=true): the changeset's What-is-new bullet now says the ceremony is to apply the mappers; the permission-set bullet states the label condition (null or absent falls back, an empty-string label is kept, unlike the position rule), lists null and JSON null among the facet defaults, separates 'only the definition columns are read' from 'the body is filtered to the keys PermissionSetSchema declares', and tightens 'adminScope when set' to the code's condition (truthy column that reads to a truthy value); the position bullet says description travels only as a non-empty string (null, '', absent and non-string are absent; whitespace-only travels as stored). position-row-definition.ts's docblock reads 'a null or empty column'. Each clause was read against the code and probed against core and both plugin-security originals; no code changed. The PR body was NOT patched: the role file forbids a dev PATCH of the PR body, which conflicts with this round's permission (see deviations). Its line 11 restates three corrected clauses, and the replacement is given in out_of_scope_findings for the seat to write.", "tests": "At d477e5fbef: node scripts/check-changeset-no-major.mjs --base origin/main exit 0; node scripts/check-adr-0087-registration.mjs --base origin/main exit 0 ('this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen)'); node scripts/check-empty-changeset.mjs --base origin/main exit 0 ('No empty-frontmatter changeset introduced ... No changeset from the merge base modified or deleted'); eslint --no-inline-config over position-row-definition.ts and its test exit 0, 0 errors 0 warnings each; pnpm check:nul-bytes exit 0 (10979 files, no raw control bytes); vitest on the two pin files 2 passed / 21 tests passed; pnpm --filter @objectstack/core typecheck exit 0 (check:test-typecheck OK, ledger unchanged at 4 files / 4 errors). Clause probe (scratch tsx, core vs plugin-security originals): every corrected clause holds and every case is identical to the original.", "mcp_calls": "0", "api_writes": "1 relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches via scripts/pm/post-stamped.mjs), executed as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/issues/22937/comments (this patch-round report). No issue_patch (declined, see deviations). Not REST: 1 git push of the branch (d477e5fbef). Cumulative for the card: 3 dispatches, 4 executed writes (pull create, PR assignee, 2 report comments), 4 git pushes.", "open_questions": [], "out_of_scope_findings": [ "carrier: the domain:engine seat (PR body write, which the role file reserves to the seat) · PR #22959's body line 11 restates three clauses this round corrected (unconditional label fallback, a facet-default list missing JSON null, 'adminScope travels only when set'). Replace that whole line with: - `permissionSetDefinitionFromRow(row)` (`permission-set-row-definition.ts`): one `sys_permission_set` row into the permission-set definition it carries. It reproduces `permissionSetBodyFromRow` (`plugin-security/src/permission-set-projection.ts`): the JSON-text facet columns become the camelCase body keys; `label` falls back to the name only when the column is `null` or absent (an empty-string label is kept); a facet column that is `null`, absent, an empty string, JSON `null` or unparseable text answers its default; `adminScope` travels only when the column is truthy and reads to a truthy value; only the definition columns are read, and the body is then filtered to the keys `PermissionSetSchema` declares (read from the schema's shape, never transcribed). · No other body line quotes a corrected sentence; the position bullet states no description rule, and the body never says the ceremony applies the mappers · noted, not filed" ], "gates": [ "node scripts/check-changeset-no-major.mjs --base origin/main :: exit 0", "node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0", "node scripts/check-empty-changeset.mjs --base origin/main :: exit 0", "node --stack-size=4000 node_modules/eslint/bin/eslint.js --no-inline-config --format json packages/core/src/security/position-row-definition.ts packages/core/src/security/position-row-definition.test.ts :: exit 0", "pnpm check:nul-bytes :: exit 0", "os-verify-lock.sh -c 'pnpm turbo run build --filter=@objectstack/core --concurrency=2' :: exit 0 (VERDICT command-exit 0; 4 tasks, 3 cached)", "os-verify-lock.sh -c 'pnpm --filter @objectstack/core exec vitest run --maxWorkers=2 src/security/position-row-definition.test.ts src/security/permission-set-row-definition.test.ts && pnpm --filter @objectstack/core typecheck' at d477e5fbef :: exit 0 (VERDICT command-exit 0; 2 files / 21 tests passed; typecheck exit 0, check:test-typecheck OK 4 files / 4 errors held)", "tsx probe.mts (scratch): each corrected clause against core and both plugin-security originals :: exit 0 (whitespace-only description travels; '' and null and 7 descriptions absent; position label '' replaced by the name; permission-set label '' kept and null falls back; admin_scope '0', 'false', 'null' absent; null, '', 'null', unparseable facets answer the default; every case identical to the original)" ], "line_budget": "483 (PR additions 483 + deletions 0 against main, 6 files; this round's commit is +5/-5 inside the PR's new files; no generated files)", "deviations": [ "Conflict, role file applied: this round allows at most one PR-body issue_patch, but .claude/agents/os-dev.md says a dev writes the PR body only once, at creation, never PATCHes it, and names the needed change in the report for the seat to write. The dispatch says the role file wins on conflict, so no PR-body write was made. The exact replacement for line 11 is in out_of_scope_findings.", "Beyond the four listed corrections, also changed to match the code: (a) in the same permission-set bullet, 'admin_scope -> adminScope when set' became 'only when the column is truthy and reads to a truthy value', because a set column of '0', 'false' or 'null' does not travel (probed); (b) the position pin's comment 'A blank description is the same definition as a null one' became 'An empty description ...', because the asserted value is '' and a whitespace-only description serializes differently from null. Both are comment or wording only.", "The worktree was recreated with 'git worktree add ../objectstack-issue-22937 claude/issue-22937-core-row-definition-mappers' (the local branch equals the remote head, e975c410bc). No merge of main: the PR reads mergeable=true.", "No conflict between the PM's four corrections and the code: each matches what core and the plugin originals do." ], "files_changed": [ ".changeset/22937-core-row-definition-mappers.md", "packages/core/src/security/position-row-definition.ts", "packages/core/src/security/position-row-definition.test.ts" ] }objectstack-fleet commentedon Oct 12, 2026
✅ ACCEPT: PR #22959 at
d477e5fbef(PR 1 of 2). Arming held on #22949domain:engineseat 2 (#20966) ·os-steve·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T06:17Z. Claim 6117549106; reports 6118339780 and 6118594623 (patch round 1). Checked on GitHub rather than taken from the reports. Classes, positions and functions only.main, assigneeos-steve;Part of #22937, with no closing keyword, as PR 1 of 2 should have (PR 2 completes the card);Clause-②: yes, matching the claim and, asyes (widening), the changeset.check-governed-merges --pr 22959: not governed);packages/plugins/plugin-security/**,content/docs/releases/orCHANGELOG.md.permissionSetDefinitionFromRowandpositionDefinitionFromRow, plus their two row types, besideconvertPositionBindingRows, exported from core's.entry. They are re-exported through@objectstack/runtimeand@objectstack/plugin-hono-serverwith no collision. Both are pure, and nothing calls them yet. Read side by side, they give the same output as the plugin originalspermissionSetBodyFromRowandpositionBodyFromRow. The dev's one-time equivalence run agreed: 60,244 and 20,737 rows, 0 differing, with a positive control that does differ. No dependency is added.@objectstack/coreminor, a non-breaking widening, so no ADR-0087 marker is owed. After patch round 1, every sentence matches the code. That round removed the false "blank" sentence and corrected four loose ones, and the seat corrected the matching PR-body line.e975c410bcand a delta PASS ond477e5fbef. Both records are on the PR (CONTRACT_REVIEW_TIER, isolated reviewers, read-only).singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204's 7b);security/index.tsis a disjoint hunk;export *are noted.Landing: held. CI on
d477e5fbefis green except theTest Coreaggregator's suite-duration ceiling step:@objectstack/cloud-connection174.50s against 163.89s, which is #22949. Every shard is green, the drift step included. The PR is not armed red.mainhas moved since the merge base, so the dev mergesorigin/mainonce, which is a real merge, not an empty commit. The seat arms on the first head whose required contexts are allsuccess, after confirming that the net diff is unchanged.objectstack-fleet commentedon Oct 12, 2026
os-dev-report
patch round 2 (merge of main)
{ "issue": 22937, "status": "done", "branch": "claude/issue-22937-core-row-definition-mappers", "pr": "https://github.com/objectstack-ai/objectstack/pull/22959", "head": "9e864370ea36d81143dc92610fc1c03912266ec1", "merged_origin_main": "e23eccb164e2e5bd4acc5221b2d9f733818258fa", "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent; the parent PM session)", "premise_still_valid": true, "summary": "Patch round 2: one merge of origin/main (e23eccb164) into the branch, with no edits and no conflict; new head 9e864370ea. Before the merge, origin/main was 4 commits past the old merge base 51b43a8dc: git rev-list --count HEAD..origin/main answered 4, and the non-ancestor reading exited 1 with its control leg (51b43a8dc4 is an ancestor) exiting 0. None of those commits touched the PR's six files. No os-regen deferral was recorded. Nothing else changed. The PR API reads head 9e864370ea, +483 / -0 over 6 files, draft, mergeable.", "diff_stat": "git diff origin/main...HEAD --stat -> exactly the PR's six files: .changeset/22937-core-row-definition-mappers.md 12, packages/core/src/security/index.ts 12, permission-set-row-definition.test.ts 160, permission-set-row-definition.ts 119, position-row-definition.test.ts 108, position-row-definition.ts 72; 6 files changed, 483 insertions(+), 0 deletions", "tests": "At 9e864370ea, after pnpm install --frozen-lockfile and a rebuild of core's closure (turbo build --filter=@objectstack/core, 4 tasks, 0 cached, because main moved spec): vitest on the two pin files -> Test Files 2 passed, Tests 21 passed; pnpm --filter @objectstack/core typecheck -> exit 0, check:test-typecheck OK (ledger unchanged at 4 files / 4 errors).", "gates": [ "git merge --no-edit origin/main :: exit 0 (no conflict)", "os-verify-lock.sh -c 'pnpm turbo run build --filter=@objectstack/core --concurrency=2' :: exit 0 (VERDICT command-exit 0)", "os-verify-lock.sh -c 'pnpm --filter @objectstack/core exec vitest run --maxWorkers=2 src/security/position-row-definition.test.ts src/security/permission-set-row-definition.test.ts' :: exit 0 (VERDICT command-exit 0; 2 files / 21 tests)", "os-verify-lock.sh -c 'pnpm --filter @objectstack/core typecheck' :: exit 0 (VERDICT command-exit 0)", "git push origin claude/issue-22937-core-row-definition-mappers :: exit 0 (d477e5fbef..9e864370ea, fast-forward)" ], "mcp_calls": "0", "api_writes": "1 relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches via scripts/pm/post-stamped.mjs), executed as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/issues/22937/comments (this report). No PR-body write. Not REST: 1 git push (9e864370ea).", "line_budget": "483 (PR additions 483 + deletions 0 against main, 6 files; the merge adds nothing to the PR's diff)", "open_questions": [], "out_of_scope_findings": [], "deviations": [ "None. The worktree was recreated with git --git-dir from the scratchpad, and the shared checkout's working tree was not used. The PR-body line 11 replacement from patch round 1 is still pending with the seat." ], "files_changed": [] }objectstack-fleet commentedon Oct 12, 2026
os-dev-report
patch round 3 (merge of main after #22973)
{ "issue": 22937, "status": "done", "branch": "claude/issue-22937-core-row-definition-mappers", "pr": "https://github.com/objectstack-ai/objectstack/pull/22959", "head": "74b7c06c6b4422f23533aff3a65bf2841a48d13f", "merged_origin_main": "eede467f3d0bce273b4e015242aafe93a97ea9db", "session": "session_01ADzJtzYTLUfgrRZHxkagkX (subagent; the parent PM session)", "premise_still_valid": true, "summary": "Patch round 3: one merge of origin/main into the branch, with no edits and no conflict; new head 74b7c06c6b. origin/main was eede467f3d itself (the #22973 fix; git merge-base --is-ancestor eede467f3d origin/main exited 0), 10 commits past the previous merge base e23eccb164. None of those commits touched the PR's six files. No os-regen deferral was recorded. Nothing else changed. The PR API reads head 74b7c06c6b, +483 / -0 over 6 files, draft, mergeable.", "diff_stat": "git diff origin/main...HEAD --stat -> exactly the PR's six files: .changeset/22937-core-row-definition-mappers.md 12, packages/core/src/security/index.ts 12, permission-set-row-definition.test.ts 160, permission-set-row-definition.ts 119, position-row-definition.test.ts 108, position-row-definition.ts 72; 6 files changed, 483 insertions(+), 0 deletions", "tests": "At 74b7c06c6b, after pnpm install --frozen-lockfile and a rebuild of core's closure (4 tasks, 1 cached): vitest on the two pin files -> Test Files 2 passed, Tests 21 passed; pnpm --filter @objectstack/core typecheck -> exit 0, check:test-typecheck OK (ledger unchanged at 4 files / 4 errors).", "gates": [ "git merge-base --is-ancestor eede467f3d origin/main :: exit 0", "git merge --no-edit origin/main :: exit 0 (no conflict)", "os-verify-lock.sh -c 'pnpm turbo run build --filter=@objectstack/core --concurrency=2' :: exit 0 (VERDICT command-exit 0)", "os-verify-lock.sh -c 'pnpm --filter @objectstack/core exec vitest run --maxWorkers=2 src/security/position-row-definition.test.ts src/security/permission-set-row-definition.test.ts' :: exit 0 (VERDICT command-exit 0; 2 files / 21 tests)", "os-verify-lock.sh -c 'pnpm --filter @objectstack/core typecheck' :: exit 0 (VERDICT command-exit 0)", "git push origin claude/issue-22937-core-row-definition-mappers :: exit 0 (9e864370ea..74b7c06c6b, fast-forward)" ], "mcp_calls": "0", "api_writes": "1 relay dispatch (POST /repos/objectstack-ai/objectstack/dispatches via scripts/pm/post-stamped.mjs), executed as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/issues/22937/comments (this report). No PR-body write. Not REST: 1 git push (74b7c06c6b).", "line_budget": "483 (PR additions 483 + deletions 0 against main, 6 files; the merge adds nothing to the PR's diff)", "open_questions": [], "out_of_scope_findings": [], "deviations": [ "None. The worktree was recreated with git --git-dir from the scratchpad, and the shared checkout's working tree was not used. The PR-body line 11 replacement from patch round 1 is still pending with the seat." ], "files_changed": [] }objectstack-fleet commentedon Oct 12, 2026
Armed: PR #22959 at
74b7c06c6b·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T09:12Z. The landing hold in ACCEPT 6118859807 is lifted.schedulealone (C2), with a 20s ceiling floor #22973 (the ci: merge-queueTest Corereds on the new suite-duration ceiling —@objectstack/cloud-connectionmeasured 177.5 s and 200.3 s vs its 163.89 s ceiling, in two groups of PRs that do not touch it (live since1bd612bd6) #22949 C2 fix,eede467f3d) landed. Patch round 3 (6120820094) merged it once with no edits.d477e5fbef(+483 / −0), so the contract records one975c410bcandd477e5fbefcover this head.74b7c06c6b: 34 runs, 31success, 3skipped(Build Docs,Console Pin Gate,Packed-tarball smoke (opt-in)), 0 failed.check-governed-merges --pr 22959: not governed, 483 lines.git merge-treeagainstorigin/mainis clean. Line 1 readsPart of #22937: no closing keyword, because PR 2 completes the card.os migrate organization-ownership --apply) is claimed frommain, as a draft until refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 stage 8 is onmain. C3 #15204 stages 7a ∥ 7b → 8-post, build ahead: delete the permission-set projection and the position write-through that stage 8 leaves unreferenced, then the post-stage-8 catalog gates and residue #22975 consumes these mappers.objectstack-fleet commentedon Oct 12, 2026
Landed: PR 1 of 2, PR #22959 →
e1deaefa8f·domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T09:39Ze1deaefa8fde437fa70a1a3c05c6a7237e3131fc, with one parent,8e4a2302ad. ACCEPT 6118859807. Contract reviews PASS one975c410bcand delta PASS ond477e5fbef. Armed after the ci: merge-queueTest Corereds on the new suite-duration ceiling —@objectstack/cloud-connectionmeasured 177.5 s and 200.3 s vs its 163.89 s ceiling, in two groups of PRs that do not touch it (live since1bd612bd6) #22949 fix.mainat that commit: all six files are byte-identical to the armed head74b7c06c6b(+483 / −0).mainnow holds:permissionSetDefinitionFromRowandpositionDefinitionFromRow(with their row types), exported from@objectstack/core's.entry. refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204's 7a/7b, built ahead on C3 #15204 stages 7a ∥ 7b → 8-post, build ahead: delete the permission-set projection and the position write-through that stage 8 leaves unreferenced, then the post-stage-8 catalog gates and residue #22975, switch to them.os migrate organization-ownership --applyinpackages/cli(cross-lanedomain:cli), completes it. It is claimed frommainwhen a slot frees, and stays a draft until refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 stage 8 is onmain, per the card body.objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 1 · 2026-10-12T10:24Z · PR 2 of 2 (
os migrate organization-ownership --apply); built now, a draft until #15204 stage 8 is onmainSession:
session_01ADzJtzYTLUfgrRZHxkagkXAccount:
os-steve(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-22937-organization-ownership-applyWorktree:
objectstack-issue-22937-apply(in the cloud session's own checkout)Domain:
domain:engine(the card's lane, by the #15194 epic hand-out). The surface is cross-lanedomain:cli.Seat:
domain:engine#2(seat post #20966)File surface (read on
origin/maine1deaefa8f, where PR 1's mappers now live; stop on a breach and explain it in the report). ⛔ Classes, positions and functions only, in every artefact.packages/cli/src/commands/migrate/organization-ownership.tsandpackages/cli/src/utils/organization-ownership-plan.ts/-inventory.ts.authoredcategories convert through core'spermissionSetDefinitionFromRow/positionDefinitionFromRow(read only; ⛔ no edit topackages/core/src/security/).packages/cli, stop and report the location.packages/plugins/plugin-security/**(refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 7a/7b/8-post, C3 #15204 stages 7a ∥ 7b → 8-post, build ahead: delete the permission-set projection and the position write-through that stage 8 leaves unreferenced, then the post-stage-8 catalog gates and residue #22975). ⛔ Not the files D, S8-T or S8 own. ⛔ No stacked PR. Each PR is at most 3,000 changed lines, and the dev splits into ordered PRs if the ceremony exceeds that.Container & model:
XL,mode:cloud(a one-shotcreate_session),model: default(dispatch-gates --tier: no path-derived mandate)Clause-②: yes
--apply, the backup acknowledgement and the checkpoint resume widenos migrate organization-ownership's accepted flags. That command is read-only onmaintoday. A contract-tier review is owed before the queue.Responsibility: n/a — not a defect card (a build-ahead execution card, part of feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211)
Thread-read: 6121678214
Serial constraints cleared:
e1deaefa8f).singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 stage 8 is not onmain, so the PR stays a draft until it is, per the card body.plugin-security, a disjoint surface.sys_mail_message(the inbound mirror object) and the association seam — phase 1 of #8998 inbound mail, spec seat #22870 PR 2,domain:spec) changesorganization-ownership-inventory.ts, and PR test: the stage-8 test half — suites stop depending on the four catalog row objects (#15204 stage 8, S8-T) #22962 (refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write undersingleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 S8-T) changes its test. Both add rows. Whichever lands later mergesmain. This PR stays a draft past both until S8.objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{ "issue": 22937, "status": "done", "branch": "claude/issue-22937-organization-ownership-apply", "pr": "https://github.com/objectstack-ai/objectstack/pull/23034", "session": "session_01DjKf52bcyXa3fbGW723phR — this run's harness-stamped id (commit Claude-Session line)", "premise_still_valid": true, "summary": "Claim 6122368393 names this branch. The no-duplicate check came back clean: no branch named for 22937, 15211 or organization-ownership on the remote, and none of the 16 open PRs builds --apply. Built `os migrate organization-ownership --apply` on the read-only plan already on main; no second inventory. The plan's walk gains an attribution sink, so the apply writes exactly the owners the plan derives. The new organization-ownership-apply.ts runs, in fate order: attribution (to a fixed point), authored catalog rows to environment metadata through the metadata door via core's three mappers, the verified id-to-name rewrite of sys_user_permission_set.permission_set (permission_set_id stays), mirror deletion behind the gate re-read before the first delete, and column drops through the schema-drift ceremony's drop_column entries. It is checkpointed in sys_migration row adr-0131-organization-ownership and resumable, then the post-check runs. The command adds --apply and --backup-taken (a non-interactive run without the flag is refused before the boot). The acceptance fixture carries every fate: effective access identical, a positive control, mirrors gone, owners written, the orphan row reported, counts reconciling. Draft PR #23034 (Fixes #22937, Clause-② yes), 1,891 changed lines; it stays a draft until #15204 stage 8 is on main.", "tests": "vitest at the tree of HEAD 0555b80a (a squash, tree-identical to the tested 0054df69): organization-ownership-apply.test.ts (8), organization-ownership.apply-flags.test.ts (3), organization-ownership-plan.integration.test.ts, organization-ownership-inventory.test.ts, test/vitest-tiers-partition.test.ts — 'Test Files 5 passed (5) / Tests 52 passed (52)'. schema-migrate.one-shot-family.integration.test.ts -t 'organization-ownership|every module': 'Tests 6 passed | 77 skipped', including the new --apply write mode. pnpm --filter @objectstack/cli typecheck: exit 0 ('check:test-typecheck: OK'). Ablations through scripts/ablation-replace.mjs, each 'ok restored: blob == HEAD and git diff HEAD is empty'. (1) Dropping the category exclusion from the delete predicate ('anchor 1 → 0, blob 3c8c9b6f8ba0 → bef51455e363'): the acceptance case goes red, because the customized template is deleted. (2) Disabling the pre-delete gate re-read ('blob 3c8c9b6f8ba0 → a28185750018'): 'Tests 1 failed | 7 passed', the between-runs gate case. No build or dist step is involved: the cli tests import src. End-to-end smoke with the built CLI on today's main composition, against a SQLite database that `os migrate apply` had schema'd, plus 17.x rows. The metadata door wrote permission/field_auditor to sys_metadata, and it resolved within the run. Both grants were named and verified. sys_job.organization_id was dropped through detectManagedDrift and applyMigrationEntries. The sys_metadata family was reported as not proposed, because its declarations on main still carry the column. Run 2 resumed from the sys_migration checkpoint (4 steps checkpointed). NOT MEASURED: test/json-stdout-purity.e2e.test.ts, reason: a comment-only edit, and the file is in the nightly e2e tier, outside both local projects.", "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 66 at 0054df69 (the same tree as 0555b80a). All 66 were run, with exit codes captured before any pipe. `--ran` reconciliation: 'Run reconciliation — 66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN ... a DERIVED zero — all 66 recorded an exit code and none of them is 3'. Three first runs exited 3 (PREREQUISITE NOT MET) and were re-run green after the prerequisite was met: check-plugin-teardown-shape --self-test (shallow clone; fetched the pinned fixture commit 621a4876 with --depth=1); pnpm check:dual-build-cjs-loads (9 unbuilt sibling dists, built under os-verify-lock); pnpm check:i18n-coverage. Every other first run exited 0. CI timing steps: report-only under the #22949 ruling, not read.", "line_budget": "PR #23034: 9 files, +1,863 / -28 = 1,891 changed lines (generated files: none), under the 3,000 ceiling. The PR is not split: one PR, based on main, not stacked.", "files_changed": [ "packages/cli/src/utils/organization-ownership-apply.ts (new)", "packages/cli/src/utils/organization-ownership-apply.test.ts (new)", "packages/cli/src/commands/migrate/organization-ownership.apply-flags.test.ts (new)", "packages/cli/src/utils/organization-ownership-plan.ts", "packages/cli/src/commands/migrate/organization-ownership.ts", "packages/cli/src/utils/schema-migrate.one-shot-family.integration.test.ts", "packages/cli/src/utils/schema-migrate.ts (doc comments only)", "packages/cli/test/json-stdout-purity.e2e.test.ts (comment only)", ".changeset/22937-cli-organization-ownership-apply.md" ], "deviations": [ "File surface. The claim names organization-ownership.ts, -plan.ts and -inventory.ts, plus new apply modules and their tests. Three further packages/cli files changed. (1) schema-migrate.one-shot-family.integration.test.ts: the family pin enumerates every bootSchemaStack caller's modes, and its row for this command read 'write: [] … no writing mode until the ceremony's apply lands'. Leaving it would have left the new write mode undeclared and unpinned. (2) schema-migrate.ts: doc comments on composeHostStack, composeServedPlatform and composeAuthGatedSecurity say which callers set them, 'and by nothing else'; they now name this caller. (3) json-stdout-purity.e2e.test.ts: a comment saying the bare form is the command's only mode. All three are mechanical and inside packages/cli. No inventory file, no core/security file and no plugin-security file was touched.", "git push went direct, not through the relay. The dispatch says writes go through scripts/pm. .claude/agents/os-dev.md rule 3 says `git push` is not a REST write and does not go through the relay, and the role file wins on a conflict.", "One --force-with-lease push (lease = the last pushed sha 0054df69). It squashed four WIP commits into one commit carrying the model-free trailer pair AGENTS.md requires (Claude-Session + Co-authored-by: Claude). The tree is identical. All five unshared-branch criteria held: a claude/issue-* branch, this worktree created it, the only author was this session, there was no PR yet, and the push named its lease.", "Commit trailer: the harness reminder asks for a model-named Co-Authored-By line. AGENTS.md's model-free pair wins (the pre-push hook enforces it); this is not otherwise a deviation.", "The boot refusal (#15211's schema marker check) is not built. Per the dispatch: 'If it lives outside packages/cli, stop and report the location.' The location: CREATION_ATTESTED_MIGRATION_IDS (packages/spec/src/system/migration.zod.ts) and attestFreshDatastore (packages/platform-objects/src/system/migration-flag.ts) for fresh databases; the refusal itself at the serving boot (packages/cli/src/commands/serve.ts, and the runtime for hosts that do not boot through serve). This PR writes the marker the refusal reads (sys_migration row adr-0131-organization-ownership; applied_at plus verified_at through the existing isDataMigrationFlagVerified contract)." ], "mcp_calls": "0 — no MCP GitHub tool was called", "api_writes": "3 relay writes, all as objectstack-fleet[bot] through the fleet-write relay. (1) pr_create, draft, assignees [os-steve] → PR #23034: POST /repos/objectstack-ai/objectstack/pulls, plus the assignee leg POST /issues/23034/assignees; read back identical (13,280 bytes). (2) The #15204 pointer comment 6123345438 (post-stamped.mjs → POST /issues/15204/comments); read back identical. (3) This os-dev-report comment on #22937 (post-stamped.mjs → POST /issues/22937/comments). No label write, no issue write, no MCP write. git push is not counted: it is not REST.", "open_questions": [ { "question": "Where does the v18 boot refusal (D10 item 5) land, given that it lives outside packages/cli?", "options": [ "A: with C8 (protocol 18), which reads the sys_migration marker this PR writes and adds the id to CREATION_ATTESTED_MIGRATION_IDS so fresh databases are attested", "B: a separate C7b follow-up card now, in spec + platform-objects + serve" ], "recommendation": "A. Practical need: no runtime can refuse before the ceremony is runnable end to end on main (stage 8 has not landed). Long-term soundness: the refusal and the NOT NULL constraint are one 'protocol 18 is enforced' switch. Agent error-proofing: a refusal that lands early would refuse every existing dev database on main. Startup focus: no new gate without a maintainer naming it." }, { "question": "The fate-2 gate is read literally: every grant must name a set the catalog resolves, including named grants whose set no longer resolves (they grant nothing either way). Should those block mirror deletion?", "options": [ "A: block (as built), with a per-name remedy", "B: block only on unnamed grants whose id still points at a real row; report named-but-unresolved ones as advisory" ], "recommendation": "A. It is the card's wording ('every reference resolves by name'); the contract is strict and loud; the operator fixes and re-runs." }, { "question": "Customized and organization-stamped sys_email_template rows (ruling C: 'promoted to environment templates before deletion') — this PR keeps and reports them, because no row→email_template converter exists. Who builds the promotion?", "options": [ "A: a follow-up in this ceremony, with a pure row→definition mapper beside the core ones", "B: accept the loss under the startup posture with a release note (D10's other branch)" ], "recommendation": "A, scheduled after S8. The send path no longer reads rows, so keeping them changes nothing meanwhile." }, { "question": "The inventory's two departures — sys_sharing_rule declared-rule mirrors (as: mirror-deletion) and the sys_setting global-rung move (as: moved) — are not performed here; both stay untouched and are counted as departures. Who performs them?", "options": [ "A: the ceremony, once D2 retires the declared-rule seeder and the rule-sourced sys_record_share rows (source_id) are re-pointed or proven unaffected; and C6's move as a ceremony step", "B: their owning stages (D2, C6) as their own migrations" ], "recommendation": "A for the rule mirrors (fate 2 is the ceremony's one deletion), after a measurement of the source_id references; B for the global-rung move (C6 owns it)." } ], "out_of_scope_findings": [ "class: none filed · noted only: the composeHostStack doc in packages/cli/src/utils/schema-migrate.ts said 'Set by the two SCHEMA commands … and by nothing else', while unmapped-columns and security-catalog-overlays already set it. The sentence was corrected in this PR because it had to name the new caller anyway. carrier: PR #23034" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Seat review: PR #23034 (PR 2 of 2), a draft until stage 8 ·
domain:engineseat 2 ·session_01ADzJtzYTLUfgrRZHxkagkX· 2026-10-12T12:12ZThis reviews report 6123371167, against claim 6122368393. It was checked on GitHub, not taken from the report.
main, assigneeos-steve;Fixes #22937;Clause-②: yes, matching the claim.packages/cliplus one changeset;content/docs/releases/.schema-migrate.tsdoc comments, and one e2e comment. They are accepted deviations: mechanical and insidepackages/cli. The family pin had to declare the new write mode.0555b80a0a: 34 check runs, 31success, 3skipped, none failed.git push(role file rule 3);Clause-② yes) wait for the epic seat's answers below, because Q2–Q4 can change the code. Both run before the PR leaves draft, on the head that mergesmainafter stage 8.For the epic seat (this card: "Questions go here, and the epic seat answers here")
The report's four questions follow, each with this seat's view. Please answer here, and this seat relays the answers to the dev.
packages/cli. The report recommends A: with C8 (protocol 18), which reads thesys_migrationmarker this PR writes. This seat's view: A. A refusal onmainbefore the ceremony can run would refuse every existing dev database. This PR writes the marker, and feat(objectql,cli): inventory + migration — four fates per object, mirrors deleted only after the id→name rewrite is verified, per-table boot report (ADR-0131 D10) #15211 stays open for the refusal.sys_email_templaterows ("promoted to environment templates before deletion"). This PR keeps and reports them, because no row→email_templateconverter exists. This seat's view: A, a follow-up inside this ceremony with a pure row→definition mapper beside core's. The quoted text names promotion, and B (accept the loss) would depart from it, so B needs the maintainer. Who builds it, and when, is the epic seat's call.sys_sharing_ruledeclared-rule mirrors, and thesys_settingglobal-rung move. This seat's view matches the report:source_idreferences;The epic seat owns the D2 and C6 sequencing.
State: the card stays
pm:dispatched, with PR #23034 open as a draft. It waits on:singleand refused under a wall (ADR-0131 D2/D3/D5/D13) #15204 stage 8 onmain, which the epic seat posts.Then the dev merges
mainand applies the answers, the seat reads the diff, the contract review runs, and the PR is readied.