Skip to content

platform-admin re-anchor (L5 removal half): delete the legacy grant-row read — one minor after L4's landing #13515

Closed as duplicate

Description

@os-steve

The removal half of L5 of the accepted #11663 platform-admin re-anchor design, filed at L4's landing exactly as #11975 and the design prescribe (design document = #11663 comment 5394453215, §5 step 6 and §6 row L5: "the dual read is deleted, one minor after step 4. Card filed at step 4's landing, not later"; maintainer acceptance = #11663 comment 5404675670, 2026-08-25, verbatim 「接受你的建议,继续」). Filed by the L4 dev at PR #13514's creation, per the L4 card's own definition of done. #11975 remains open and carries the window's discipline; this card is the window's EXIT.

Restart-when: @objectstack/plugin-security has published a minor greater than the one carrying L4 (PR #13514 / .changeset/walled-bootstrap-stops-granting.md). Measured 2026-08-31: L4 is not in 17.2.0 and 0 major changesets are pending ⇒ L4 ships in 17.3.0, so this exit lands no earlier than 17.4.0.
Restart-touch: packages/core/src/security/resolve-authz-context.ts, packages/plugins/plugin-security/src/bootstrap-platform-admin.ts

⛔ NOT Blocked-by: #11975 — that line was removed 2026-09-01 because it formed a mutual deadlock. #11975 carries Blocked-by: #13515, so the two cards named each other and neither unlock predicate ("the Blocked-by target is closed") could ever fire. #11975 → #13515 is the sound edge and stays: its acceptance criterion genuinely needs this exit on main. This edge was the false one — what this card actually waits for is a release boundary, which was wrongly encoded as a card dependency and is now written as the boundary it is. Diagnosed by triage on this card 2026-08-31; repaired by the domain:services PM seat, to whom triage routed it.

Timing constraint (the minor boundary): lands one minor after the release that carries L4 (PR #13514, @objectstack/plugin-security walled bootstrap stops minting the grant row + deprecation pointer live). The exit PR's body must name the minor boundary it honours (#11975's acceptance criterion).

Content — delete the legacy path, as its own reviewed change (never a rider on another leg):

Acceptance criterion: on a walled rig, a seeded legacy org-less admin_full_access grant confers NOTHING (posture resolves without PLATFORM_ADMIN unless the config anchor matches); the exit is a reviewed change on origin/main whose PR body names the minor boundary; single-posture first-user standing is unchanged unless #11979 landed first.


Generated by Claude Code

Activity

  1. os-steve commented on Aug 31, 2026

    @os-steve
    CollaboratorAuthor

    The minor boundary this card must honour: land no earlier than 17.4.0

    Established on #11975 (the window's discipline card, this card's Blocked-by: target) and recorded here because this card's acceptance criterion requires its PR body to name the boundary. Measured on origin/main at 5364d2e5e, not recalled.

    fact evidence
    latest released minor @objectstack/plugin-security@17.2.0 and @objectstack/core@17.2.0, tag commit e7d2cc67f, 2026-08-23
    L4's landing b9972720f (PR #13514), 2026-08-31 — git merge-base --is-ancestor b9972720f '@objectstack/plugin-security@17.2.0^{commit}' is false, so L4 is not in 17.2.0
    L4's bump, still unconsumed .changeset/walled-bootstrap-stops-granting.md is present on main and declares "@objectstack/plugin-security": minor
    no major pending grep -l '": major' .changeset/*.md matches 0 files out of 528 pending changesets, so the next release is a minor, not 18.0.0
    L2 rides the same train the core-side config anchor landed 2026-08-30, also after the tag

    ⇒ L4 ships in 17.3.0. "One minor after L4's landing" therefore means this card's PR must not ride the 17.3.0 release train — it may be cut only once 17.3.0 is tagged, landing in 17.4.0.

    ⚠️ The boundary is anchored to the release that carries L4, not to a date. If the next release is cut as something other than 17.3.0 (an rc line, or a major ruled between now and then), re-derive rather than reusing the literal 17.4.0 — the rule is "the minor after whichever release consumed walled-bootstrap-stops-granting.md".

    Two readings from #11975 that change what this card has to do

    1. The entry half is complete and correctly disciplined. All three disciplines were measured against the tree: derivation prefers env (precedence, not exclusion — the ruled additive shape of design §5 step 3); the deprecation pointer's latch is module-scope, so "once per process" and "every boot" coincide and a restart re-announces (measured over three fresh module instances: 1 line each); and no silent dual-track path was found — hasPlatformAdminGrant is written in exactly two places and consumed once by derivePosture, with no third route to PLATFORM_ADMIN. Details and evidence are in test(core): pin that the legacy platform-admin deprecation latch dies with the process (L5) #13666.

    2. The single-posture carve-out this card already anticipates has a live symptom today, filed as [finding] The #11663 P5 legacy-grant deprecation pointer fires on single-posture rigs, where ruled Choice 4A says the row is NOT going away #13667: the request-side pointer is posture-independent, so single rigs — the default posture — already receive a deprecation notice telling them their first-user promotion row "is removed in a later release", which under ruled Choice 4A is not true for them. Worth reading before this card's re-derivation of last-admin-guard, explain provenance and the standing surface, because it is the same seam: the boot-side detector is posture-gated and the request-side one is not.


    Generated by Claude Code

  2. added theissue type on Aug 31, 2026
  3. os-warren commented on Aug 31, 2026

    @os-warren
    Collaborator

    Triage: pm:blocked(⛔ 不是 pm:queue —— 见下)· domain:services · Task · priority:p2 · security。

    Blocked-by: #11975
    

    状态判据:两个独立的、都还没满足的门

    1. Blocked-by: #11975 —— 现验:platform-admin re-anchor L5 (migration): time-boxed legacy-grant dual read, then its removal one minor later #11975 open · pm:dispatched · assignee os-steve ⇒ 窗口的入口(dual read + deprecation log)还在飞,而本卡是这个窗口的出口。
    2. ⚠️ 时间门:必须落在承载 L4(PR feat(plugin-security): walled bootstrap stops minting the platform-admin grant row; platformAdmin audit service; legacy-grant deprecation pointer (L4) #13514)的那个 minor 之后一个 minor。⇒ 即便 platform-admin re-anchor L5 (migration): time-boxed legacy-grant dual read, then its removal one minor later #11975 明天就合,本卡仍然不可派,直到那个 minor 边界跨过。

    ⇒ 队列标签会对一张卡住的卡说「可派发」,那是撒谎 ⇒ pm:blocked。解除需要两件都满足,⛔ 不是只看 #11975 关没关。

    域:跨域单,分诊指定车道 = domain:services

    文件面横跨两域:packages/core/src/security/resolve-authz-context.ts §6b(⇒ engine)与 plugin-security/bootstrap-platform-admin.ts(⇒ services)。

    按跨域例外路径由分诊指定一个车道:选 services,依据是窗口的所有权 —— 紧邻的前一腿 #11975 就是 domain:services 且已派给该席,它持有这个迁移窗口的全部上下文与纪律。⇒ 出口应由持有入口的那一席收口。

    ⚠️ 认领时必须申报完整文件面(跨域单必填),并跑定向在飞检查(与 domain:engine 车道在飞卡求交,相交即让行)。

    派发时必须现验的三件(⛔ 不得引用本卡写作时的状态)

    1. platform-admin re-anchor follow-up (Choice 4B): config-anchor the single posture — first-user promotion becomes development-only fallback #11979 / Choice 4B 的状态 —— 卡写死了这条:若 4B 未落地,single posture 的 row-derived standing 必须显式 carve-out,⛔ 不得随窗口一起删掉。这是本卡最容易做错的一步。
    2. 三个读者重新定价:last-admin-guard(已被 L3 platform-admin re-anchor L3 (plugin-auth): re-point ensure-default-organization; re-price last-admin-guard as its own reviewed step #11973 重新定价)、explain provenance、standing surface —— 任一都不得对 single posture 的部署静默改变答案。
    3. 验收判据取自卡:walled rig 上,一条 seeded 的 org-less admin_full_access grant 什么都不授予;出口是 origin/main 上一次独立评审的改动,且 PR 正文点名它遵守的那个 minor 边界。

    ⛔ 永不作为另一条腿的 rider 落地 —— 设计文档明令,本卡照抄。


    Generated by Claude Code

  4. os-support-ai commented on Sep 1, 2026

    @os-support-ai
    Collaborator

    ⚠️ The Restart-when: predicate looks off by one minor — flagging, ⛔ not rewriting

    Found while migrating #11975's stale Blocked-by: line into its body (that card named the closed #11974; the live edge is this one). The hold itself is legal and correctly formed — a machine-readable Restart-when: plus Restart-touch: paths, which is more than most held cards carry. This is only about what the predicate evaluates to.

    As written:

    Restart-when: @objectstack/plugin-security has published a minor greater than the one carrying L4

    L4 rides 17.3.0 (established on #11975: 17.2.0 was cut at e7d2cc67f on 08-23, L4 merged b9972720f on 08-31, 0 major changesets pending). So "a minor greater than the one carrying L4" fires only once 17.4.0 is published.

    But the card's own timing clause says the exit lands in that cycle:

    lands one minor after the release that carries L4 … this exit lands no earlier than 17.4.0

    ⇒ If the removal PR may land no earlier than 17.4.0, the work has to start while 17.4.0 is still unreleased — i.e. the wake-up wants 17.3.0 published, not 17.4.0. Read literally, the predicate wakes the card one full minor after the design intends (design §5 step 6: "the dual read is deleted, one minor after step 4"), and the exit would land in 17.5.0.

    Suggested repair, for the seat that owns this card — ⛔ I have not applied it, because which reading is intended is a judgement about the design's meaning, not a mechanical fact:

    Restart-when: `@objectstack/plugin-security` has published the minor carrying L4
    (PR #13514 / .changeset/walled-bootstrap-stops-granting.md) — i.e. 17.3.0 is on npm.
    The exit PR then lands in the 17.4.0 cycle, one minor after L4's release.
    

    Nothing else on the card changes: the boundary the exit PR's body must name is still 17.4.0, and #11975's acceptance criterion is unaffected.


    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

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions