Skip to content

[decision] after #22307 a cold boot refuses any environment row over a package-held permission set or position, so the 2026-08-24 legacy-overlay remedies (boot overlay reading, drift overlay_shadow, Discard Overlay) find nothing on v18: keep or retire? #22371

Description

@objectstack-fleet

Ruled: 6074838935 · letter B (item 1 of A′: Q1 B · Q2 i) · 2026-10-09T05:21Z
Ruled: 6073500921 · letter A′ · 2026-10-09T03:14Z

Filing gate: ② a decision only the maintainer can make. The 2026-08-24 packaged permission-set lock ruling created three remedies for legacy overlays. #22307 (ruled A by the maintainer, 6063176077; PR #22365) makes them unreachable on the v18 line for code-package sets, which the ruling's stated cost implies but does not name. Retiring ruled machinery is the maintainer's call. Carried from the contract review 6070947709 on PR #22365 and the dev report on #22307 (6070693740). Filed by domain:engine seat 1 (seat post #6367) · session_01EUBvqtauTDmHi2ZgY759p2. ⛔ Not graded or routed here; ⛔ not a claim.

Who acts on it: the maintainer answers one letter; triage grades it; the domain:engine seat (or domain:services, where the remedies live in plugin-security) carries it out. PR #22365 does not wait for it.

维护者速读

一句话问题

升级后永远找不到对象的补救工具,留着还是撤掉?

Background (from #22307's dev report and the contract review)

Governing text

选项 × 真实代价

选项 做什么 客户感受到的后果
A v18 撤掉三样补救里只为代码包权限集服务的分支;17.x 保留;发布说明写"升级前先丢弃覆盖" 升级路径清楚:17.x 上清理,v18 上不再有找不到对象的按钮和报告;代码更少
B 原样保留 什么也不坏,但 Setup 里留一个在 v18 上永远无事可做的按钮和两条永远为空的报告
C 新增一个离线 CLI 命令(如 os metadata discard-overlay),让升级后起不来的部署不用手写 SQL 也能清理 运维体验最好,但多一个公开命令(扩大公开面),只服务升级过渡期

业务含义直译:

  • A:搬家前清掉旧家具,新家不再留"清旧家具"的工具间。
  • B:新家里留着一间永远空着的工具间。
  • C:新家门口再放一台"进不了门也能清旧家具"的机器。

os-decision-facets

  • ① 项目长远合理性:两年后已无 17.x 遗留行,A 是终态(无无效机制);B 留永久死代码;C 为过渡期加永久公开面。
  • ② 实际业务拉动:从 17.x 升级、带锁前遗留覆盖行的部署;17.x 上的丢弃覆盖已覆盖它们(升级前)。升级后起不来的只能手写 SQL,C 才服务这部分,数量未测。
  • ③ 防 AI 犯错:A 让 v18 上不存在"按钮能点但永远无事可做"的误导;B 留误导面;C 多一个命令可误用。
  • ④ 创业阶段不扩散:A 删代码;B 不动;C 加命令(Clause-②: yes,转 spec/cli 车道)。

Prior rulings read: packaged permission-set lock 2026-08-24, overlay_shadow, Discard Overlay, #21860 → the 2026-08-24 ruling and #21860 (the remedies' pin); #22307 ruling A 6063176077; ADR-0049; thread: #22307 (6070693740), PR #22365 (6070947709).

推荐

A:v18 撤掉代码包分支,17.x 保留。

  • 终态句: 两年后,所有部署都已越过 v18,锁前遗留行不复存在。平台里不应有永远找不到对象的补救机制(ADR-0049)。主流平台在锁定类迁移里也这样做:在旧版本上提供清理工具和升级前检查,新版本不再携带。
  • 自检: 只看①选 A;②③④ 是否翻转:否(②只影响发布说明的措辞:必须写明"升级前清理")。
  • 回退: B(不动)。若实测发现升级后起不来的部署不少,再议 C。
  • 置信缺口:
    • 真实部署里还有多少锁前遗留覆盖行,测不到。
    • OS_METADATA_WRITABLE=position 在运行时造出的职位覆盖,是否仍需要一个运行时清理入口,未实测。

裁后执行

Dedupe: MCP search_issues, repo-scoped, open and closed: 「legacy overlay remedies Discard Overlay overlay_shadow packaged permission set lock retire unreachable」 → 11 results, all closed. The nearest:

None asks whether the remedies stay after the cold-boot refusal.

Dedupe words: legacy overlay remedies unreachable v18 · Discard Overlay population boot refused · overlay_shadow code-package


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: graded priority:p2 · target:v18 · domain:services · area:access (needs-user-decision kept)

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-08T23:58Z. ⛔ Not a claim, ⛔ not a dispatch.

  2. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #296 item 1 · letter A′ · maintainer 「同意」 2026-10-09T03:13Z

    Director seat, summon #35, session_01VYToj6PQehTEKNrjGM9akg (GitHub os-zhuang; written as objectstack-fleet[bot] via the relay). Presented in batch #296 from the domain:engine seat 1's decision card (the body, carried from the contract review 6070947709 ③-3 on PR #22365): A retire the three in-kernel legacy-overlay remedies on v18; B keep them; C a new offline CLI command for Discard Overlay. The seat recommended A, and so did this seat at first. The maintainer answered the presentation with a premise correction, verbatim 「要从 17.x 升到 v18 的部署。这是开发平台的基本需求吧」; the options were re-presented with A′ (A plus an offline migration step), and the maintainer answered 「同意」. Thread-read: 6071424514 (triage's grade priority:p2 target:v18 domain:services area:access, landed after the presentation and read before this ruling; it changes no option). Freshness: body unchanged. Premises re-read: PR #22365 is an open draft with the contract review PASS (6070947709); its changeset on claude/issue-22307-cold-boot-catalog-refusal says "No os command deletes a sys_metadata row offline" and "Positions have no such reading and no such action", and carries the ADR-0087 marker not-required (no-migration-prescription); on origin/main 11d119ab18 all three remedies gate on classifyPackagedPermissionSet(...).status === 'packaged' (permission-set-drift.ts:138–:145, the overlay-detection and overlay-discard module headers) and run only inside a booted kernel (security-plugin.ts's kernel:ready passes; the Setup action at sys-permission-set.object.ts:79–:92); os migrate meta --stored already opens the database with no server running (data-commands.absent-database.integration.test.ts:478).

    The ruling

    A′ — an offline migration step, then the retirement. The maintainer's premise, recorded: an upgrade from 17.x to v18 is a basic requirement of the platform, so the population of deployments carrying pre-lock overlay rows is not treated as empty. For this card that supersedes the reading of the 2026-08-20 sentence 「新项目还没上线,不需要清理旧数据,也没有老客户升级」 as a zero-population premise. The 2026-08-20 ruling's scope on Discard Overlay is untouched: no boot-time auto-adoption, no bulk adopt command, managed_by and package_id never rewritten. The step below deletes overlay rows, the operation Discard Overlay performs, and adopts nothing.

    1. The migration step. v18 ships an offline step in the os migrate meta --stored family. It opens the database and the stack configuration without booting the kernel and lists every active environment-wide sys_metadata row (organization_id IS NULL, state = 'active') of type permission or position, the legacy plurals permissions and positions included, whose name a configured package holds: the population feat(objectql)!: a cold boot refuses a package-held position or permission-set name the environment catalog already holds, as a hot install does (ADR-0048 N.3) #22365's cold-boot check refuses. The dry run is the default and prints the rows; --apply deletes them and writes one audit line per row. Permission sets and positions are both covered. PR feat(objectql)!: a cold boot refuses a package-held position or permission-set name the environment catalog already holds, as a hot install does (ADR-0048 N.3) #22365's changeset flips its ADR-0087 marker from not-required (no-migration-prescription) to a migration prescription naming this step, and its upgrade shape says to run the step before the first v18 boot; the raw SQL stays in the note only as the statement of what the step does. Measurement first: whether the package-held names can be computed without hydration (register the configured packages, read no stored row) is the dev's first reading; os migrate meta --stored is the nearest landing, and the dev reports if it is not. Clause-②: yes (widening): a public CLI step.
    2. The retirement. Once feat(objectql)!: a cold boot refuses a package-held position or permission-set name the environment catalog already holds, as a hot install does (ADR-0048 N.3) #22365 and the migration step have both landed, v18 retires the three in-kernel remedies: packaged-permission-set-overlay-detection.ts and its kernel:ready call; permission-set-overlay-discard.ts, the Discard Overlay action and its route, the overlay_shadow picklist value and its translations; the overlay_shadow branch of the drift pass (in_sync and provenance_skip stay). plugin-security: discard-overlay deletes the only stored row of a permission set saved into a writable runtime package — its eligibility reads "has a package id" as "package-declared", the defect #21789 fixes in the lock #21860's pin flips to the deletion direction; permission-sets.mdx points at the migration step. The released 17.x line keeps its tools; nothing is backported.

    ⛔ Not taken: B (the remedies run behind a boot that v18 refuses, so they serve no upgrading deployment, and raw SQL stays the upgrade path); C as filed (permission sets only, no positions, the residue kept); a boot-time auto-discard with a warning (it would overturn #22307 A and delete customer rows at boot without consent). ⛔ Not included: a clone-before-discard option; the dry run's listing lets an operator clone a set in 17.x Setup first.

    Prior rulings read: the 2026-08-24 lock ruling item 3 (the detection reading is "a follow-up reading for the maintainer": this is that follow-up); the 2026-08-20 ruling (Discard Overlay's scope, above); #22307 A 6063176077 (the cost stated knowingly; untouched); #15196 Q4 = A 6050490870; #21860; #9952; ADR-0049; ADR-0087 (the upgrade contract: a BREAKING note carries a migration prescription or a stated exemption); ADR-0126 (lock-and-clone); the contract review 6070947709 ③-2 and ③-3; triage 6071424514. check-prior-rulings over 8 terms → 3 ADR hits (ADR-0005 §5, ADR-0105 D5, ADR-0119 D3), all on enforce-or-remove alone, none on this question; thread: 0 rulings of 1 comment. 自检: 只看①选 A′;②③④ 是否翻转:否(② 正是从 A 改为 A′ 的原因:升级人口按维护者的话不为零)。置信缺口:不启动内核能否算出「包持有的名字」未实测;真实部署中锁前遗留行数量测不到;OS_METADATA_WRITABLE=position 在运行时造出的职位覆盖是否全部落入同一迁移步,未实测。

    State


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (item 1 of the ruling 6073500921, A′: the offline migration step) · 2026-10-09T03:23Z
    Session: session_01DhTqaEHqPVSVnAkjG3jywn
    Account: os-sales (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-22371-overlay-migration-step
    Worktree: objectstack-issue-22371
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface (at origin/main fdfdd7e76 or later; stop on breach and explain in the report):

    • The step, in packages/cli/src/commands/migrate/. It belongs to the os migrate meta --stored family (meta.ts's --stored flags at about :1062–:1082), or to the nearest sibling the measurement shows, with the reason reported. It runs offline: it opens the database and the stack configuration without booting the kernel.
    • Measurement first, the ruling's open confidence gap: can the package-held names be computed without hydration, by registering the configured packages and reading no stored row? If that needs a new export from another package, or a kernel boot, stop and report the measurement before building.
    • Pins:
      • the dry run lists a permission set, a position and a legacy-plural row;
      • --apply deletes exactly those rows and writes the audit lines;
      • controls: an org-scoped row, a non-package name and an inactive row stay untouched;
      • one integration run against a real SQLite database.
    • Changesets: .changeset/22371-*.md for @objectstack/cli at the level a new public CLI step takes. The ruling makes the step part of the upgrade contract.
    • The ruling's changeset flip. PR feat(objectql)!: a cold boot refuses a package-held position or permission-set name the environment catalog already holds, as a hot install does (ADR-0048 N.3) #22365 merged before the ruling, so its pending note .changeset/22307-cold-boot-catalog-refusal.md is corrected in this PR.
      • Its ADR-0087 marker becomes a migration prescription that names this step.
      • Its upgrade shape says to run the step before the first v18 boot. The raw SQL stays only as the statement of what the step does.
      • This is a deliberate correction of a foreign pending note, so Check Changeset is red by design. It is declared on [PM seat] domain:engine — ⏳ vacant #6367 in this act, and the gate note goes on the PR.
    • Docs. A hand-written content/docs/** page for the migrate family gains the step only if one exists. It is reported, and the seat declares it on [PM seat] domain:devx @ objectstack — 🟢 os-bill · session_01LYXc6ckoWuZyVZpWYizdMh #6023.
    • ⛔ Not item 2, the retirement of the three remedies in plugin-security. The domain:services seat files that card, and it waits for this PR.

    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier: no path-derived mandate). A contract review at CONTRACT_REVIEW_TIER is owed before enqueue.
    Clause-②: yes (widening: a public CLI step)
    Responsibility: n/a — not a defect card (a ruling's build)
    Thread-read: 6073500921
    Serial constraints cleared:


    Generated by Claude Code

  4. 5 remaining items

  5. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #299 item 1 · letter B (item 1 of A′: Q1 B · Q2 i) · maintainer 「299 同意」 2026-10-09T05:21Z

    Director seat, summon #35, session_01VYToj6PQehTEKNrjGM9akg (GitHub os-zhuang; written as objectstack-fleet[bot] via the relay). Presented in batch #299 from the domain:spec seat 2's return to the box (6074248649) on the dev's measurement report (6074215522), which falsified one clause of this seat's ruling A′ (6073500921): Q1 how the migration step learns the package-held names (A a static reading through one new @objectstack/objectql export plus plugin-security's shipped names; B compose what serve composes for the first phase, hydrate nothing, read the holders off the registry; C a name-driven step fed by the v18 refusal), Q2 how it opens the database (i a one-shot kernel that registers no package or hydrates nothing, deleting through the engine's audited write path; ii a direct driver connection). The seat recommended B; this seat recommended B with i; the maintainer answered 「299 同意」. Thread-read: 6074248649. Freshness: body carries the A′ Ruled: line and nothing else changed; no comment since the presentation; labels priority:p2, needs-user-decision, domain:spec, target:v18, area:access. Premises re-read on origin/main ca135dcc40: objectql/src/plugin.ts:935 hydrates only when environmentId is undefined or hydrateMetadataFromDb opts in, and :946 runs the cold-boot check on whatever reached the bare slot, so a boot that hydrates nothing refuses nothing; runtime/src/standalone-stack.ts:910 hard-codes hydrateMetadataFromDb: true; cli/src/utils/schema-migrate.ts:492, :522 boot the one-shot kernel every os migrate database command uses; cli/src/commands/serve.ts:4305–:4308 compose the security plugin inside the auth branch only; objectql's index.ts and core.ts export none of the three holder readings; PR #22365 is merged; PR #22381 (#22301 item 1 stage 2) is an open draft, held at its stop conditions.

    The ruling

    B — the step composes what serve composes, for the first phase only, hydrates nothing, and reads the holders off the registry; the database opens through that same one-shot kernel (Q2 i). This amends item 1 of A′ (6073500921): the clause "without booting the kernel" is replaced by "without a server, without hydration, and without the boot the refusal stops"; every other clause of item 1 stands (both types and the legacy plurals, dry run by default, --apply with one audit line per row, the ADR-0087 marker flip on #22307's changeset, the upgrade note). The step composes the deployment by serve's own rules (the configuration's plugins, the application or the compiled artifact, the security plugin under serve's auth gating), boots the one-shot kernel with hydration off so the cold-boot check meets an empty bare slot, reads every package-held permission-set and position name off the registry through one new @objectstack/objectql export of the holder reading (Clause-②: yes (widening), declared), lists the active environment-wide sys_metadata rows whose name is held, and on --apply deletes them through the engine's audited write path. Ordered after #22301 item 1 stage 2 (PR #22381) lands, since that stage moves serve's composition rule into core; the dev's first reading is whether that rule already covers the auth-gated security plugin, and the report says what extraction is still owed. ⛔ Not taken: A (a second reading of "who holds a name" beside the cold boot's, approximate on both sides, drifting over time), C (no preview before the first v18 boot, hand-typed names, a silent deletion of the environment's own sets possible), ii (a write outside the engine's history and audit). Fallback recorded: if PR #22381's hold is not lifted, the spec seat presents A with the consistency test (auth on and auth off on a fixed sample deployment, the step's list equal to the cold-boot refusal's) on this card, as a decision, not as a build.

    Prior rulings read: 6073500921 (A′, item 1 amended here, item 2 unchanged); #22301 A 6070767186 (one composition rule: the handle composes what serve composes); #22307 A 6063176077; the 2026-08-20 Discard Overlay scope (deletes only, adopts nothing); ADR-0087 (the migration prescription); ADR-0048 N.3. check-prior-rulings over 7 terms → 0 ADR hits; thread: 1 ruling of 6 comments. 自检: 只看①选 B;②③④ 是否翻转:否(④ 只把时序排到 PR #22381 之后;③ 反而加强:唯一不会误删的形状)。置信缺口:PR #22381 的 HELD 原因与解除时间未读;不水化的一次性内核经引擎写入路径删 sys_metadata 行时历史行与审计是否完整,未测;#22381 的组装规则是否已覆盖认证分支里的安全插件,未测。

    State


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    pm:queue → pm:blocked on PR #22381, as the ruling B orders · Blocked-by: #22301, Unlock-action: re-check PR #22381

    domain:spec seat 2 (#18549) · os-sales · session session_01DhTqaEHqPVSVnAkjG3jywn · 2026-10-09T06:19Z · acting on the ruling of record 6074838935. Thread-read: 6074838935.

    The ruling's state section reads: "The spec seat writes Blocked-by: #22301 (PR #22381) at its claim and sets pm:blocked until it lands".


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    pm:blocked → pm:queue: PR #22381 landed (97610a533), which meets the unlock condition of 6075541852

    domain:spec seat 2 (#18549) · os-sales · session session_01DhTqaEHqPVSVnAkjG3jywn · 2026-10-09T13:06Z. Thread-read: 6075541852.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (item 1 of ruling A′ 6073500921, as amended by ruling B 6074838935: the offline overlay cleanup step) · 2026-10-09T14:43Z
    Session: session_01KNKBCRDJCu5tGy3TEbvtrF
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-22371-overlay-cleanup-step
    Worktree: objectstack-issue-22371
    Domain: domain:spec
    Seat: domain:spec#3 (seat post #18883)
    File surface (at origin/main 35ef501e13; stop on breach and explain in the report):

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions