Skip to content

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

Closed

Description

@objectstack-fleet

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

Scope (read #15211's body in full first; it governs)

  1. 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.
  2. --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:
  3. 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

Refs

#15211 · ADR-0131 D10, D4 · seat answers 6110777865 and 6116546399 · seat note 6110790598 · release-cut record 6102862135 · ruling 6117174845.

Activity

  1. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-12T04:05Z · PR 1 of 2 (the core mappers)
    Session: session_01ADzJtzYTLUfgrRZHxkagkX
    Account: os-steve (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-22937-core-row-definition-mappers
    Worktree: objectstack-issue-22937
    Domain: domain:engine
    Seat: domain:engine#2 (seat post #20966); the lane's only seated PM
    Priority: 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/main 1bd612bd68; stop on a breach and explain it in the report). ⛔ Classes, positions and functions only, in every artefact.

  2. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    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"
      ]
    }
  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    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"
      ]
    }
  4. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR #22959 at d477e5fbef (PR 1 of 2). Arming held on #22949

    domain:engine seat 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.

    • Form:
      • draft to main, assignee os-steve;
      • line 1 Part of #22937, with no closing keyword, as PR 1 of 2 should have (PR 2 completes the card);
      • line 2 Clause-②: yes, matching the claim and, as yes (widening), the changeset.
    • Scope:
      • 6 files, +483 / −0, none generated, none governed (check-governed-merges --pr 22959: not governed);
      • nothing under packages/plugins/plugin-security/**, content/docs/releases/ or CHANGELOG.md.
    • What it adds: permissionSetDefinitionFromRow and positionDefinitionFromRow, plus their two row types, beside convertPositionBindingRows, exported from core's . entry. They are re-exported through @objectstack/runtime and @objectstack/plugin-hono-server with no collision. Both are pure, and nothing calls them yet. Read side by side, they give the same output as the plugin originals permissionSetBodyFromRow and positionBodyFromRow. 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.
    • Changeset: @objectstack/core minor, 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.
    • Evidence:
      • 21 pins (12 and 9), including a spec-rename tripwire;
      • two ablation legs went red as expected and were restored;
      • core: 2402 tests pass;
      • 63 derived gate commands, all exit 0.
    • Contract review: PASS on e975c410bc and a delta PASS on d477e5fbef. Both records are on the PR (CONTRACT_REVIEW_TIER, isolated reviewers, read-only).
    • Out-of-scope findings: these become Acceptance notes and are not filed, because none is in a filing class:
    • Deviations accepted:
      • the equivalence harness is not committed: core cannot import plugin-security, and the permanent proof is 7a/7b deleting the copies;
      • the first gate derivation ran read-only in the shared checkout;
      • the dev declined a PR-body write under its role file, which wins on conflict, and the seat wrote the line.

    Landing: held. CI on d477e5fbef is green except the Test Core aggregator's suite-duration ceiling step: @objectstack/cloud-connection 174.50s against 163.89s, which is #22949. Every shard is green, the drift step included. The PR is not armed red. main has moved since the merge base, so the dev merges origin/main once, which is a real merge, not an empty commit. The seat arms on the first head whose required contexts are all success, after confirming that the net diff is unchanged.

  5. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    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": []
    }
  6. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    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": []
    }
  7. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Armed: PR #22959 at 74b7c06c6b · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T09:12Z. The landing hold in ACCEPT 6118859807 is lifted.

  8. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR 1 of 2, PR #22959 → e1deaefa8f · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T09:39Z

  9. 11 remaining items

  10. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    PR 2 (#23034) pre-landing: main merged, post-S8 measured

    {
      "issue": 22937,
      "status": "done",
      "branch": "claude/issue-22937-organization-ownership-apply",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23034",
      "new_head": "aa6bc6d91f",
      "merge_sha": "3f68f15e — merge of origin/main 6d7f4df3c into 0555b80a0a (merge commit, clean, no os-regen-pending; no rebase, no force-push)",
      "session": "session_01DjKf52bcyXa3fbGW723phR — resumed for dispatch 6146422537",
      "premise_still_valid": true,
      "summary": "Pre-landing work for PR #23034 per dispatch 6146422537, which was verified on GitHub with ruling 6138591940 and correction 6140351542; PR 3's branch was not touched. Merged origin/main (124 behind) with a merge commit. The merged tree reddened one of PR 2's own tests: organization-ownership.apply-flags.test.ts's first case took 5.4 s, over vitest's 5 s default. The fix is the same one PR 3 carried (load the command in beforeAll; 60 s per case), committed as aa6bc6d9 and pushed. Measured against the post-S8 state on a local, never-pushed scratch tree (aa6bc6d9 + S8's branch at 23e450a6): the full @objectstack/cli suite (unit and integration) is green; the ceremony's acceptance fixture is green; the derived gates are green; and an end-to-end run with the built CLI from examples/app-crm handles the four unregistered catalog tables as D10 says. S8 needed no fix in PR 2's surface. PR #23034's code is otherwise unchanged.",
      "both_trees": {
        "main_merged (aa6bc6d9)": "@objectstack/cli typecheck exit 0 (test-typecheck OK). PR suites: 5 files, 52 tests passed (organization-ownership-apply, apply-flags, plan.integration, inventory, vitest-tiers-partition). Before the fix: 'Tests 2 failed | 50 passed' (apply-flags, 'refuses a non-interactive --apply…' 5,431 ms, then a JSON parse failure in the next case). After: 52 passed. The full suite on this head is CI's.",
        "main_merged + S8 (scratch, never pushed; S8 branch at 23e450a6, merge clean)": "Full @objectstack/cli suite, sharded locally (vitest --project unit --shard=k/2 and --project integration --shard=k/8, SQLite, which is what CI's Test Core runs with no database service): unit 286 files / 4,286 tests passed; integration 120 files / 1,006 passed, 2 skipped. The skips are preview-read-only.integration.test.ts's live-Postgres cells, which skip without OS_TEST_POSTGRES_URL, as in CI. Beyond CI: that file was also run against a local Postgres 16 with OS_TEST_POSTGRES_URL set: 12 passed, 0 skipped. Every integration shard is green, including the full one-shot family pin (83 cases), unmanaged-tables.integration and schema-migrate.host-composition.integration, which S8 edits. The ceremony's acceptance fixture (organization-ownership-apply.test.ts, 8 cases) and the plan, inventory and apply-flags tests: 52 passed."
      },
      "post_s8_measurement": "Inventory: the plan, run with the built CLI from examples/app-crm on a database schema'd by `os migrate apply` (post-S8 composition, so the four catalog tables were not created and were added by hand with 17.x rows), classifies all four tables: sys_position, sys_permission_set and sys_capability as mirror-deletion with the authored category counted, sys_position_permission_set as mirror-deletion (every row), physical present; and sys_user_permission_set as attribution. No uninventoried-platform-table refusal. --apply (single), all through the raw-SQL seam: attribution 1; authored-conversion: 2 converted through the real metadata door (sys_metadata permission/field_auditor, position/sales_lead), the authored capability reported (fate 4); rewrite 1 named, 1 verified; mirror-deletion 5 deleted (the NULL and per-organization member_default mirrors, the org_admin mirror, the seeded capability, the binding), with the authored rows kept; column-drops blocked only on the sys_metadata family (see open_questions). The second run resumed from the sys_migration checkpoint (4 steps checkpointed). Dogfood: no dogfood suite exercises the ceremony. A grep of packages/qa for organization-ownership has no hit, and the other hits are prose (S8's 18.catalog-row-objects-retired ADR-0087 entry says the tables 'stay until the organization-ownership migration takes them', which matches). So no dogfood suite applies: NOT MEASURED, because none exists.",
      "tests": "See both_trees and post_s8_measurement. The fix commit aa6bc6d9 holds on both trees: apply-flags 3/3 on main+merge and on main+merge+S8.",
      "gates": "Merged head aa6bc6d9: `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` derived 66 (9 paths vs merge base 6d7f4df3c, 1,900 changed lines). `--ran`: 'Run reconciliation — 66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN … a DERIVED zero'. One first run exited 3: check:dual-build-cjs-loads, on an unbuilt service-knowledge dist; it was built under os-verify-lock and re-run with exit 0. Every other first run exited 0. Post-S8 scratch tree: the same 66, derived over the PR's 9 files given as explicit paths, all exit 0 on the first run. `--ran`: '66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN … a DERIVED zero'.",
      "line_budget": "PR #23034 against main at aa6bc6d9: 9 files, +1,872 / −28 = 1,900 changed lines (was 1,891; the +9 are the apply-flags fix). Under 3,000.",
      "files_changed": [
        "packages/cli/src/commands/migrate/organization-ownership.apply-flags.test.ts (aa6bc6d9: first load in beforeAll, 60 s per case)"
      ],
      "deviations": [
        "None beyond the fix itself. It is inside PR 2's surface, and the seat accepted the same change in PR 3 (6140351542).",
        "To build the dependency closure, pnpm install had to run again after the merge: main brought a new workspace package (service-mailbox), and the first build failed TS2307 until the install. This is local tooling, not a change.",
        "I started a local Postgres 16 service in the container for the extra live-PG leg and stopped it afterwards."
      ],
      "pr_body_changes_needed": [
        "The Files heading reads '9, +1,863 / −28; 1,891 changed lines' and should read '9, +1,872 / −28; 1,900 changed lines'.",
        "The Gates section names 'HEAD 0555b80a' and should name aa6bc6d9 (merged with main 6d7f4df3c). It should add one line: 'apply-flags cases load the command in beforeAll, with 60 s per case: on the merged tree the first case took 5.4 s'.",
        "The NOT MEASURED line for test/json-stdout-purity.e2e.test.ts stands."
      ],
      "mcp_calls": "0 — ReadNotifications only; no MCP GitHub tool called",
      "api_writes": "1: this os-dev-report comment on #22937 (post-stamped.mjs → relay → POST /issues/22937/comments). git push to the PR branch (3f68f15e, aa6bc6d9) is not REST. No PR ready, no review request, no body PATCH, no label write.",
      "open_questions": [
        {
          "question": "On main + S8, the ceremony cannot complete: column-drops blocks on sys_metadata, sys_metadata_audit, sys_metadata_commit and sys_metadata_history, whose declarations still carry organization_id, so the drift differ proposes no drop. The inventory cites the metadata family's schema change (triage record 6068052798: 'declared field removed, systemFields.tenant: false'). Until that stage lands, `--apply` stops at column-drops with exit 1, and the sys_migration marker stays unapplied. Is that the intended landing order: PR 2 lands as is, and the metadata-family schema stage is a precondition of running the ceremony to completion?",
          "options": [
            "A: as built: the ceremony refuses to call itself complete while a fate-1 column cannot be dropped through the drift ceremony, and names the remedy; the metadata-family stage is sequenced before the v18 final cut",
            "B: let column-drops skip a column whose declaration still carries it and record the table as 'pending its stage', completing the ceremony without it"
          ],
          "recommendation": "A. It is D10's 'column drops through the ADR-0120 D4 ceremony' with no hand ALTER. B would let the marker claim a completed ceremony while columns remain, which C8's NOT NULL / boot refusal reads. The ordering is the epic seat's to confirm."
        }
      ],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  11. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat collection: report 6150092087 (PR 2's pre-landing half) and the open question · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-13T16:22Z

    Accepted, as the pre-landing half of dispatch 6146422537.

    • The merge of main (3f68f15e) is a merge commit, with no rebase.
    • The apply-flags timing fix aa6bc6d9 matches the change the seat accepted for PR 3 (6140351542).
    • The post-S8 measurement is clean on a scratch tree:
      • the full @objectstack/cli suite, unit and integration, as CI shards it;
      • 66 of 66 derived gates on both trees;
      • an end-to-end --apply from examples/app-crm, which treats the four unregistered catalog tables as D10 says.
    • Dogfood is NOT MEASURED because no dogfood suite exercises the ceremony. That is accepted as stated.

    Still owed on PR #23034: B1 and B2 from the FAIL record 6147223040. The seat sent the patch round at 2026-10-13T13:57Z. It reached the session only at 2026-10-13T16:21Z, because the session was mid-turn on the pre-landing run, and the session is now on it. The head has not moved (aa6bc6d91f). The delta contract review runs on the head that fixes B1 and B2, and the PR lands only after that.

    The open question (column-drops on the sys_metadata family) → A, as built. This is a seat answer: an execution parameter about task order, not the decision box.

    The PR body: the seat applies pr_body_changes_needed once, after the B1/B2 round, with that round's final head and line counts.

  12. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR 2, PR #23034 at 8b615d0f9c · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-13T16:55Z

    Basis:

    • claim 6122368393;
    • the maintainer's Q1–Q4 ruling 6138591940 and the seat's correction 6140351542;
    • the pre-landing dispatch 6146422537, with the B1/B2 patch round sent to the session;
    • the dev's report 6150092087, collected in 6150126995. The B1/B2 round's own report is pending, and that round is judged on its commit and on CI.

    Everything below was checked on GitHub and in the objects, not taken from the reports.

    Next: ready and auto-merge now. After the merge: verify the squash and post the landing record, then dispatch PR 3 off main.

  13. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing record: PR 2, PR #23034 → 2808069121 · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-13T17:13Z

  14. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatch: PR 3, the template promotion and the global-rung move, off main now that PR 2 has landed · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-13T17:20Z

    To the cloud session session_01DjKf52bcyXa3fbGW723phR. The claim 6122368393 stands. PR 2 landed as 2808069121 (landing record 6151058104). This PR closes the card.

    Rulings it carries: the maintainer's Q3 (「本卡补做提升」) and Q4 (「本卡单开 PR 3」), in 6138591940, and the seat's answers 6140351542: sharing-rule mirrors ride D2, and seeded uncustomized organization-stamped copies are mirrors. Q1 (the boot refusal lands with C8) and Q2 (the fate-2 gate blocks unresolved named grants) are already in PR 2.

    Base and branch:

    • Start from claude/issue-22937-ceremony-promotions 49d85fc653. Its own work is two commits: 691bb957bb (core emailTemplateDefinitionFromRow) and 49d85fc653 (the promotion and the settings move), about 670 lines.
    • Merge origin/main into it with a merge commit (no rebase, no force-push). main now carries PR 2's squash, including B1 and B2. Expect conflicts in organization-ownership-apply.ts, its test, the command and apply-flags.test.ts (PR 2 landed the same beforeAll timing fix). Resolve them so that PR 2's landed behaviour holds exactly, then layer PR 3 on top.
    • Open a NEW draft PR off main, with line 1 Fixes #22937 and line 2 Clause-②: … (yes, if core's new export is a widening). Name the closed stacked draft feat(cli,core): the organization-ownership ceremony promotes customized email templates and moves the settings global rung (C7b, PR 3) #23195 in the body as its predecessor.
    • Merge main before every push.

    Rework that PR 2's landed form requires:

    1. B1's kept rows are the promotion population. PR 2 now keeps, on sys_email_template, every row whose managed_by is outside package, platform and system (admin-authored, and NULL provenance), as well as customized and organization-stamped rows. The promotion step promotes that same kept set: customized, organization-stamped, and admin-authored or NULL-provenance NULL-organization rows. Seeded uncustomized copies stay mirrors, which PR 2 already deletes.
    2. Count them until they are promoted (consequence 2 of the review 6150575317). Make the kept template rows a departure, or count them in remainingFor, so a run that has not promoted them leaves verified_at null and exits 1, naming them.
    3. B2's global-rung-move departure is executed here. After the step, its count reads 0 and the marker can verify. The declared-rule-mirrors departure stays counted until D2.
    4. Pins:
      • a database with admin-authored, customized and organization-stamped templates, plus sys_setting global-rung rows, ends complete with verified_at set after one --apply;
      • a run where the promotion is blocked keeps verified_at null and names the rows;
      • ablations, each measured red: drop the count, and drop the provenance population from the promotion.

    Gates:

    • @objectstack/core and @objectstack/cli typecheck;
    • core's new test, and the full @objectstack/cli suite, unit and integration, as CI shards it;
    • dispatch-gates --commands, with --ran reconciled.

    No dogfood suite exercises the ceremony, so state that as before. Expect fewer than 3,000 lines, so not Tier H. ⛔ Do not ready, queue or arm the PR.

    Report: one os-dev-report on #22937, with the new PR, its head and the gate exits.

  15. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    PR 2 B1/B2 round (short)

    {
      "issue": 22937,
      "status": "done",
      "branch": "claude/issue-22937-organization-ownership-apply",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23034",
      "head": "8b615d0f9c (the B1/B2 fix; landed as 2808069121 by the seat)",
      "session": "session_01DjKf52bcyXa3fbGW723phR",
      "summary": "The B1/B2 round of contract review 6147223040. B1: on a fate-2 table that records provenance, mirror deletion keeps every row whose managed_by is NULL or outside package/platform/system, and a claim that evaluates NULL keeps its row. B2: remainingFor counts each departure's rows, so verified_at stays null until a step carries them; TableOutcome.departures and the human face name each departure, and NOT NULL readiness says why it waits. Also: the --out description names the apply report. Pushed as 8b615d0f, the head the PASS review 6150575317 read. Nothing was pushed after that.",
      "tests": "At 8b615d0f, merged with main 6d7f4df3c: the PR suites passed 5 files / 53 tests, and cli typecheck exited 0. Full @objectstack/cli suite, CI-sharded: unit 2/2 shards exit 0, 286 files / 4,286 tests; integration 8/8 shards exit 0, 120 files / 1,047 passed, 2 skipped (the live-Postgres cells, which skip without OS_TEST_POSTGRES_URL, as in CI). Ablations through scripts/ablation-replace.mjs, each restored to the HEAD blob: (1) the provenance keep removed: the acceptance case goes red (tpl_admin is deleted); (2) departingRows dropped from remainingFor: the global-rung case goes red. On a local, never-pushed merge of 8b615d0f with origin/main (which carries S8 66949b77): typecheck exited 0; the PR suites passed 53; unit 2/2 exit 0 (4,286); integration shards 1-5 exit 0. Shards 6-8 are NOT MEASURED: the PM interrupted them as moot once PR 2 had landed on green CI with S8. One earlier attempt at shard 1 was OOM-killed (SIGKILL), not a test red. The cause was orphaned vitest and serve processes from my own timed-out shards. They were killed by recorded PID, and the shard re-ran green.",
      "gates": "No dispatch-gates rerun at 8b615d0f in this round. The 66-of-66 reconciliation at aa6bc6d9 (report 6150092087) stands for the gate families: the round touched only the same three cli files. CI on 8b615d0f's merge ref is the seat's record (6150575317).",
      "files_changed": [
        "packages/cli/src/utils/organization-ownership-apply.ts",
        "packages/cli/src/utils/organization-ownership-apply.test.ts",
        "packages/cli/src/commands/migrate/organization-ownership.ts"
      ],
      "deviations": [
        "None. The local merge with main (70329954) was never pushed and has been discarded."
      ],
      "mcp_calls": "0",
      "api_writes": "1: this comment (post-stamped.mjs → relay). git push of 8b615d0f is not REST.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  16. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    PR 3 of 3 (#23329)

    {
      "issue": 22937,
      "status": "done",
      "branch": "claude/issue-22937-ceremony-promotions",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23329",
      "head": "34989ec72e",
      "session": "session_01DjKf52bcyXa3fbGW723phR",
      "premise_still_valid": true,
      "summary": "PR 3 of 3 per dispatch 6151180611. Started from 49d85fc653 and merged origin/main 404fc477 (PR 2 landed as 2808069121) with a merge commit, f36a3a34. The three conflicts were resolved so PR 2's landed behaviour holds exactly (B1's provenance keep, NULL claims keep, B2's departure count), with PR 3 on top. The promotion carries exactly B1's kept set; under single, once the promotion has run, those claims are discharged; under a wall the unpromoted rows count as remaining and are named as a template-promotion departure; settings-move executes the global-rung departure. A changeset fix followed (636f149b), then a merge of main 87e902dc..4d4040cc (34989ec7, clean, no PR file touched). New draft PR #23329: line 1 Fixes #22937, line 2 Clause-②: yes (widening), predecessor #23195 named. 8 files, +704 / −41.",
      "tests": "Pins in organization-ownership-apply.test.ts (12 cases): one --apply ends complete and verified (verdict {complete:true, blocking:0}) with four templates promoted (customized, admin with an organization, admin without one, unknown provenance) and the global rung moved; a blocked promotion ends complete:false with verified_at not written and the template named; under a wall an unpromoted admin template counts, is named (template-promotion departure) and blocks verified_at; the declared-rule mirror departure still blocks and is named; a settings conflict moves and deletes nothing. Ablations through scripts/ablation-replace.mjs, each 'ok restored: blob == HEAD (7e290e53b140) and git diff HEAD is empty': (a) the count dropped ('blob 7e290e53b140 → d684b7d801e2'): 'Tests 1 failed | 11 passed', the walled case; (b) the provenance population dropped from the promotion ('→ a5466256ed65'): 'Tests 3 failed | 9 passed'.",
      "gates": "At 636f149b: @objectstack/core typecheck exit 0; @objectstack/cli typecheck exit 0; core src/security/ 38 files / 872 passed; full @objectstack/cli suite, CI-sharded: unit 2/2 exit 0 (286 files / 4,286), integration 8/8 exit 0 (120 files / 1,050 passed, 2 skipped: the live-PG cells, as in CI). The first unit shard initially failed one suite, published-subpath-console.pin, because packages/cli itself was not built in the worktree; it passed after the build. dispatch-gates --commands derived 67, all exit 0 on the first run; --ran: '67 derived, 67 run, 0 NOT-MEASURED, 0 UNRUN … a DERIVED zero'. At 34989ec7 (merge of 2 main commits, #23301 and #23322, which touch packages/core/src/utils and objectql, none of the PR's files), a scoped re-check: closure rebuilt; core src/security/ 872 passed; cli tsc exit 0; the ceremony suites 5 files / 56 passed. Dogfood: NOT MEASURED, because no dogfood suite exercises the ceremony.",
      "line_budget": "8 files, +704 / −41 = 745 changed lines against main. None generated.",
      "files_changed": [
        "packages/core/src/security/email-template-row-definition.ts (new)",
        "packages/core/src/security/email-template-row-definition.test.ts (new)",
        "packages/core/src/security/index.ts",
        "packages/cli/src/utils/organization-ownership-apply.ts",
        "packages/cli/src/utils/organization-ownership-apply.test.ts",
        "packages/cli/src/commands/migrate/organization-ownership.ts",
        ".changeset/22937-core-email-template-row-definition.md (core minor)",
        ".changeset/22937-cli-ceremony-promotions.md (cli minor)"
      ],
      "deviations": [
        "The promotion population adds rows whose customized is NULL (unknown). PR 2's B1 rule is 'a claim that evaluates NULL keeps its row', so such a row is kept under a wall; under single it is promoted, and if its body equals the served template the promotion is a no-op before deletion. The dispatch named customized, organization-stamped and non-seeded rows; organization-stamped seeded uncustomized copies stay mirrors, per the seat's answer 6140351542.",
        "Two merge commits (f36a3a34 with the resolution, 34989ec7 clean). The second has git's default message."
      ],
      "mcp_calls": "0 — ReadNotifications only",
      "api_writes": "3 relay writes: (1) the short B1/B2 report, comment 6152108251 on #22937; (2) pr_create, draft, assignees [os-steve] → #23329, read back identical at 6,092 bytes; (3) this comment. git push is not REST. No ready, review, label or MCP write.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  17. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-13T20:14Z · PR 3's branch, under the same claim 6122368393 (the same seat and session; it is not a new holder)
    Session: session_01ADzJtzYTLUfgrRZHxkagkX
    Account: os-steve (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-22937-ceremony-promotions
    Worktree: objectstack-issue-22937-pr3 (in the cloud session's own checkout)
    Domain: domain:engine
    Seat: domain:engine#2 (seat post #20966)
    File surface: packages/cli/src/utils/organization-ownership-apply*.ts, packages/cli/src/commands/migrate/organization-ownership.ts, packages/core/src/security/email-template-row-definition*.ts, packages/core/src/security/index.ts, two changesets
    Container & model: M, mode:cloud (session_01DjKf52bcyXa3fbGW723phR), model: default
    Clause-②: yes
    Responsibility: n/a — not a defect card
    Thread-read: 6153947869
    Serial constraints cleared: PR 2 (#23034) landed as 2808069121; PR 3 is PR #23329, off main, and closes this card

  18. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Patch round for PR 3 (PR #23329): the contract review is FAIL (6154293191) · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-13T20:15Z

    To session_01DjKf52bcyXa3fbGW723phR. Read the record in full. The seat's answers are below; all of it is in this PR.

    F1, the claim gate: done by the seat. The Claim: naming claude/issue-22937-ceremony-promotions is 6154303731. Your next push re-runs the gate.

    F2 (blocking): the template delete must stay inside fate 2 on every run, resumed runs included.

    • Today, under single, the sys_email_template DELETE is WHERE 1 = 1, discharged by posture alone. So:

      • on a resumed run (template-promotion checkpointed, mirror-deletion not), a row customized or authored between runs is deleted unpromoted;
      • a nameless row is "reported, never promoted", and then deleted.
    • Fix: before the first template DELETE, re-run the idempotent promotion pass. Better still, delete only the ids whose environment copy is verified, plus the seeded uncustomized mirrors B1 already deletes, and block on any other row.

    • The nameless arm becomes a blocker, which keeps the row, names it, and leaves verified_at null. It is never deleted.

    • Pins:

      • a between-runs case: a row customized after the promotion checkpoint survives and blocks, or is promoted, and is never deleted unpromoted;
      • a nameless-row case.

      Each comes with a measured ablation.

    The walled promotion is in this PR (the maintainer's Q3 「本卡补做提升」, applied as ADR-0131 §6 Q1 ruling C words it). PR 3 must not leave a walled deployment unable ever to verify.

    • Under isolated or group, the population is the same B1 kept set, grouped by (name, locale):

      • One candidate body for a (name, locale), or several identical ones: promote it through the same door, as under single.
      • Two or more differing bodies for one (name, locale) are a conflict, fate 4. List it in the plan and the --apply report with each candidate's row id and organization. It counts as remaining and blocks verified_at until the operator chooses one row per conflict. ⛔ Nothing is guessed, and no conflict row is deleted.
    • The operator's choice: use the smallest shape that fits the command's existing flags and report. For example, a repeatable flag that names one row id per conflict, or a choices file. Validate it against the listed conflicts: an unknown or ambiguous choice is refused with a located message. Name the shape in the changeset; it is part of the declared widening.

    • Pins:

      • a walled database with no conflict ends verified;
      • a conflict blocks and names its candidates;
      • a chosen conflict promotes the chosen body, verifies, and deletes the losers only after the promotion is verified;
      • a bad choice is refused.

      Each comes with ablations.

    • If this turns out to need more than about 600 added lines, or a decision this text does not settle, stop and report the fork. Do not narrow it silently.

    The notes, same round:

    • Give the settings move the same population as its departure (organization_id IS NULL), and read back each destination row before deleting its source.
    • Print the moves on the human face.
    • The mapper uses EMAIL_TEMPLATE_FLOOR_LOCALE, not 'en-US'.

    The card closes with this PR. The card's C7b sentence (drop sys_user_permission_set.permission_set_id and both indexes) is carried by #15211, C7b's own card, which stays open. The seat posts that pointer, so Fixes #22937 stays. Add one line to the PR body under the known limits, naming #15211 for the column drop.

    Then:

    ⛔ Do not ready, queue or arm the PR.

  19. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    PR 3 of 3 (#23329), patch round 6154321875

    {
      "issue": 22937,
      "status": "done",
      "branch": "claude/issue-22937-ceremony-promotions",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23329",
      "head": "db20886484",
      "session": "session_01DjKf52bcyXa3fbGW723phR",
      "premise_still_valid": true,
      "summary": "Patch round for review FAIL 6154293191 / patch round 6154321875. Commit 1bede353, then a clean merge of origin/main 614fdec8 (db208864, no PR file touched). F1 is the seat's claim (6154303731). F2: mirror deletion re-runs the idempotent template promotion after the fate-2 gate and before its first template DELETE; if that pass is not done, the step is blocked and nothing is deleted. It then deletes the seeded, uncustomized mirrors (the selector keeps the whole B1 population, in any posture) and, by id in IN_CHUNK slices with a count read-back, only the rows whose environment copy that pass verified. A nameless customized or authored row is a blocker: kept, named, verified_at null. Walled promotion: the step runs under every posture over the B1 kept set grouped by (name, locale). A single or identical candidate is promoted through the door. Differing bodies are a conflict: listed in the plan (TablePlan.templateConflicts) and the --apply report (TableOutcome.templateConflicts plus the step blocker), each candidate with row id and organization, counted as remaining, blocking verified_at. The operator chooses with the repeatable --template-choice ROW_ID; the chosen body is promoted, and every candidate of that group is deleted by id only after the promotion is verified. A choice that names no candidate, or two candidates of one conflict, throws TemplateChoiceRefusal before any write; the command maps it to reason template-choice-refused, and --template-choice without --apply is refused. Notes: the settings move selects organization_id IS NULL (when the column exists) and reads each destination row back, requiring equality, before deleting the source; the human face prints moved out / moved in and the template conflicts (plan and apply); the core mapper falls back to EMAIL_TEMPLATE_FLOOR_LOCALE. Changesets updated (flag, conflict rule, walled promotion, F2, settings selector; core: one constant import).",
      "body_change_for_seat": "Please add one line under the PR body's 'Not in this PR' list: '- The sys_user_permission_set.permission_set_id column and its index drop is #15211's, not this PR's.' The body's other walled-template lines ('Under a wall no promotion runs…', the walled pin, 'Under single, after it has run, PR 2's template claims are discharged') are now stale and describe the previous head: under every posture the promotion runs, conflicts block until --template-choice, and the template delete is by verified id only. The os-dev role makes no body PATCH, so the seat owns it.",
      "tests": "organization-ownership-apply.test.ts now 17 cases (was 12). New pins: (1) between runs: killed at DELETE FROM sys_capability with template-promotion checkpointed, a customized row tpl_late inserted, the resume promotes crm.late and ends complete, blocking 0, no template row left; (2) a nameless customized row blocks the promotion, stays, is named, verdict complete:false; (3) walled, no conflict: complete, blocking 0, crm.note promoted, mirror and row deleted, no departure; (4) conflict under group: blocked, conflicts 1, the blocker names 'tpl_a (organization org_a), tpl_b (organization org_b)' and --template-choice, templateConflicts listed in the report, both rows kept, nothing promoted; (5) chosen conflict (tpl_b): the From B body is promoted, verified, both rows deleted (deleted 2); (6) tpl_nope refused with the exact located message, and tpl_a plus tpl_b refused as ambiguous, with no write. Two existing pins updated: the acceptance case's DELETE allow-list now pins the settings selector with organization_id IS NULL, and the walled acceptance case now expects the four templates promoted (mirror deletion is still not reached there). Ablations through scripts/ablation-replace.mjs, each 'ok restored: blob == HEAD (5805c2d00e26) and git diff HEAD is empty': A1, the pre-delete promotion re-run disabled (to 3534d572b54d): 1 failed | 16 passed, the between-runs pin. A2, the nameless blocker disabled (to f2b1dfa7320e): 1 failed, the nameless pin. A3, the walled-promotion wall restored (to d84779f4e168): 4 failed, the walled cases. A4, the conflict detection disabled (to ee75c35284b1): 2 failed, the conflict and chosen pins. A5, the chosen body replaced by the first candidate (to 98dad315726b): 1 failed, the chosen pin. A6, choice validation disabled (to e54580e7ed9b): 1 failed, the refusal pin. A7, the template keep in the delete selector replaced by a no-op claim (to 614e1551111f): 17 passed, GREEN. Measured cause: the re-run promotion verifies every population row whenever it completes, so the id-only delete never meets an unverified row the keep would hold. The keep is a second line of defence behind A1's gate, which is red under its own ablation; no fixture reaches the keep alone.",
      "gates": "At 1bede353 (main cc14657e): @objectstack/core typecheck exit 0; @objectstack/cli typecheck exit 0; core src/security 39 files / 887 passed; the full @objectstack/cli suite, CI-sharded: unit 2/2 exit 0 (287 files / 4,292 passed), integration 8/8 exit 0 (121 files / 1,067 passed, 2 skipped: the live-PG cells, as in CI); dispatch-gates --commands derived 67, all exit 0 on the first run, and --ran: '67 derived famil(ies) accounted for, 67 run, 0 NOT-MEASURED (a DERIVED zero)'. At db208864 (merge of 6 main commits, 572ecfb2..614fdec8: spec, metadata-protocol, service-automation, plugin-security, docs, pm; none of the PR's files), a scoped re-check: closure rebuilt; core and cli typecheck exit 0; core src/security 887 passed; the ceremony suites 4 files / 39 passed; the derivation re-run is the identical 67. Dogfood: NOT MEASURED, because no dogfood suite exercises the ceremony.",
      "line_budget": "This round: 8 files, +451 / -137, under the ~600 added-line stop. PR against main: 9 files, +1,025 / -47.",
      "files_changed": [
        "packages/cli/src/utils/organization-ownership-apply.ts",
        "packages/cli/src/utils/organization-ownership-plan.ts",
        "packages/cli/src/commands/migrate/organization-ownership.ts",
        "packages/cli/src/utils/organization-ownership-apply.test.ts",
        "packages/core/src/security/email-template-row-definition.ts",
        "packages/core/src/security/email-template-row-definition.test.ts",
        ".changeset/22937-cli-ceremony-promotions.md",
        ".changeset/22937-core-email-template-row-definition.md"
      ],
      "deviations": [
        "Ablation A7 is green, measured and explained in tests; no pin isolates the delete selector's keep.",
        "The settings read-back throws (a mid-write failure: the checkpoint holds, a re-run resumes) rather than returning a blocker, because the INSERT has already been written when it fails. No pin reaches it: SQLite's INSERT ... SELECT always reads back equal.",
        "A --template-choice for a conflict that a finished run already removed is refused as naming no candidate. That is the located message the round asked for, and a re-run without the flag is a no-op."
      ],
      "mcp_calls": "0 MCP writes",
      "api_writes": "1 relay write: this comment. git push is not REST. No ready, queue, arm, review, label, body or MCP write.",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  20. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT: PR 3, PR #23329 at db2088648c · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-13T22:24Z

    Basis:

    • claim 6122368393, and the seat's claim 6154303731 naming this branch;
    • the maintainer's ruling 6138591940 (Q3, Q4) and the seat's answers 6140351542;
    • dispatch 6151180611 and the patch round 6154321875;
    • the dev's reports 6153947869 and 6156054460.

    Everything below was checked on GitHub and in the objects, not taken from the reports.

    • Form:
    • Scope:
      • 9 files, +1,025 / −47 = 1,072 changed lines, in packages/cli, packages/core/src/security and two changesets;
      • no governed path, under 3,000. Not Tier H; the seat lands it.
    • The change, read in the diff:
      • core's emailTemplateDefinitionFromRow;
      • the template-promotion step over B1's kept set, under every posture, grouped by (name, locale). Conflicts are listed, counted and resolved by --template-choice; a nameless row blocks;
      • mirror deletion re-runs the promotion before its first template DELETE, and deletes promoted rows by verified id only;
      • the settings-move step, with organization_id IS NULL and a read-back before each source DELETE.
    • CI on db2088648c: ci-failure --pr 23329 reads GREEN: 40 check runs, none failed. git merge-tree against origin/main 828fe1d5a8 is clean.
    • Contract review: FAIL 6154293191 at 34989ec72e (F1, F2, the walled promotion, the card closure), then the delta review PASS 6156331986 at db2088648c. Every finding is closed. Both records were adopted after a tool-use audit of the reviewer's transcript.
    • Semver: core minor, cli minor, Clause-②: yes (widening). --template-choice is a new flag inside the declared widening, and it is named in the cli changeset.
    • The card closes with this PR. Each piece the card still names has a carrier:
    • Acceptance notes (remedy-quality, not filed):
      • no pin isolates the delete selector's keep (A7 green; it is a second line behind A1's gate);
      • "verified" after door.save is the door accepting in-process, not a find read-back;
      • the plan's conflict read is its one unpaged SELECT;
      • the inventory's organization-stamped category label still says "promoted with the customized population" (the inventory file is outside this PR);
      • the settings read-back's message does not say the destination now holds a differing copy.

    Next: ready and auto-merge now. After the merge: verify the squash and post the landing record; the card closes through Fixes.

  21. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Landing record: PR 3, PR #23329 → ed0383419d; the card closes · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-13T22:57Z

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions