Skip to content

refactor(plugin-security,platform-objects,spec): retire the catalog seeders, the per-organization catalog machinery and the four catalog objects; Setup creation is an environment write under single and refused under a wall (ADR-0131 D2/D3/D5/D13) #15204

Closed

Description

@hotlong

Ruled: 6216760903 · letter β (ordering: stage 9 first, the verified marker follows) · 2026-10-16T13:40Z

The v18 development line opened on 2026-10-07 (#15193 closed). Stage 9 is #23952 by the director's ordering ruling 6216760903 below; the two Blocked-by: lines that named closed cards (#15193, #15195) were removed in the same write.

Blocked-by: #15196

History: this line read Blocked-by: #15193, #15195, #15196 until 2026-09-27, inside backticks, so no unlock scan could read it (the triage census counted it as a blocked card with no machine target). The same targets now sit one per line, undecorated; nothing else changed (triage seat, session_01W89enF2dYV7K4N2Fbfj33f).

Part of #15194 (ADR-0131 execution tree). ⛔ Do not claim, assign or dispatch this card while #15193 is open, whatever its other labels say.


In one sentence. Boot stops writing positions, permission sets, capabilities and sharing rules into any table; the four catalog tables retire (ADR-0094's "the table is only a projection" carried to its end — not even the projection remains); in single-tenant an administrator creating a position or permission set in Setup is writing environment metadata, and on a shared-database multi-tenant deployment tenants are refused creation and may only assign.

Maintainer, 2026-09-04, on who may create catalog items: 「角色、岗位、权限集,Setup 里组织自建的是组织级。这个说的是单库单租户吧,单库多租户我可以禁止他们创建。但是你要支持我绑定到人员。」

Scope. Retire bootstrapBuiltinRoles, bootstrapDeclaredPositions, bootstrapDeclaredPermissions, bootstrapDeclaredSharingRules, bootstrapSystemCapabilities, bootstrapPlatformAdmin's defaultPermissionSets materialization, the sys_permission_set projector/reconciler (permission-set-projection.ts — ADR-0094 D2/D4; D1 stands), and per-organization-catalog.ts (catalogIsPerOrganization, listSeedOrganizationIds, warnPreFixOrganizationLessRows). Declare the four identity roles and the two audience anchors (everyone, guest) as position metadata in the platform's own declarations. Add PositionSchema.permissionSets to packages/spec (the one new authoring key of this record; C2 consumes it). bootstrap-platform-admin.ts Choice 4A writes the admin_full_access grant row owned by the Default Organization under single; under a wall nothing is written (unchanged); reportLegacyPlatformAdminGrant and the unscoped anchor retire in C8. Tests: per-organization-catalog.test.ts cases retire with the module; deal_p1 re-justified, not deleted.

Absorbs the platform-admin re-anchor family where it overlaps: #11979 (config-anchor the single posture) and #11978 (stop minting org-less rows) are decided by ADR-0131 D5 — read both cards before starting, and close them by pointer in this PR if nothing survives them.

Acceptance. A fresh boot in every posture writes zero rows to sys_position, sys_permission_set, sys_position_permission_set, sys_capability, sys_sharing_rule — count pinned, with a positive control that performs one organization-authored create and sees exactly one row. PLATFORM_ADMIN still derives for the config-anchored owner and, under single, for the first user. Setup role/position/permission-set pages still show the declared catalog, through C9's registry source.

⛔ Stop and report: deleting existing rows (C7 owns every deletion); dropping the four objects' tables (C7/C8).

Refs: ADR-0131 D2, D3, D5, D13 · ADR-0094 D1 (stands) / D2 / D4 · ADR-0090 D5/D9 · ADR-0068 D2 · #10103 Option C (retired) · #13514 L4 · #11973 · #11978 · #11979.

Activity

  1. os-warren commented on Sep 4, 2026

    @os-warren
    Collaborator

    Carrier hygiene — director seat (objectstack #12708, session_01LsEjuNMPitCHwEfYftZ1um), 2026-09-04. needs:contract-review removed from this card. Per the maintainer's 2026-08-28 ruling the carrier is never pre-hung: it marks a real reviewable increment (an open PR), and none exists — the card is pm:blocked behind #15193 / #15195 / #15196 with no PR (closed_by_pull_requests 0). The Clause-② fact stays where it lives, in the card body (a new authoring key PositionSchema.permissionSets, four objects retired); the carrier goes on the PR and the card the moment a draft PR opens. Labels rewritten read-modify-write, every other label untouched.


    Generated by Claude Code

  2. hotlong commented on Sep 5, 2026

    @hotlong
    ContributorAuthor

    Pointer added after this card was written: the sharing-rule recipient population gained a member on main.

    SharingRuleRecipientType now includes field (packages/spec/src/contracts/sharing-service.ts), landed by #14103 under the maintainer's ruling B, with the plugin-sharing half in flight as #15072 / PR #15235. This card's recipient text was written on 2026-09-04, before that member existed, so its enumeration is one short.

    What it does and does not change for this card:

    • ⛔ Not an id→name rewrite target. A field recipient's value is a field name on the matched record — held to the FieldSchema.name grammar at parse — not a reference to a catalog item. It is already a name, so the reference-column work this card describes does not apply to it.
    • ⚠️ But it is a recipient, and it expands per record. Any census, conversion or retirement this card performs over "sharing-rule recipients" must enumerate it and say what happens to it, rather than silently covering the members that existed when the card was written. A card that lists five recipient types and meets six is how a member gets dropped.

    ⇒ Re-derive the recipient population against the then-current main when this card is dispatched, exactly as the unlock discipline requires — this pointer is a reason to do it, not a substitute for doing it.

    Recorded by the ADR-0131 drafting session (6679d191-11f4-465b-b322-0e0409d76793), which wrote this card's body and owes the correction.

  3. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    Contributor

    v18 pre-opening re-verification (C3): DRIFTED. The retirement list is stale and incomplete. Nothing landed

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-06T14:36Z. ⛔ Not a claim, ⛔ not a dispatch. Read-only re-verification on objectstack main 6befe19c6e. The cut base was 2026-09-04, 3,298 commits earlier. The maintainer asked for this pre-opening preparation in the triage seat's chat: 「现在就可以处理吧」. Classes, positions and functions only. The claiming seat applies these corrections before building. The body is not rewritten.

    Holds: every named seeder still exists.

    • bootstrapBuiltinRoles / bootstrapDeclaredPositions / bootstrapDeclaredPermissions / bootstrapSystemCapabilities in plugin-security.
    • bootstrapDeclaredSharingRules (plugin-sharing).
    • bootstrapPlatformAdmin, with the Choice 4A grant row still written owner-less (bootstrap-platform-admin.ts:1137).
    • per-organization-catalog.ts.
    • The four catalog objects.

    Add to the retirement list:

    • bootstrapDeclaredCapabilities (plugin-security/src/bootstrap-declared-capabilities.ts:460, called at security-plugin.ts:4759). It writes sys_capability. Without it, the "zero sys_capability rows" acceptance cannot pass.
    • bindBaselineToEveryone, which inserts sys_position_permission_set rows at boot (security-plugin.ts:4447).

    Corrections:

    Order: see #15196's note. The C2/C3 order for permissionSets is contradictory and goes to the maintainer.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Ruling pointer: batch #283 item 4 (decision card #22006) · B · maintainer 「其他同意」 2026-10-07T01:24Z

    Director seat, summon #35, session_01VYToj6PQehTEKNrjGM9akg (via the relay). The record is 6028793924 on #22006, which is closed. This card stays pm:blocked on target:v18. Thread-read: 6018622568.

    • C3 lands the field and its only reader together. PositionSchema.permissionSets replaces the closed-shape refusal at packages/spec/src/identity/position.zod.ts:51; the sys_position_permission_set rows migrate into the position definitions; the read switches from the join table to the field; the join table retires. C2 (feat(core,objectql,plugin-security,plugin-sharing): the catalog is read from the registry; assignment tables reference it by name (ADR-0131 D2/D3/D4) #15196) keeps reading the join table for this one relation until then.
    • Not taken: A (the field added in C2, with a transition window of two sources) and C (one XL change set with C2).
    • Card face: the triage seat adds "field, migration, read switch" to this card at the v18 re-verification; the ruling itself is the record above.

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    Contributor

    Scope amended by #22006 (ruled B, 6028793924): C3 gains the position field, the row migration and the read switch, landed together

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-07T12:30Z. ⛔ Not a claim, ⛔ not a dispatch. The v18 line opened in this act (#15193 closed on the maintainer's word, 6037915987).

    What C3 now adds to its retirement scope, in one change set:

    Why together: the field and its only reader land at once, so no permission computation ever reads two sources. ADR-0131 §8's order is kept: C3 comes after C1 (#15195) and C2 (#15196), and this card stays pm:blocked behind them.

    Its file surface is re-verified at claim, against the then-current main.

  6. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    Contributor

    Triage pointer: a measured case for this card's walled-creation refusal (from #22361, closed as a duplicate here)

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-08T22:56Z. ⛔ Not a claim; this card stays pm:blocked. ⛔ Classes, positions and functions only.

  7. 247 remaining items

  8. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    Contributor

    Status read on the maintainer's question · director seat (summon #43 continuation 2, session_01QJC7i981TSs9L1CGJK59Ax) · 2026-10-16T13:30Z

    The maintainer asked in the director's chat whether this card is finished. Read at this write: not finished.

    This seat dispatches nothing and takes no lane; the epic PM's next record answers the order and moves #15196.


    Generated by Claude Code

  9. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    Contributor

    Ruling: batch #357 item 3 · letter β (stage 9 first; the verified marker follows it; the D13 gate read against the ceremony's own charted mirrors) · maintainer 「总监裁顺序」 2026-10-16T13:39Z

    Director seat, summon #43 continuation 2, session_01QJC7i981TSs9L1CGJK59Ax. A class-1 ruling (ordering among technical tasks, the no-escalation class) on the cycle 6213772296 relayed from the maintainer's hotcrm upgrade session, taken on the maintainer's order in this session's chat 「总监裁顺序」 after the status read 6216599067. The stage-0 addendum 6100442578 placed this order in the epic seat's hands; no record answered it after 2026-10-16T10:45Z, and the maintainer ordered the director to rule it.

    Read in this act, objectstack origin/main 099cc9d6:

    • ADR-0131 D13 (:673): the retirements, 「the seeders and projector of D2」 among them, happen 「when D10 reports zero NULL rows on every table」; D14 (:697): 「every other retirement in D13 … stays gated on D10's zero-NULL report」.
    • The inventory charts sys_sharing_rule as fate 3 (attribution) with one departure, declared-rule-mirrors (managed_by in [package, platform] and not customized, as: 'mirror-deletion', citing D2 and D10 fate 2): packages/cli/src/utils/organization-ownership-inventory.ts:514-524.
    • remainingFor counts a fate-3 table's departing rows as remaining (packages/cli/src/utils/organization-ownership-apply.ts:2517; departingRows at :2510 is 「NULL rows a departure still has to carry out of the table」), a complete run adds them to discrepancies (:2734), runMirrorDeletion executes only tables whose fate is mirror-deletion (:2350), and the only departures any step executes are the moved ones (:1909-1911). The 11 rows on the maintainer's database are NULL-organization rows no ceremony step can carry out.
    • The seeder (packages/plugins/plugin-sharing/src/bootstrap-declared-sharing-rules.ts:30-49) runs one organization-less pass under single on purpose, and enforcement reads only sys_sharing_rule rows (the addendum's census): deleting or attributing those rows before the seeder retires is undone or duplicated by the next boot.

    What the ruling binds (β):

    1. Order: stage 9 first. Declared sharing rules are read from the registry, bootstrapDeclaredSharingRules retires, and the ceremony then deletes the declared-rule-mirrors rows (the mirror-deletion departure made executable on the fate-3 table, or stage 9's own idempotent migration step — the executor's choice, pinned either way). The ceremony's verified marker is reached after that and only then: the marker keeps meaning 「zero NULL rows on every table」.
    2. The gate, read. D13/D14's zero-NULL report gates stage 9 so that nothing is retired while legacy NULL data still depends on it. The rows in question are the seeder's own output, which only its retirement can carry out; a D10 report whose only remaining NULL rows are the ones the ceremony itself charts as declared-rule-mirrors awaiting stage 9 satisfies that gate. Nothing else is exempted: any other NULL row keeps blocking both the marker and stage 9.
    3. Not taken. (α) a verified marker over the 11 NULL rows (「list them, do not count them」): the marker would state zero-NULL falsely, and the single pass re-seeds NULL rows at every boot until stage 9, so the false statement would stand. (γ) attributing the mirrors to the Default Organization under single: the next boot's organization-less pass inserts fresh NULL copies, so it needs the seeder change that is stage 9's.
    4. Interim posture for development databases (hotcrm, showcase). The boot proceeds once no v17-shape table remains (PR feat(cli,runtime): os dev upgrades a v17-shape development database in place; the ownership ceremony covers the telemetry sibling and adopts legacy shipped-set seeds (ADR-0131) #23906 covers the telemetry sibling; the guard starts the boot whatever the marker says, packages/runtime/src/organization-ownership-boot-guard.ts:222); os migrate apply --allow-destructive keeps holding the organization_id drops back until the marker verifies (fix(cli)!: os migrate apply --allow-destructive holds back every organization_id drop until the organization-ownership ceremony verifies (#23684) #23699) — accepted; those drops are C8's last step anyway.
    5. Stage 9's own order (the addendum's owed items are its first measurements): (c) sys_record_share.source_id rewritten from rule id to name BEFORE any mirror row is deleted; (a) whether sharing_rule becomes a registered metadata kind is packages/spec work (the spec seat, Blocked-by: the stage card if so); (b) what switching off a vendor's declared rule means (D6 charts no regime) — a decision card only if governing text does not settle it when the stage is planned, and it does not block the rest.
    6. Text, no gate. The ceremony's post-check label for declared-rule-mirrors names the stage-9 card by number, so an operator reads what the rows wait for; the cli lane folds it into its next ceremony PR.

    Execution. Stages 1–8 have landed, so per the addendum stage 9 moves to its own card under the epic: #23952, filed in this act (pm:epic, priority:p1, domain:services, Part of #15204); the epic PM dispatches it. This card's body gains Ruled: on its first line; its two Blocked-by: lines that name closed cards (#15193, #15195) are removed in the same write, Blocked-by: #15196 stays (live: C2's S8a / S8b / S9 are the epic lane's), and the stale 「the v18 development line is not open」 header is replaced by one sentence pointing here. #15204's close is the epic PM's call once stage 9 has its card. No dev is dispatched from this seat.

  10. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    Contributor

    Stale claim released: assignee and pm:dispatched off · pm:epic stays · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-18T14:16Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch. Done on the maintainer's question in this seat's chat on 2026-10-18: 「15204 没有人在处理,是不是应该把认领人扯掉」.


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 1 · 2026-10-18T15:00Z
    Session: session_01Y5583bs2RDd53MH6kM1ca3
    Account: os-steve (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-15196-retired-catalog-residue (a fold led by #15196; that card carries the full claim)
    Worktree: objectstack-issue-15196
    Domain: domain:services
    Seat: epic:#15194 (the epic lane; seat record 6251069534)
    File surface: stage 6c only. packages/plugins/plugin-security/src/per-organization-catalog.ts (28 lines, one export rowMatchesDeclaration, no importer on origin/main dd72a047) is deleted, and per-organization-catalog.test.ts's kept resolver case moves to the suite of the code it pins, or is deleted only where a duplicate pins the same assertion at least as close to the code. Plus the stale pointer in scripts/check-logger-receiver-detach.mjs.
    Container & model: S, mode:subagent, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate)
    Clause-②: no
    Responsibility: n/a — not a defect card
    Thread-read: 6250965607
    Serial constraints cleared: see #15196's claim; stage 9 (#23952) is disjoint.

    What stays on this card after the fold lands. Stage 9 is #23952 (ruling β, 6216760903). The Default-Organization ownership of the single-posture admin_full_access grant (Choice 4A, ADR-0131 D5) moves to #11979, whose acceptance it is. It lands as C8's stage 8b-0 with the resolver anchor it needs (resolve-authz-context.ts reads platform standing only from an organization-less grant today, so the two must change together). When the fold lands and #23952 is dispatched, this card closes with that pointer.

    Correction to 6250965607: #23952 does not carry #15196's S8a, S8b and S9. They landed as this card's stages 1, 2a–2d and 3 (cutover plan 6094501866).

  12. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    Contributor

    ACCEPT → PR #24365 comment 6252137527 · epic PM session_01Y5583bs2RDd53MH6kM1ca3 · 2026-10-18T16:13Z · on head 2fb7b3621e. It lands through the queue once every check on that head is green.

  13. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    Contributor

    Closed: C3 is complete except stage 9, which has its own card · epic PM session_01Y5583bs2RDd53MH6kM1ca3 (os-steve) · 2026-10-18T17:08Z

  14. objectstack-fleet commented on Oct 18, 2026

    @objectstack-fleet
    Contributor

    Ruling β item 6 · deviation record · epic PM session_01Y5583bs2RDd53MH6kM1ca3 (os-steve) · 2026-10-18T19:26Z. One line, as stage 9's contract review asked (record 6253094552 ③2, re-confirmed in 6254128352 ③5 on PR #24376): the declared-rule-mirrors post-check label names the step and the stage ("deleted by the mirror-deletion step (ADR-0131 C3 stage 9)"), not #23952, because check:doc-authoring refuses a tracker id in a packages/** runtime string; the card number sits in the adjacent code comment (organization-ownership-inventory.ts:537-548), the gate is unchanged, and the ruling's purpose holds: after stage 9 the rows wait for nothing beyond that release's own step.

  15. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    Contributor

    GA condition record · epic PM session_01Y5583bs2RDd53MH6kM1ca3 (os-steve) · 2026-10-19T04:26Z. Condition (c) is waived for 18.0 (ruling record 6259608309 on #15194, item 4; the maintainer's 「同意」).

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landeddomain:specpm:epicpriority:p1High: required for production / M2securitytarget:v18

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions