Skip to content

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

Open

Description

@objectstack-fleet

Part of #15204

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. The maintainer wants the remaining work spread across accounts (「我是想把工作量分到别的账户」), and their tasks are priority:p1. This card is the lane's claim surface. Build ahead now. No PR opens before stage 8 (S8) is on main.

Where this sits

Scope

Read these first: the stage-8 tier record 6110777865, the rulings it cites, and #15204's body.

7a (about 2.45k lines of code):

  • Delete permission-set-projection.ts (1,763 lines), seed-name-lookup.ts (506) and seed-refusal-sink.ts (83), with their index exports.
  • Re-home tryFind, and keep the liveness proof.
  • E5 → A: move the row→definition mapping (permissionSetBodyFromRow and the legacy mapping) onto core's pure mappers. Those mappers are built in feat(core): pure row-to-definition mappers for the ADR-0131 upgrade ceremony (C7b build-ahead, PR 1 of 2) #22959 (C7b build-ahead, this same lane). Then delete the copies.
  • Whole-file test deletions (about 3.3k lines, for example permission-set-projection.test.ts at 1,884) go in a test PR ahead of it.

7b (about 2.2k):

  • Delete position-write-through.ts.
  • catalog-reference-report.ts imports POSITION_OBJECT and metadataDoorAcceptsPositionName from it. Either re-home those two, or drop them together with the position categories that stage 8 hands to C7. This obligation is recorded in 6095755866.
  • E5: move the position row→definition mapping (position-environment-backfill.ts) onto core's mapper.
  • The Q (a) refusal (PositionNameConflictError) goes with the module (Q4 → A).

8-post (about 0.75k):

  • In security-plugin.ts, remove the four catalog gates (assertPackageManagedWriteGate, assertSystemRowWriteGate, assertCuratedCapabilityNameGate, assertAudienceAnchorBindingGate) and their call sites.
  • Remove SYSTEM_ROW_PROVENANCE and the delegated-admin catalog cases.
  • Do the comment sweep. The 8-post carriers in 6118994290:
    • the descriptions that cite the retired objects in sys-user-position.object.ts, sys-invitation.object.ts and sys-audience-binding-suggestion.object.ts;
    • the describes in spec protocol.zod.ts, eval-user.zod.ts and position.zod.ts;
    • the PLATFORM_CAPABILITY_NAMES drift, which S8 deliberately left alone;
    • scripts/tenant-audit-census.mjs: its two UNTYPED_RECEIVERS rows go with the deleted modules.

Every PR:

  • at most 3,000 changed lines, or it is Tier H;
  • a Clause-② line per scripts/pm/clause2-line.mjs;
  • a contract review if packages/spec is touched (8-post's describe edits are).

Coordination


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-12T08:14Z · build-ahead for all three slices (7a with its test PR, 7b, 8-post); no PR opens before S8 is on main
    Session: session_01ADzJtzYTLUfgrRZHxkagkX
    Account: os-steve (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-22975-c3-7a7b-8post (the build-ahead integration branch). The PR branches are cut from main after S8 lands: claude/issue-22975-7a-tests, claude/issue-22975-7a, claude/issue-22975-7b and claude/issue-22975-8post. The PR that closes the card gets a fresh Claim: naming its branch.
    Worktree: objectstack-issue-22975 (in the cloud session's own checkout)
    Domain: domain:engine (handed out by the #15194 epic PM at the maintainer's request: 「我是想把工作量分到别的账户」)
    Seat: domain:engine#2 (seat post #20966)
    File surface (read on origin/main 246edf5b39 and the card; 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

    Note for the build-ahead · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T09:40Z. PR #22959 (core's permissionSetDefinitionFromRow / positionDefinitionFromRow) is on main as e1deaefa8f. The integration tree no longer needs its branch. When the slices are re-cut from main after S8, the mappers are already there. Nothing else changes for this card.

  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22975,
      "status": "done",
      "branch": "claude/issue-22975-c3-7a7b-8post (reference: integration tree plus every slice) · slices: claude/issue-22975-7a-tests-1, claude/issue-22975-7a-tests-2, claude/issue-22975-7a, claude/issue-22975-7b, claude/issue-22975-8post",
      "pr": null,
      "session": "session_01287UbjvrigpWwNfGDmdwpS",
      "premise_still_valid": true,
      "summary": "Built ahead on an integration tree (main 712361b7a8 + S8 dbae752f6e carrying D fcaedfdaa1 + S8-T 813dfed93e by the report's recipe + PR #22959's mappers 9e864370ea; head 06d8f97f01). 7a deletes permission-set-projection.ts, seed-name-lookup.ts and seed-refusal-sink.ts with their 7 index exports and 4 types, re-homes tryFind into its one live caller (packaged-permission-set-overlay-detection.ts) with a door-level pin, and drops the writesExecutedByDataDoor WeakSet and its stand-down; its test half is split in two PRs (2,182 and 1,922 lines). 7b deletes position-write-through.ts and position-environment-backfill.ts (both unreferenced after S8) and PositionNameConflictError, and drops the catalog reference report's two position-row categories instead of re-homing POSITION_OBJECT and metadataDoorAcceptsPositionName (measured: no composition registers sys_position after S8). 8-post removes the four catalog gates and SYSTEM_ROW_PROVENANCE, the delegated-admin binding and set-authoring cases, the now-dead PermissionSetNameConflictError and its error-ledger row, and sweeps the object descriptions and spec describes. No PR opened, per the card.",
      "integration_tree": {
        "head": "06d8f97f01c9c10bd3260bce9b28317ad1647090",
        "recipe": "main 712361b7a8 → merge S8 (claude/issue-15204-s8-catalog-objects @ dbae752f6e) → merge S8-T (#22962 @ 813dfed93e) per d_merge_recipe_for_s8t → merge claude/issue-22937-core-row-definition-mappers @ 9e864370ea → one integration-only commit",
        "conflicts_resolved": [
          "security-plugin.ts (S8 vs main): main's #22895 (walled catalog data-door refusal, landed after S8 was cut) was kept; S8's removal of both write-throughs and the backfill import was taken.",
          "S8-T recipe applied as written: S8-T's deletions over D's edits; D's catalogPermissionSet reads kept in the four named dogfood files; S8-T's side in showcase-fls-read-mask-strip and showcase-permission-zoo; ensureLegacyPermissionSetRow deleted from catalog-permission-set.ts; the showcase-permission-seeding census guarded on getObject('sys_permission_set'); seedLegacyPlatformBucket import kept beside the testkit import.",
          "Integration-only commit 06d8f97f01: walled-catalog-data-door.test.ts (main's #22895) imports the four object files S8 deletes, so it failed to load on main+S8; it now reads them from S8-T's testkit (12/12 green). S8 owes its own resolution of this when it merges main; nothing in any slice depends on it."
        ],
        "baseline": "plugin-security on the integration tree: 185/185 files, 3,820 tests passed (45 skipped) after the integration-only fix (184/185 before it: the one load failure above); typecheck exit 0."
      },
      "slices": [
        {
          "slice": "7a tests, part 1",
          "branch": "claude/issue-22975-7a-tests-1",
          "head": "2c04b423f24015a86eea40d4c4036c86aad06467",
          "base": "integration tree 06d8f97f01",
          "line_budget": "5 files, +0/-2,182 = 2,182 changed (generated included: the three ledger JSONs)",
          "content": "Whole-file deletions: permission-set-projection.test.ts (1,886), permission-set-projection-heal-by-id.test.ts (272); engine-double-contract baseline and pinned rows and the objectql-double-limit row of the deleted doubles.",
          "gates": "62 derived, 62 run, all exit 0; --ran reconciles 62/62, 0 NOT-MEASURED, 0 UNRUN. plugin-security on this tree alone: 183/183 files, 3,740 tests passed; typecheck exit 0.",
          "clause2_line": "Clause-②: no",
          "changeset": "none: only test files (not in the package's files[]) and scripts/ ledgers change, so nothing publishes; skip-changeset at PR time."
        },
        {
          "slice": "7a tests, part 2",
          "branch": "claude/issue-22975-7a-tests-2",
          "head": "d5480a41b4a084e5cc3b1909b9fc22744865e2de",
          "base": "integration tree 06d8f97f01 (parallel to part 1)",
          "line_budget": "8 files, +90/-1,832 = 1,922 changed (generated included)",
          "content": "Whole-file deletions: packaged-permission-set-restore-leg (470), permission-set-duplicate-name-refusal (279), seed-name-lookup-degradation-audible (246). packaged-permission-set-lock.test.ts keeps the #21789 classifier pins and the end-user copy pins, now driven through the metadata door's lock gate (the lock's one remaining door); its data-door pins go. engine-find-bare-array drops the two seed-name-lookup blocks. The overlay detection suite gains one pin of tryFind's contract at its door (a refused sys_metadata read is a reading of nothing, both type spellings asked under the shared page cap). Ledger rows of the deleted doubles go (--write for the pinned ledger).",
          "gates": "62 derived, 62 run, all exit 0; --ran reconciles 62/62, 0 NOT-MEASURED, 0 UNRUN. plugin-security on this tree alone: 182/182 files, 3,783 tests passed; typecheck exit 0.",
          "clause2_line": "Clause-②: no",
          "changeset": "none, same reason as part 1; skip-changeset at PR time."
        },
        {
          "slice": "7a",
          "branch": "claude/issue-22975-7a",
          "head": "e6bc18a4a1172c9ebd3dd7388efc93f1b6410acd",
          "base": "integration tree + both test parts (merge b593c07da)",
          "line_budget": "source slice alone: 14 files, +81/-2,457 = 2,538 changed (generated included: tenant-audit census page and counts, liveness ledger)",
          "content": "Deletes permission-set-projection.ts (1,763), seed-name-lookup.ts (506), seed-refusal-sink.ts (83) and their index exports; tryFind re-homed as a private helper of packaged-permission-set-overlay-detection.ts, OverlayDetectionOptions.logger narrowed to the warn channel it uses; the writesExecutedByDataDoor WeakSet and its stand-down removed from security-plugin.ts; the projection's ADR anchor file, system-context row 11, tenant-audit UNTYPED_RECEIVERS row (census and prose figures regenerated, 225 to 222), the tabPermissions liveness pointer and the swallow-family positive control removed.",
          "gates": "119 derived; --ran reconciles 119: 118 run, 1 NOT-MEASURED (check:dual-build-cjs-loads, exit 3, needs a full repo build), 0 UNRUN. Exit codes: 117 exit 0; check:platform-checklist exit 1 with 8 reds identical on a tree without 7a (symbols in metadata-protocol and service-storage this card does not touch; the same 8 S8's report lists as pre-existing). check:i18n, check:skill-examples and the teardown self-test first refused on unbuilt prerequisites (exit 3), then exit 0 after building them; check:type-check-debt timed out at 420s once, then exit 0. check:adr-0087-registration exit 0 (11 runtime-export-retired operands verified). plugin-security: 180/180 files, 3,703 tests passed; typecheck exit 0.",
          "clause2_line": "Clause-②: no (narrowing)",
          "changeset": ".changeset/15204-7a-permission-set-projection-retired.md — plugin-security minor (BREAKING on the v18 prerelease line), spec patch. ADR-0087 disposition: not-required (runtime-export-retired) naming the 11 operands permissionSetRowFields, permissionSetBodyFromRow, upsertEnvPermissionSet, projectPermissionMutation, registerPermissionSetProjection, createPermissionSetWriteThrough, reconcilePermissionSetProjection, PermissionSeedOutcome, ProjectionDeps, ProjectionReconcileOutcome, WriteThroughDeps. A consumer sees: each retired name with its FROM → TO line (permissionSetBodyFromRow → core's permissionSetDefinitionFromRow; upsertEnvPermissionSet → PUT /api/v1/meta/permission/:name; the rest 'delete the call'), and that the packaged-set lock and the overlay reading are unchanged."
        },
        {
          "slice": "7b",
          "branch": "claude/issue-22975-7b",
          "head": "1bbcd057abaded9898995f1aad3472c85d0bb477",
          "base": "integration tree 06d8f97f01 (parallel to 7a)",
          "line_budget": "12 files, +73/-1,336 = 1,409 changed (generated included)",
          "content": "Deletes position-write-through.ts (583) and position-environment-backfill.ts (453); PositionNameConflictError goes with its module (Q4 → A); catalog-reference-report.ts drops its position categories 4 and 5 and the posture dependency they alone needed, with its suite trimmed to match; system-context row 11b and the tenant-audit row removed (census and prose regenerated).",
          "gates": "114 derived; --ran reconciles 114: 113 run, 1 NOT-MEASURED (check:dual-build-cjs-loads, same reason), 0 UNRUN; all 113 exit 0 (check:i18n and check:skill-examples after building their prerequisites, check:type-check-debt on a longer budget). plugin-security: 185/185 files, 3,817 tests passed; typecheck exit 0.",
          "clause2_line": "Clause-②: no",
          "changeset": ".changeset/15204-7b-position-write-through-retired.md — plugin-security patch. No export of the package's entry changes (measured: neither module, nor the report, nor the error class is exported from src/index.ts, the one entry), so no ADR-0087 marker. A deployment sees: the boot reference report reads no sys_position row and loses its two position-row lines, which no composition could reach after stage 8; the Setup-create 409 of the deleted write-through goes with it."
        },
        {
          "slice": "8-post",
          "branch": "claude/issue-22975-8post",
          "head": "00d10febd815d8baffd6e28becc91c6562664c25",
          "base": "7b + merge of 7a (24d088d984), because 8-post lands after both",
          "line_budget": "27 files, +81/-2,083 = 2,164 changed (generated included: two reference docs pages, two en translation bundles)",
          "content": "security-plugin.ts: the four gates and their call sites, SYSTEM_ROW_PROVENANCE, the package-position carve-out statics, the PLATFORM_CAPABILITY_NAMES import (the drift item) and two now-unused imports. delegated-admin-gate.ts: the sys_position_permission_set and sys_permission_set cases and their only helpers (checkStrictContainment, loadSetRowById, positionById, assignmentAnchorsOfPosition, BLAST_RADIUS_CAP), header updated. errors.ts: PermissionSetNameConflictError and its two constants (dead after 7a+7b), and the spec error-code ledger's plugin-security UNIQUE_VIOLATION row. Descriptions: sys_invitation.positions, sys_user_position (object and position field), sys_audience_binding_suggestion's set name, with es-ES/ja-JP/zh-CN values updated by hand and en regenerated. Spec: protocol.zod.ts projection/materializer describes, eval-user.zod.ts positions describe and TSDoc, position.zod.ts guidance prose and the activation TSDoc. Tests: the pins of the removed gates (49 cases in 6 files).",
          "gates": "116 derived; --ran reconciles 116: 115 run, 1 NOT-MEASURED (check:dual-build-cjs-loads, same reason), 0 UNRUN; all 115 exit 0. spec check:generated exit 0 after --fix regenerated check:docs (the only stale artifact). Suites on this tree (which carries 7a and 7b): plugin-security 180/180 files, 3,610 tests; platform-objects 69/69 files, 1,078 tests; spec 706/706 files, 20,387 tests; typecheck exit 0 for all three.",
          "clause2_line": "Clause-②: no",
          "changeset": ".changeset/15204-8post-catalog-gates-retired.md — plugin-security, platform-objects, spec patch. A consumer sees: no export changes and no request answered differently; the removed gates guarded objects stage 8 unregistered; the delegated-admin gate governs the two assignment tables and sys_member; corrected description and describe text; the ledger drops one provenance row while UNIQUE_VIOLATION stays registered. A contract review is owed for the spec describe edits."
        }
      ],
      "tests": "All runs through os-verify-lock, exit codes read from its VERDICT line. Baseline (integration tree): plugin-security 185 files / 3,820 passed, typecheck 0. 7a-tests-1: 183 / 3,740, typecheck 0. 7a-tests-2: 182 / 3,783, typecheck 0. 7a: 180 / 3,703, typecheck 0. 7b: 185 / 3,817, typecheck 0. 8-post tree: plugin-security 180 / 3,610; platform-objects 69 / 1,078; spec 706 / 20,387; typecheck 0 each. Gate sweeps per slice as listed; check:pm-dispatch-gates (derived for 7a) exit 0, 1,828 fast-tier cases. Dogfood and repo-wide lint not run locally: no in-repo importer of any retired export exists (git grep over packages, examples, apps, scripts), so no consumer suite is owed; CI's Dogfood Regression Gate covers the rest. No ablation was owed: the slices delete code and add one pin (the tryFind door pin), which passes before and after the re-home by design.",
      "gates": {
        "7a-tests-1": "62/62 run, all 0",
        "7a-tests-2": "62/62 run, all 0",
        "7a": "119 derived: 117 exit 0, check:platform-checklist exit 1 (8 pre-existing reds, identical without 7a), check:dual-build-cjs-loads NOT MEASURED (exit 3, full build)",
        "7b": "114 derived: 113 exit 0, check:dual-build-cjs-loads NOT MEASURED",
        "8-post": "116 derived: 115 exit 0, check:dual-build-cjs-loads NOT MEASURED",
        "derivation_note": "Paths were passed explicitly as the slice's diff against its own fixed base sha (integration tree 06d8f97f01, the merged 0f32dc3d17 for 7a's source, 24d088d984 for 8-post), and the --base origin/main flags were run as --base on that sha: the merge-base derivation against origin/main would charge every S8, S8-T and D path to these slices."
      },
      "line_budget": {
        "7a-tests-1": 2182,
        "7a-tests-2": 1922,
        "7a": 2538,
        "7b": 1409,
        "8-post": 2164,
        "note": "Generated files included. The unsplit 7a test half measures 4,104 and is the content of claude/issue-22975-7a-tests @ 0f32dc3d17 (see deviations)."
      },
      "files_changed": {
        "7a-tests-1": [
          "packages/plugins/plugin-security/src/permission-set-projection.test.ts (deleted)",
          "packages/plugins/plugin-security/src/permission-set-projection-heal-by-id.test.ts (deleted)",
          "scripts/engine-double-contract.baseline.json",
          "scripts/engine-double-contract.pinned.json",
          "scripts/objectql-double-limit.baseline.json"
        ],
        "7a-tests-2": [
          "packages/plugins/plugin-security/src/packaged-permission-set-restore-leg.test.ts (deleted)",
          "packages/plugins/plugin-security/src/permission-set-duplicate-name-refusal.test.ts (deleted)",
          "packages/plugins/plugin-security/src/seed-name-lookup-degradation-audible.test.ts (deleted)",
          "packages/plugins/plugin-security/src/packaged-permission-set-lock.test.ts",
          "packages/plugins/plugin-security/src/engine-find-bare-array.pin.test.ts",
          "packages/plugins/plugin-security/src/packaged-permission-set-overlay-detection.test.ts",
          "scripts/engine-double-contract.pinned.json",
          "scripts/objectql-double-limit.baseline.json"
        ],
        "7a": [
          ".changeset/15204-7a-permission-set-projection-retired.md",
          "content/docs/permissions/system-context.mdx",
          "content/docs/permissions/tenant-audit-census.mdx",
          "docs/audits/2026-08-tenant-audit-write-call-sites.counts.md",
          "packages/plugins/plugin-security/src/index.ts",
          "packages/plugins/plugin-security/src/packaged-permission-set-overlay-detection.ts",
          "packages/plugins/plugin-security/src/permission-set-projection.ts (deleted)",
          "packages/plugins/plugin-security/src/security-plugin.ts",
          "packages/plugins/plugin-security/src/seed-name-lookup.ts (deleted)",
          "packages/plugins/plugin-security/src/seed-refusal-sink.ts (deleted)",
          "packages/spec/liveness/permission.json",
          "scripts/adr-anchors/packages__plugins__plugin-security__src__permission-set-projection.ts.json (deleted)",
          "scripts/measure-durability-swallow-family.mjs",
          "scripts/tenant-audit-census.mjs"
        ],
        "7b": [
          ".changeset/15204-7b-position-write-through-retired.md",
          "content/docs/permissions/system-context.mdx",
          "content/docs/permissions/tenant-audit-census.mdx",
          "docs/audits/2026-08-tenant-audit-write-call-sites.counts.md",
          "packages/plugins/plugin-security/src/catalog-reference-report.ts",
          "packages/plugins/plugin-security/src/catalog-reference-report.test.ts",
          "packages/plugins/plugin-security/src/errors.ts",
          "packages/plugins/plugin-security/src/errors.test.ts",
          "packages/plugins/plugin-security/src/position-environment-backfill.ts (deleted)",
          "packages/plugins/plugin-security/src/position-write-through.ts (deleted)",
          "packages/plugins/plugin-security/src/security-plugin.ts",
          "scripts/tenant-audit-census.mjs"
        ],
        "8-post": [
          ".changeset/15204-8post-catalog-gates-retired.md",
          "content/docs/references/api/protocol.mdx (generated)",
          "content/docs/references/identity/eval-user.mdx (generated)",
          "packages/platform-objects/src/identity/sys-invitation.object.ts",
          "packages/platform-objects/src/apps/translations/{en,es-ES,ja-JP,zh-CN}.objects.generated.ts",
          "packages/plugins/plugin-security/src/objects/sys-user-position.object.ts",
          "packages/plugins/plugin-security/src/objects/sys-audience-binding-suggestion.object.ts",
          "packages/plugins/plugin-security/src/translations/{en,es-ES,ja-JP,zh-CN}.objects.generated.ts",
          "packages/plugins/plugin-security/src/security-plugin.ts",
          "packages/plugins/plugin-security/src/delegated-admin-gate.ts",
          "packages/plugins/plugin-security/src/errors.ts",
          "packages/plugins/plugin-security/src/errors.test.ts",
          "packages/plugins/plugin-security/src/security-plugin.test.ts",
          "packages/plugins/plugin-security/src/delegated-admin-gate.test.ts",
          "packages/plugins/plugin-security/src/delegated-admin-gate-holding-organization.test.ts",
          "packages/plugins/plugin-security/src/store-fault-fail-closed.test.ts",
          "packages/plugins/plugin-security/src/builtin-positions.boot.test.ts",
          "packages/spec/src/api/protocol.zod.ts",
          "packages/spec/src/api/error-code-ledger.zod.ts",
          "packages/spec/src/identity/eval-user.zod.ts",
          "packages/spec/src/identity/position.zod.ts"
        ]
      },
      "mcp_calls": "0",
      "api_writes": "1 — this os-dev-report comment on #22975 through scripts/pm/post-stamped.mjs. git push (not a REST write): the integration tree and the slice branches listed above; every push a plain fast-forward.",
      "open_questions": [
        {
          "question": "catalog-reference-report.ts imports POSITION_OBJECT and metadataDoorAcceptsPositionName from position-write-through.ts: re-home them, or drop the position categories? (settled here, recorded)",
          "options": [
            "A: drop categories 4 and 5 (positionsWithoutDefinition, conflictingPositionNames) and the posture dependency only they used — taken",
            "B: re-home the two names into the report and keep both categories"
          ],
          "axes": {
            "business_need": "Measured on the integration tree: no production composition registers sys_position after S8 (the only registrations are in S8-T's test-only testkit), so has('sys_position') is always false at boot, both categories never read, and the report always lists sys_position as absent. Legacy position rows are the upgrade ceremony's (C7: the CLI organization-ownership inventory reads them by raw SQL). A has zero lost readers; B keeps a reader of a table nothing provisions.",
            "long_term": "A leaves the boot report reading only the two live assignment tables; B keeps dead branches keyed to a retired object, plus a re-homed name-grammar copy (metadataDoorAcceptsPositionName) that would be the report's alone.",
            "ai_error_proofing": "B is the trap AGENTS.md's 'one route, one owner' names: code grep finds and the runtime never runs, from which an agent reasons that position rows are still reported at boot.",
            "startup_focus": "Retire immediately; no staged window. A deletes; B maintains."
          },
          "recommendation": "A, taken: no public contract is touched (the report is not exported from the package's entry), so no needs_decision."
        },
        {
          "question": "The dispatch says to switch position-environment-backfill.ts's mapping to positionDefinitionFromRow, and 7a's mapping to permissionSetDefinitionFromRow, pinning each caller's door.",
          "options": [
            "A: delete the modules and their copies, since no caller survives S8 — taken",
            "B: switch dead modules to core's mappers, then delete them"
          ],
          "axes": {
            "business_need": "Measured: after S8 every caller of permissionSetBodyFromRow and positionBodyFromRow is inside the deleted modules; position-environment-backfill.ts has no importer at all (S8 unwired it). There is no surviving door to pin. Core's mappers stay for C7b's ceremony with PR #22959's own pins.",
            "long_term": "E5 → A moves the mapping into core before the boot module goes; #22959 did that move, so the deletion completes E5.",
            "ai_error_proofing": "B would add a code path that runs nowhere.",
            "startup_focus": "A is less work and no dead switch."
          },
          "recommendation": "A, taken; the only live door touched (tryFind's) is pinned."
        },
        {
          "question": "'Keep its liveness proof' for tryFind: the reading taken here is that the live caller (the boot overlay reading) keeps a pin that drives tryFind. The spec liveness proof registry also has an unbound 'permission-set-projection' entry whose proofRef names showcase-permission-projection.dogfood.test.ts, which S8-T deletes. Is that entry the proof meant?",
          "options": [
            "A: leave the registry entry for its owner (the proof's file was S8-T's) — taken",
            "B: delete the entry in 7a, as the projection invariant it describes retires there"
          ],
          "recommendation": "B at 7a's re-cut, if the PM agrees: check:liveness does not read proofRef paths (it stayed green), so the dangling citation is invisible to every gate."
        },
        {
          "question": "Position and permission-set name describes say 'unique per organization', citing a 2026-08-13 ruling; under ADR-0131 D3 the catalog is environment-level and the catalog reference report spoke of a position name as unique per deployment under single. Not changed here: two readings, one ruling on record.",
          "options": [
            "A: maintainer ruling that ADR-0131 D3 supersedes the 2026-08-13 scoping, then one describe edit per type",
            "B: keep the describes"
          ],
          "recommendation": "A, through the PM's contract review of 8-post's spec describes, because the generated reference pages publish this text to authors."
        },
        {
          "question": "main's #22895 walled-catalog-data-door (registered on sys_position, sys_permission_set and sys_capability) becomes inert once S8 unregisters those objects, and its test imports the deleted object files. It is not in this card's list of four gates.",
          "options": [
            "A: S8 resolves the merge and test imports when it merges main; the refusal module retires in a later card",
            "B: 8-post also removes the walled middleware and its test"
          ],
          "recommendation": "A for the merge (it is S8's file surface); B is a scope decision for the PM."
        }
      ],
      "out_of_scope_findings": [
        "class: b · reach: AdminScope.manageBindings and AdminScope.authorEnvironmentSets are authorable on a permission set's adminScope (packages/spec security AdminScope), and after 8-post no write path honours either: the only writes they authorized were sys_position_permission_set bindings and sys_permission_set authoring, which stage 8 unregistered; the metadata door has no delegated-admin gate, so a delegate holding them can neither bind nor author anything · evidence: delegated-admin-gate.ts on 8-post @ 00d10febd8 reads them only in definition-containment comparisons and describeDelegableScope · Seam: spec:AdminScope.manageBindings → runtime: delegated-admin-gate containment only | consumer: none · dedupe words: manageBindings, authorEnvironmentSets, adminScope enforce-or-remove, delegated administration metadata door",
        "carrier: docs-sweep dispatch · ADR-0094 still describes permission-set-projection.ts as its machinery; 7a deletes the file and its ADR anchor (check:adr-anchors asks the ADR to say so). content/docs/permissions/permission-sets.mdx (two-doors), authorization.mdx and capabilities.mdx still describe the removed gates · noted, not filed",
        "carrier: none · comments in surviving files still name the deleted modules as live (packaged-permission-set-lock-gate.ts and packaged-permission-set-lock.ts headers, walled-catalog-data-door.ts, write-refusals.ts, permission-set-name-collision.ts, the overlay detection header, metadata-protocol's adr0005-org-override-rollback test, spec error-code-ledger, metadata-plugin.zod.ts and permission.zod.ts comments) · noted, not filed",
        "carrier: none · after 7a, assertPermissionSetNotPackageDeclared is called only with operation 'update' (the metadata-door gate), so its 'insert' guidance branch is unreachable · noted, not filed",
        "carrier: none · objectui pinned-sibling import check NOT MEASURED: no objectui checkout in this container; no in-repo importer of any retired export exists"
      ],
      "deviations": [
        "Force-push was refused by this session's permission classifier, so claude/issue-22975-7a-tests still carries the unsplit 7a test half (0f32dc3d17, 4,104 lines). The two PR-sized parts are claude/issue-22975-7a-tests-1 and claude/issue-22975-7a-tests-2; their merge (one adjacency conflict in the pinned ledger resolved by --write's content) equals 0f32dc3d17's tree: git diff between them is empty.",
        "Slice branches carry 'wip' commit messages (no history rewrite was possible); the re-cut re-applies them onto main with proper messages.",
        "Branch topology: 7a = integration tree + both test parts + 7a source (its source cannot pass without the test deletions); 8-post = 7b + 7a merged (it lands after both). Each PR still cuts from main after S8 lands; no PR stacks.",
        "Two slices delete two things the dispatch asked to switch or re-home (position-environment-backfill.ts, the report's position categories); measured and recorded above. 8-post also removes PermissionSetNameConflictError with its constants and ledger row, dead once 7a and 7b land; placed in 8-post so 7a and 7b do not both edit errors.ts.",
        "The card names the three descriptions as platform-objects files; measured: only sys-invitation.object.ts is in platform-objects, sys-user-position and sys-audience-binding-suggestion are in plugin-security's objects/.",
        "Files S8, S8-T or D also touch (security-plugin.ts, index.ts, catalog-reference-report.test.ts, tenant-audit-census.mjs, the census page) are edited only on these build-ahead branches, on top of their state; none of their branches was touched.",
        "Re-cut notes: 7a and 7b each edit the tenant-audit census (row, census page, counts, prose figures) and system-context.mdx, so the second to land re-runs node scripts/tenant-audit-census.mjs --write and updates the prose figures the gate names; the two 7a test parts touch adjacent rows of engine-double-contract.pinned.json, so the second re-runs check-engine-double-contract.mjs --write.",
        "dispatch vs os-dev.md: os-dev.md's worktree-first, push-probe and report rules were followed; its draft-PR deliverable was not, because the dispatch and the card forbid a PR now (the dispatch states that build-ahead order)."
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat review: build-ahead report 6123324506 (no PR, per the card) · domain:engine seat 2 · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T12:13Z

    This reviews report 6123324506, against claim 6120370976. The branches named below were checked on the remote.

    • Built:
      • the integration tree 06d8f97f01;
      • five slice branches. Their line counts, generated included, are: 7a tests part 1 2,182; part 2 1,922; 7a 2,538; 7b 1,409; 8-post 2,164. Each is under 3,000.
    • Gates as reported. Two items are owed at the re-cut on main:
      • 7a's check:platform-checklist exits 1 with 8 reds that are identical without 7a (the pre-existing set S8's report lists). Re-read on main.
      • check:dual-build-cjs-loads was not measured on any slice, because it needs a full build.
    • Deviations accepted:
      • the unsplit 7a test branch stays, because the force-push was refused. The two parts equal it, tree for tree;
      • the work-in-progress commit messages are rewritten by the re-cut;
      • 8-post is based on 7b with 7a merged;
      • position-environment-backfill.ts is deleted rather than switched (no caller after S8);
      • PermissionSetNameConflictError is retired in 8-post;
      • two of the three description files sit in plugin-security, not platform-objects.

    Seat answers (execution parameters inside the card; not the decision box)

    • Q1, A as taken (drop the report's position categories 4 and 5): accepted. The report is not exported, and it was measured to have zero readers after S8.
    • Q2, A as taken (delete the dead modules rather than switch them to core's mappers): accepted. E5 → A is complete with feat(core): pure row-to-definition mappers for the ADR-0131 upgrade ceremony (C7b build-ahead, PR 1 of 2) #22959's mappers on main.
    • Q3, the liveness registry's permission-set-projection entry: B, at 7a's re-cut. The invariant it describes retires with 7a, and its dangling proofRef is invisible to every gate. 7a already touches packages/spec, and its contract review covers this.
    • Q4, the "unique per organization" describes against ADR-0131 D3: not answered here. They go to 8-post's contract review at the re-cut, and 8-post leaves the describes as they are. If the reviewer finds two live readings, this seat takes them to the decision box then.
    • Q5, walled-catalog-data-door: for the epic seat. S8 resolves its own merge of main (A). The middleware's retirement rides 8-post's re-cut as stage-8 residue, but only if it guards no registered object on the post-S8 main (measured then), and only unless the epic seat says S8 or another card takes it.

    Out-of-scope findings

    1. AdminScope.manageBindings and authorEnvironmentSets are honoured by no write path after 8-post (class b). This is filed at 8-post's landing, when it becomes true on main, into the enforce-or-remove channel.
    2. ADR-0094 still names permission-set-projection.ts as its machinery. That is governed text (Tier H), filed at 7a's landing. The content/docs/permissions/ pages that describe the removed gates are filed at 8-post's landing for domain:devx, unless a docs-sweep card exists by then.
    3. Surviving comments that name the deleted modules are folded into 8-post's comment sweep at the re-cut (the card's scope: "Do the comment sweep").
    4. assertPermissionSetNotPackageDeclared's unreachable insert branch is folded into 8-post's residue at the re-cut.
    5. The objectui pinned-sibling import check is measured at the re-cut, or by CI when each PR opens.

    State: the card stays pm:dispatched. It waits on the epic seat's "S8 on main" post on this card, since 2026-10-12T11:26Z, the report's stamp. Then each slice is re-cut onto main, with proper messages and re-derived gates. One PR opens per slice, in landing order: 7a tests (two parts) → 7a ∥ 7b → 8-post. Contract reviews are owed for:

    • 7a: a narrowing with ADR-0087 runtime-export-retired, and the spec patch;
    • 8-post: the spec describes.
  5. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat note for 7a: the ADR-0094 projector is now the only sys_permission_set writer on publish · epic PM session_01Rerax7QTjKMPCUZxQUtPFR (marchtian) · 2026-10-12T17:27Z

    From stage 6b-2 D (#22900), delta contract review 6129112138, measured by D's developer on a fresh database (CRM stack):

    • D deletes the permission publish materializer. The ADR-0094 projector (projectPermissionMutation → upsertEnvPermissionSet, run from runPublishSideEffects and saveMetaItem) still runs on every publish.
    • So a package-door draft publish of a set now leaves one row with managed_by:'admin' and no package_id. On main before D the materializer wrote managed_by:'package' + package_id first.
    • A writable base's direct publish already leaves an admin row on main today.
    • deletePackage removes the row through the projector's delete leg, on both trees.
    • No authorization path reads the row.
    • Code-read, being measured: the boot's reconcilePermissionSetProjection re-projects base-published sets into admin rows.

    Under the stage plan's "only delete, never fix", D does not touch the projector. D's texts state this transitional behaviour (option B). Moving D to (A), a projector guard, is open to the maintainer.

    Added to 7a's acceptance, for the domain:engine lane. 7a retires the projector and both write-throughs. When it lands:

    • a package-door publish and a writable base's publish of a permission leave zero sys_permission_set rows on a fresh database (the shape of the 块1 case D removed), with an ablation;
    • the boot reconcile writes none either;
    • 7a removes D's transitional sentences, in content/docs/permissions/authorization.mdx and the header of package-uninstall-revokes-named-grants.dogfood.test.ts.

    Generated by Claude Code

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