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 — 🟢 os-project-manager #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 — ⏳ vacant #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. 16 remaining items

  5. 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):

  6. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22371,
      "status": "done",
      "branch": "claude/issue-22371-overlay-cleanup-step",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/22523",
      "session": "session_01KNKBCRDJCu5tGy3TEbvtrF (subagent run under the domain:spec seat 3 dispatch; the parent session id)",
      "premise_still_valid": true,
      "summary": "Built item 1 of ruling A′ as amended by ruling B: `os migrate security-catalog-overlays` (preview by default, `--apply`, `--yes`, `--force`, `--json`, `--database-url`). It composes what `os serve` composes for phase 1: the existing composeHostStack declaration boot, plus the security plugin behind serve's auth gate. It boots with sys_metadata hydration off and reads the package holders off the registry through ONE new objectql export, `findPackageHeldSecurityCatalogNames`; the cold-boot check now computes its conflicts from the same private reading. It lists the active env-wide permission/position rows (legacy plurals included) over held names. `--apply` deletes canonical rows through protocol.deleteMetaItem (a history tombstone and a sys_metadata_audit row) and legacy-plural rows through the SysMetadataRepository beneath it (the same tombstone), with one audit line per row. FIRST READING (premise 3): materializeStackPlugin does NOT cover the auth-gated security plugin. Extraction done: packages/core/src/stack-auth.ts (resolvePlatformAuthComposition, resolveStackTiers, resolveAuthSecret, plus the predicates and the tier constants); serve.ts now asks it, keeping its gate line and composing exactly what it did. Still owed: no `--preset` / `--dev` in the step (the default preset and NODE_ENV are read); AuthPlugin, organizations and audit stay serve-only (none holds a catalog name, measured); verify's harness composes auth and security ungated (#22301 territory). The refusal message now names the step. The 22307 changeset's marker flips to `registered security-catalog-environment-overlay-refused` (a new D3 semantic entry in packages/spec, a declared deviation), and its upgrade shape, after-upgrade bullets and 'no os command deletes offline' sentence are rewritten.",
      "tests": "Pre-merge at 5a5cb1057, each exit captured before any pipe, under os-verify-lock: closure build 59/59 exit 0; core typecheck 0 and test 87 files / 2276; objectql typecheck 0 and test 391 / 7718; runtime typecheck 0 and test 345 / 4878 (+19 skipped); spec src/migrations 3 / 200; cli typecheck 0 (incl. check:test-typecheck); cli unit tier 274 files: 1 red, test/normalized-call-sites.test.ts flagging the new `stack.requires` read in schema-migrate.ts (the createStandaloneStack result, already resolved over package bodies), classified as a top-level row, re-run 11/11 at 02812be5eb; cli integration (the 4 touched files: the new pin, one-shot-family, host-composition, requires-providers) 4 / 103. Post-merge of origin/main 446c8b2a6 at ed5af305c8: whole-workspace build 72/72 exit 0; core/objectql/runtime/cli typecheck 0; core test 88 / 2288; runtime test 345 / 4878; 7 touched cli unit files 186/186; the 4 integration files 103/103. THE PIN (security-catalog-overlays.integration.test.ts, in-process oclif over one SQLite database and one compiled artifact): with auth off the preview lists permission, position and positions (legacy plural); with auth on it adds permissions/member_default held by com.objectstack.plugin-security. Controls never listed: an env-wide unheld name, an org-scoped row, a draft row. In both postures list == the cold-boot refusal's conflicts[] (the same composition booted with hydration on); the preview writes nothing and exits 1. `--apply` (auth on) deletes exactly the 4 rows with the controls kept, writes 4 history tombstones and 2 sys_metadata_audit rows, then the cold boot comes up and a second preview lists 0 and exits 0; `--apply` with auth off leaves member_default alone. ABLATION (scripts/ablation-replace.mjs, not committed): composeAuthGatedSecurity true to false in the command, anchor 1 to 0, blob a484cc0a4 to 92908a4cb; the pin went red 3 of 4 (auth-on apply listed 3 against the boot's 4 with member_default missing; both previews lost securityPlugin); restore blob a484cc0a4, git diff HEAD 0 bytes. PUBLIC DOOR, measured by hand with built bin/run.js and NODE_ENV=production on one fixture database: os serve with no OS_AUTH_SECRET exit 1, 3 names refused; with it exit 1, 4 names (+member_default, plugin-security); the step's --json listed exactly those 3 and those 4 (securityPlugin no-secret / composed). After --apply with auth on (2 rows via protocol.deleteMetaItem, 2 via sys-metadata-repository), os serve with auth on, on the same database, printed 'Server is ready' (stopped by its own timeout, port confirmed free). PREMISE 5 (scratch, not committed): deleteMetaItem's sys_metadata_history and sys_metadata_audit rows from a non-hydrated kernel and from a hydrated one were column-identical bar ids and timestamps; receipts identical. The mutation projector does not run in the step's kernel because the security plugin's start() is suppressed (composition, not hydration). LINT: eslint --no-inline-config --format json over the 18 changed .ts files gave 18 file results, 0 errors, 0 warnings, 0 ignored; population read from eslint.config.mjs (none ignored); invariance: type-aware linting is never enabled (eslint.config.mjs lines 326-328), so no untouched file's verdict can move.",
      "mcp_calls": "0",
      "api_writes": "3 REST writes, all through the fleet-write relay (each is one POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]): (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls (draft) giving #22523, body read back identical at 14763 bytes; (2) label-write --assign, POST /repos/objectstack-ai/objectstack/issues/22523/assignees zhuangjianguo, read back matched; (3) this report, POST /repos/objectstack-ai/objectstack/issues/22371/comments via scripts/pm/post-stamped.mjs. Not REST: git push of the branch (the empty probe first, then 9 pushes), and one git fetch --shallow-since=2026-07-04 to deepen for check-engine-split-ratio.",
      "open_questions": [
        {
          "question": "The ruling's marker flip on .changeset/22307-cold-boot-catalog-refusal.md needs a registry entry: the ADR-0087 closed vocabulary admits a migration prescription only as `registered ID`. So this PR adds a D3 semantic entry in packages/spec (18.security-catalog-environment-overlay-refused.ts and its generated registry.ts region), which is outside the claim's declared file surface. Measured: the gate's own findMigrationPrescription returns null for both the base body and the rewritten one, so the old `not-required (no-migration-prescription)` marker would still pass mechanically. Keep the registration?",
          "options": [
            "A. Keep it (as shipped). The upgrade contract carries the prescription in the ledger os migrate meta --from 17 reads, and the guide will project it at protocol 18. Cost: 2 spec files outside the declared surface (the seat's home lane), and a registry.ts region a concurrent spec registration can conflict with.",
            "B. Drop the spec entry and keep the old marker beside the rewritten body. Mechanically green. Cost: the ruling's 'flips its ADR-0087 marker ... to a migration prescription naming this step' goes unexecuted, and the prescription lives in prose only."
          ],
          "recommendation": "A. Long-term soundness: the ledger is where ADR-0087 says an upgrader learns a manual step, and the entry's replacement names the step. Guarding against AI mistakes: a prescription in prose under a marker that says 'no prescription' is the self-contradiction the gate exists to refuse; the detector misses it only by spelling. Real business need: the upgrade population is non-zero by the maintainer's word. No sprawl at the startup stage: one data file and one generated region, no new gate."
        }
      ],
      "out_of_scope_findings": [
        "carrier: item 2's card (domain:services, which already points permission-sets.mdx at the step), or a docs follow-up. content/docs/deployment/cli.mdx's 'Data migrations' table and its 'If the database is in use' table should each gain a row for os migrate security-catalog-overlays; docs were outside this claim's surface. Noted in the PR's Acceptance notes, not filed.",
        "carrier: none (承接者:无). A canonical row whose package item declares _lock full or no-delete is refused by deleteMetaItem's lock gate (ITEM_LOCKED). The step reports the row as failed and exits 1, and the changeset's SQL stays the statement of what to delete. No shipped package declares such a lock on a permission set or position, so this was not measured. Noted, not filed."
      ],
      "gates": "At ed5af305c8, dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 100. 99 exit 0. node scripts/check-empty-changeset.mjs --base origin/main exits 1, red by design: a deliberate correction of the pending note .changeset/22307-cold-boot-catalog-refusal.md, stated on the PR for confirmation. Verdict line: '✓ dispatch-gates --ran: 100 derived famil(ies) accounted for — 100 run, 0 NOT-MEASURED (a DERIVED zero — all 100 recorded an exit code and none of them is 3).' Artifact rosters (the coordinator's addendum): 49 commands, all exit 0. 46 ran plain, check:error-code-provenance among them (exit 0: the step stamps no registered error code, so no owner-key row is owed). check-partof-closing-keyword.mjs exits 0 with PR_BODY; check-closing-target-claim.mjs and check-single-claim-paths.mjs exit 0 with PR_NUMBER=22523. Earlier runs, superseded at ed5af305c8: check-engine-split-ratio exit 2 (shallow clone), green after git fetch --shallow-since; check:dts-closure exit 1 (raced the battery's own spec rebuild), green re-run; check:dual-build-cjs-loads, check:i18n and check:i18n-coverage exit 3 (no whole-workspace dist), all green after the full build. Also run: node scripts/check-cli-command-ids.mjs, exit 0.",
      "line_budget": "+1782 -65 = 1847 changed lines, 20 files (GET pulls/22523: additions 1782, deletions 65, changed_files 20), against merge base 446c8b2a6. This includes the generated registry.ts region (+42). Under the 3,000 human-merge threshold.",
      "deviations": [
        "packages/spec (2 files: the new semantic entry and its generated region in src/migrations/registry.ts) is outside the claim's declared file surface. It is the spec seat's home lane, and it is required by the closed ADR-0087 vocabulary for the ruled marker flip. See open_questions; spec-changes.json and the upgrade guide do not move before protocol 18.",
        "The cold-boot NAMESPACE_CONFLICT message in packages/objectql/src/registry.ts now names the step as the remedy for the environment's rows, in place of the metadata-API-or-database sentence. The envelope is unchanged and no test pins the old text.",
        "packages/cli/test/normalized-call-sites.test.ts gains one top-level row for schema-migrate.ts's `stack.requires` read. That read is the standalone stack's result, already resolved over package bodies.",
        "serve.ts keeps its literal gate line `if (!hasAuthPlugin && tierEnabled('auth'))`, now built from core's predicate and tier set; the host-kernel and no-secret branches read the core rule's answer. Kept so the two contract pins anchored on that line stay as they are.",
        "The step has no --preset and no --dev; it reads the default preset and NODE_ENV and prints the gate's answer.",
        "Merged origin/main 446c8b2a6 (which touched core, runtime and plugin-security) before opening the PR, and re-verified at ed5af305c8.",
        "Docs not edited: cli.mdx (see out_of_scope_findings).",
        "The premise-5 trail comparison and the ablation ran as one-off scratch steps, not committed."
      ],
      "files_changed": [
        ".changeset/22307-cold-boot-catalog-refusal.md",
        ".changeset/22371-security-catalog-overlays-step.md",
        "packages/cli/src/commands/migrate/security-catalog-overlays.integration.test.ts",
        "packages/cli/src/commands/migrate/security-catalog-overlays.ts",
        "packages/cli/src/commands/serve.ts",
        "packages/cli/src/utils/schema-migrate.one-shot-family.integration.test.ts",
        "packages/cli/src/utils/schema-migrate.ts",
        "packages/cli/src/utils/schema-migration-plugins.ts",
        "packages/cli/src/utils/security-catalog-overlays.ts",
        "packages/cli/test/normalized-call-sites.test.ts",
        "packages/core/src/index.ts",
        "packages/core/src/stack-auth.test.ts",
        "packages/core/src/stack-auth.ts",
        "packages/objectql/src/index.ts",
        "packages/objectql/src/protocol-boot-hydration-scoped.test.ts",
        "packages/objectql/src/registry.ts",
        "packages/runtime/src/standalone-stack-hydrate-metadata.test.ts",
        "packages/runtime/src/standalone-stack.ts",
        "packages/spec/src/migrations/entries/semantic/18.security-catalog-environment-overlay-refused.ts",
        "packages/spec/src/migrations/registry.ts"
      ]
    }

    Generated by Claude Code

  7. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat review of PR #22523 at ed5af305c8: the build is accepted as built. One patch round: sync with protocol 18 and regenerate. Then the contract review, then landing

    domain:spec seat 3 (#18883) · zhuangjianguo · session session_01KNKBCRDJCu5tGy3TEbvtrF · 2026-10-09T18:03Z · holder of claim 6083206634. Report: os-dev-report 6086448551. Thread-read: 6086448551.

    Checked in the diff and on the head, not taken from the report (20 files, +1782 / −65 = 1,847 changed lines, under the 3,000-line threshold):

    • The step os migrate security-catalog-overlays (preview by default, --apply, --yes, --force, --json, --database-url).
      • It composes serve's phase 1, including the security plugin behind serve's auth gate, which is now shared through @objectstack/core's stack-auth.ts.
      • It boots with hydrateMetadataFromDb: false, a new option on createStandaloneStack whose default stays on.
      • It reads the holders through ONE new @objectstack/objectql export, findPackageHeldSecurityCatalogNames, which the cold-boot check now reads too. That is ruling B's "no second reading", met.
    • The ruling's first reading answered: materializeStackPlugin did not cover the auth-gated security plugin. The extraction to core is the one composition rule (verify: the in-process handle boots a leaner stack than serve and has no door for eight things an app's tests need (requires[] capabilities, system/predicate update, the form door, user-less triggers, …), measured by hotcrm#2013 #22301 ruling A), and serve composes what it did.
    • The changeset: @objectstack/cli, objectql, core and runtime all minor, Clause-②: yes (widening), with every new export named. core's export * from './stack-auth.js' follows the entry's existing form (42 such lines on main).
    • The cold-boot refusal now names the step; the envelope is unchanged and the runtime string carries no tracker number.
    • .changeset/22307-cold-boot-catalog-refusal.md is corrected: the marker, the upgrade shape, the after-upgrade bullets, and "No os command deletes …". The PR body declares that check-empty-changeset is red by design for it. The contract review on the patched head must name that note and judge each rewritten sentence; that record is the confirmation.
    • The pin and the public door (the report's readings, shape checked):
      • In both auth postures, the step's list equals the cold boot's conflicts[].
      • --apply deletes exactly the held rows and keeps the controls, and the cold boot then comes up.
      • The ablation leg reads red, and the restore is blob-equal.
      • Premise 5 is measured: the history and audit rows from a kernel that hydrated nothing match a hydrated kernel's.

    CI at ed5af305c8: 2 failures at this stamp.

    The open question, answered: A, the registration stays. The ruling orders the marker flipped "to a migration prescription naming this step". ADR-0087's closed vocabulary spells a prescription only as registered ID. The prescription belongs in the ledger an upgrader's os migrate meta --from 17 reads. The two packages/spec files are accepted as this seat's own lane.

    Patch round:

    1. Merge origin/main with bash scripts/pm/os-regen-merge.sh, then regenerate packages/spec/spec-changes.json and docs/protocol-upgrade-guide.md with their own generators. ⛔ Never gen:schema in the MERGE state.
      • check:spec-changes, check:upgrade-guide and check:generated must pass.
      • Then re-verify the touched packages on the merged head.
    2. Add the step's rows to content/docs/deployment/cli.mdx: the "Data migrations" table and the "If the database is in use" table. Item 2's card, the carrier the report named, is not filed yet, so the command ships with its own reference rows. This is a cross-lane domain:devx path, declared on its seat post.
    3. A pr_body_delta: one sentence on why the step is a sibling command in the os migrate family and not a mode of os migrate meta --stored. The ruling asked the dev to report it if meta --stored was not the nearest landing.

    Carried, not filed: a canonical row whose package item declares _lock full or no-delete is refused by deleteMetaItem's lock gate. The step reports it as failed, exits 1, and leaves the SQL as the fallback. No shipped package declares such a lock on a permission set or position, so there is no reach.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22371,
      "status": "done",
      "branch": "claude/issue-22371-overlay-cleanup-step",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/22523",
      "session": "session_01KNKBCRDJCu5tGy3TEbvtrF (subagent run under the domain:spec seat 3 dispatch; the parent session id)",
      "premise_still_valid": true,
      "summary": "Patch round on PR #22523, head ae87d67c8d (pushed; three commits on top of ed5af305c8). (1) 16e58dc320 merges origin/main da989bbb24 through scripts/pm/os-regen-merge.sh: no rebase, the merge committed before any regeneration, and gen:schema never run. (2) 7dc9788339 holds the regeneration alone. With protocol 18 on main (PR #22215), the D3 entry security-catalog-environment-overlay-refused now projects into packages/spec/spec-changes.json (+14, two records, additions only) and docs/protocol-upgrade-guide.md (+3). check:spec-changes, check:upgrade-guide, check:migration-registry and check:generated are all green. (3) ae87d67c8d adds the step's rows to content/docs/deployment/cli.mdx: one in the 'Data migrations' table and one in the 'If the database is in use' table (domain:devx; the seat declares it). Open question A is applied: the D3 registration and both packages/spec files stay. Check Changeset is left red by design for the declared 22307 correction.",
      "tests": "All at ae87d67c8d. Build of the whole workspace minus docs: 72/72, exit 0. spec check:generated exit 0: 'All 15 generated artifacts are up to date', measured against the packages/spec/dist this run built; check:spec-changes, check:upgrade-guide and check:migration-registry exit 0. Typecheck exit 0 for core, objectql, runtime and cli (cli includes check:test-typecheck). Tests: core 88 files / 2288; objectql 392 / 7739; runtime 345 / 4878 passed, 19 skipped; spec src/migrations 3 / 200; cli unit tier 275 / 4059; the 4 touched cli integration files (security-catalog-overlays.integration.test.ts, schema-migrate.one-shot-family, schema-migrate.host-composition, schema-migrate.requires-providers) 4 / 103. The seat note (18:55Z) arrived while this battery held the lock. These are the full core/objectql/runtime suites, not the narrowed minimum, so nothing is declared to CI as a narrowing. The cost is stated in deviations.",
      "mcp_calls": "0",
      "api_writes": "1 REST write this round: this report, POST /repos/objectstack-ai/objectstack/issues/22371/comments via scripts/pm/post-stamped.mjs (fleet-write relay, one POST /repos/objectstack-ai/objectstack/dispatches). PR body not patched, as ordered. Not REST: git push of 3 commits (16e58dc320, 7dc9788339, ae87d67c8d); the remote head is ae87d67c8d.",
      "pr_body_delta": {
        "why_a_sibling_not_a_mode": "`os migrate security-catalog-overlays` is a sibling in the `os migrate` family rather than a mode of `os migrate meta --stored` for three reasons. The two operations differ: `--stored --apply` rewrites every stored row through `saveMetaItem`, while the step deletes one refused population, and putting both under one `--apply` would give the flag a second, destructive meaning. The boots differ: `--stored` boots without the host config and hydrates `sys_metadata`, which is exactly the boot the cold-boot refusal stops over a compiled artifact, while the step needs serve's composition with the auth-gated security plugin and hydration off. The exit contracts differ: `--stored` exits 1 when rows remain uncanonical, and the step exits 1 when the next boot would be refused. As a sibling it keeps the family's conventions (preview by default, `--apply`/`--yes`/`--force`/`--json`/`--database-url`, the occupancy gate), and the refusal message names it directly.",
        "docs_rows": [
          "content/docs/deployment/cli.mdx, Data migrations table: | `os migrate security-catalog-overlays` | List the environment-wide permission-set and position rows (the legacy plurals `permissions` / `positions` included) stored over a name a configured package holds — the rows a v18 cold boot refuses — each with the package that holds its name; `--apply` deletes them, one history tombstone per row. Run it before the first v18 boot, with the environment the deployment boots with: the platform security plugin's sets are held only where `os serve` composes it (an auth secret set). Adopts nothing; exits 1 while it lists a row |",
          "content/docs/deployment/cli.mdx, If the database is in use table: | `os migrate security-catalog-overlays --apply` | **Refuses** likewise — it deletes `sys_metadata` rows, and a live process saving metadata is exactly the collision |"
        ],
        "verification_lines": [
          "Patch round, head `ae87d67c8d`: origin/main `da989bbb24` merged through `scripts/pm/os-regen-merge.sh` (`16e58dc320`). The protocol-18 regeneration is its own commit (`7dc9788339`): `spec-changes.json` +14 and `docs/protocol-upgrade-guide.md` +3, additions only. `check:spec-changes`, `check:upgrade-guide`, `check:migration-registry` and `check:generated` all exit 0, the last against a freshly built spec dist.",
          "At `ae87d67c8d`: the whole-workspace build passed (72/72). Typecheck exit 0 for core, objectql, runtime and cli. Tests: core 88 / 2288, objectql 392 / 7739, runtime 345 / 4878 (+19 skipped), spec migrations 3 / 200, cli unit 275 / 4059, and the 4 touched cli integration files 4 / 103.",
          "Gates at `ae87d67c8d`: 125 derived families, of which 124 exit 0 and `check-empty-changeset` is red by design (the declared 22307 correction). `--ran`: 125 derived, 125 run, 0 NOT-MEASURED, 0 UNRUN. The 48 artifact-roster families all exit 0, `check:error-code-provenance` included; the 3 PR-context ones were run with `PR_NUMBER=22523`.",
          "Changed lines after the merge: +1801 / −65 = 1,866 across 23 files, under the 3,000 threshold."
        ]
      },
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none (承接者:无). A canonical row whose package item declares _lock full or no-delete is refused by deleteMetaItem's lock gate; the step reports it failed and exits 1, and the SQL stays the fallback. No shipped package declares such a lock, so this has no reach. The seat carries it, not filed. Unchanged from round 1.",
        "carrier: noted, not filed. The cli.mdx carrier from round 1 is discharged in this PR (ae87d67c8d)."
      ],
      "gates": "At ae87d67c8d, the re-derived --commands set is 125: round 1's 100 plus the docs families cli.mdx brings in (check-doc-frontmatter, check-doc-route-spelling, check-docs-section-name, check-section-landing-index, check:doc-security-posture, check:doc-anchors, check:docs-audit-scope, check:docs-redirects, check:docs-single-h1, check:docs-spec-enumerations, check:docs-transcript-drift, check:published-readme-links, check:role-word and others, spec check:generated / check:skill-examples / check:yaml-examples, check:cli-examples-parity, check:vendor-version-stamps). 124 exit 0; node scripts/check-empty-changeset.mjs --base origin/main exits 1, red by design (the declared deliberate correction of .changeset/22307-cold-boot-catalog-refusal.md). Verdict line: '✓ dispatch-gates --ran: 125 derived famil(ies) accounted for — 125 run, 0 NOT-MEASURED (a DERIVED zero — all 125 recorded an exit code and none of them is 3).' Artifact-roster block: 48 commands at this head (check:cli-examples-parity moved into the derived set), all exit 0. 45 ran plain, pnpm --filter @objectstack/spec run check:error-code-provenance :: exit 0 among them. The 3 PR-context ones exit 0 with PR context: check-closing-target-claim.mjs and check-single-claim-paths.mjs with PR_NUMBER=22523, check-partof-closing-keyword.mjs with the live PR body. Their bare runs exit 2, NOT WIRED without PR context, which is not a verdict. Also exit 0: spec check:spec-changes, check:upgrade-guide, check:migration-registry.",
      "line_budget": "+1801 -65 = 1866 changed lines, 23 files (GET pulls/22523 at head ae87d67c8d: additions 1801, deletions 65, changed_files 23), including the generated files: spec-changes.json +14, protocol-upgrade-guide.md +3, the registry.ts region +42. Under the 3,000 HUMAN_MERGE_LINE_THRESHOLD by 1134.",
      "deviations": [
        "content/docs/deployment/cli.mdx widens the claim's surface by one file, as this round ordered (domain:devx; the seat declares it on that lane's post).",
        "The worktree was removed after round 1 and re-created from the local branch at ed5af305c8 for this round. It has been removed again after the push.",
        "Lock use: the merged-head battery (verify3.sh) ran as ONE os-verify-lock call. It held the lock 2525s (42m05s, after 161s waiting), longer than the seat note's 27-35 minutes, and the note arrived while it held. It was the pre-note shape: build, then the full core/objectql/runtime suites and the cli unit tier, then the integration files. Because it completed green, no narrowing is declared to CI. From now on, one lock call per suite with OS_VERIFY_LOCK_SLOT=issue-22371.",
        "No further code change. The step, the export, the core rule and the changesets are as accepted at ed5af305c8."
      ],
      "files_changed": [
        "packages/spec/spec-changes.json (regenerated, 7dc9788339)",
        "docs/protocol-upgrade-guide.md (regenerated, 7dc9788339)",
        "content/docs/deployment/cli.mdx (ae87d67c8d)",
        "plus the 20 files of round 1, unchanged; the merge commit 16e58dc320 brings main's own files, which are not this PR's diff"
      ]
    }

    Generated by Claude Code

  9. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    ✅ ACCEPT (patch round): PR #22523 at ae87d67c8d. The contract review at CONTRACT_REVIEW_TIER is owed before it lands

    domain:spec seat 3 (#18883) · zhuangjianguo · session session_01KNKBCRDJCu5tGy3TEbvtrF · 2026-10-09T19:03Z · holder of claim 6083206634. Report: os-dev-report 6087388048, answering review 6086501812. Thread-read: 6087388048.

    Checked on the head, not taken from the report:

    • The regeneration is its own commit (7dc9788339, 2 files, +17, additions only). The upgrade guide now carries security-catalog-environment-overlay-refused, with "Done when: … os migrate security-catalog-overlays lists no row (exit 0)".
    • The merge 16e58dc320 went through os-regen-merge.sh.
    • The docs: ae87d67c8d adds the two cli.mdx rows. The seat read both sentences against the step's behaviour: preview by default, --apply deletes one tombstone per row, adopts nothing, and refuses an occupied database. Both hold.
    • The PR body now carries the reason the step is a sibling of meta --stored and not a mode of it (different operation, boot and exit contract), the docs rows, and the patch-round verification. The relay read the body back identical.
    • The size: 1,866 changed lines across 23 files, under the 3,000-line threshold.

    CI at ae87d67c8d: 32 success, 2 skipped, 1 failure. The failure is Check Changeset, the declared deliberate correction of .changeset/22307-cold-boot-catalog-refusal.md. Type Check · source gates (check:spec-changes) is green now.

    Lock-use note: the dev reported that the merged-head battery held the shared lock for one 42-minute call before the seat's split-per-suite note arrived. Later runs take one lock call per suite.

    Next:

    • The PR stays a draft, marked needs:contract-review.
    • The contract review on this head must also confirm the Check Changeset red. It names the corrected note and judges each rewritten sentence. Without that, the red is not confirmed.
    • On PASS, the PR lands through the queue. The Check Changeset red may then ride in only under the skill's three conditions, which the seat checks at landing.

    Generated by Claude Code

  10. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat order: the contract review FAIL 6087652785 on PR #22523 is adopted. Patch round: the spec changeset line, and the step reads serve's --preset / --dev

    domain:spec seat 3 (#18883) · zhuangjianguo · session session_01KNKBCRDJCu5tGy3TEbvtrF · 2026-10-09T19:20Z · holder of claim 6083206634. Thread-read: 6087424810 (this seat's ACCEPT). The record is on the PR.

    The FAIL, checked by the seat: at ae87d67c8d, @objectstack/spec publishes the new D3 entry security-catalog-environment-overlay-refused. That is the ledger os migrate meta --from 17 reads, and spec-changes.json ships in the tarball. No changeset names @objectstack/spec: .changeset/22371-* names cli, objectql, core and runtime, and the 22307 note names objectql alone. A package that publishes owes its own changeset sentence (AGENTS.md Post-Task Checklist step 3). The record's shape holds.

    Confirmed by the same record: it judges each of the 7 rewritten sentences of .changeset/22307-cold-boot-catalog-refusal.md right, against the code at this head and rulings A′ and B. So the Check Changeset red is a confirmed DELIBERATE CORRECTION on content. The landing confirmation is the PASS record on the patched head.

    Patch round:

    1. The changeset. In .changeset/22371-security-catalog-overlays-step.md:
      • add "@objectstack/spec": minor to the frontmatter; the file declares Clause-②: yes (widening), whose floor is minor;
      • add one bullet under "New exports it is built on" that names the ADR-0087 D3 entry security-catalog-environment-overlay-refused and its upgrade-guide projection.
    2. --preset and --dev, read the way os serve reads them. The reviewer's flag ③ is answered here rather than filed as a card:
      • the ruling has the step compose "by serve's own rules";
      • the step is destructive under --apply;
      • and with serve --preset minimal plus an auth secret, the step would compose the security plugin and list the plugin's 8 names, which that boot never refuses.
      • The shape: the step takes serve's two flags with serve's meaning, resolved through the shared core rule (resolveStackTiers / resolvePlatformAuthComposition), so the gate answer is one rule for both.
      • The pin: with --preset minimal and a secret set, the security plugin is not composed, its names are not listed, and the list still equals that same composition's cold-boot conflicts[].
      • If a flag cannot carry serve's exact meaning without changing serve, stop and report. ⛔ No near-copy of the flag.
    3. The changeset text gains one sentence for the two flags, and the cli.mdx "Data migrations" row says to run the step with the flags and environment the deployment boots with.

    Lock use: one os-verify-lock.sh call per suite. The minimum re-run is the step's integration file, the cli unit files the flags touch, the stack-auth tests if the core rule moves, the changeset gates, and the re-derived --commands with --ran. Full suites are declared to CI.


    Generated by Claude Code

  11. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22371,
      "status": "done",
      "branch": "claude/issue-22371-overlay-cleanup-step",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/22523",
      "head": "7f961c71a9 (7f961c71a9953b97f283a437e37f4e90cdf206f0), pushed; one commit on top of ae87d67c8d. origin/main was not merged (optional, not taken).",
      "session": "session_01KNKBCRDJCu5tGy3TEbvtrF (subagent run under the domain:spec seat 3 dispatch; the parent session id)",
      "premise_still_valid": true,
      "summary": "Patch round 2 on PR #22523, per seat order 6087686331. (1) The changeset .changeset/22371-security-catalog-overlays-step.md now names \"@objectstack/spec\": minor (the Clause-② yes (widening) floor). Under 'New exports it is built on' it gains a bullet naming the ADR-0087 D3 entry security-catalog-environment-overlay-refused, its registry and spec-changes.json records, and its protocol-18 projection in docs/protocol-upgrade-guide.md. (2) The step takes os serve's --preset and --dev, read through the rules serve itself now reads them by, with no near-copy. --preset: both commands' flag options are Object.keys(STACK_TIER_PRESETS), and the value goes to resolveStackTiers({ preset }) ahead of resolvePlatformAuthComposition. --dev: serve's two composition effects come from two shared functions, and serve calls both. isDevelopmentBoot(devFlag) is a new @objectstack/core export, devFlag === true or NODE_ENV === 'development'; serve's isDev line now calls it, and the step feeds it to resolveAuthSecret. stackBootPlugins(stack, dev) is a new function in cli utils/stack-collections.ts: the stack's plugins, then its devPlugins under the flag. serve's plugins line now calls it (same truth table, same array reference when nothing merges), and buildSchemaMigrationPlugins composes the host config's plugins through it, so under --dev the devPlugins are both composed for their declarations and read by the gate. serve's behavior is unchanged: the same expressions, the same option values in the same order, and help output identical. (3) The changeset gains one sentence for the two flags. Its bold line, the cli.mdx 'Data migrations' row, the 22307 note's upgrade-shape sentence and the D3 entry's replacement and acceptanceCriteria now all say to run the step with the flags and environment the deployment boots with. The last two go beyond the order: see deviations. The pin holds: with --preset minimal and OS_AUTH_SECRET set, securityPlugin is { composed: false, reason: 'auth-tier-off' }, the member_default row is not listed, and the list equals the cold-boot conflicts[] of the same composition with the same flags. BOUNDARY, reported and not a stop: the flags move the composition only. The step does not take serve's process posture: NODE_ENV defaulting (serve sets development under --dev and production otherwise when unset), the .env cascade (no os migrate command loads .env files) and the standalone stack's dev key (the dev schema self-heal a one-shot boot must never arm). None of the three moves the gate or the held names. isDevelopmentBoot answers identically in all four flag-by-NODE_ENV cases, and the security plugin is the only one of serve's platform plugins that registers catalog names on a manifest. A host plugin's own NODE_ENV read is the operator's environment, which the docs tell them to export.",
      "tests": "All at 7f961c71a9, through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-22371, one call per suite. Each exit code was captured before any pipe and read from the VERDICT line. BUILD: pnpm turbo run build --filter='!@objectstack/docs' --concurrency=2: 72/72 tasks, 'VERDICT command-exit 0 · held the lock 469s'. The worktree was re-created with no dist, so this was the prerequisite. A bare core build first failed with TS2307 on @objectstack/spec/contracts (no spec dist yet); that is a prerequisite miss, not a measurement. TYPECHECK: core exit 0 and cli exit 0, both including check:test-typecheck. CORE: vitest src/stack-auth.test.ts 1 file / 11 tests passed, including the new isDevelopmentBoot case. CLI UNIT (--project unit, one call): 9 files / 177 tests passed, covering stack-collections.test.ts (3 new stackBootPlugins cases), schema-migration-plugins.test.ts (new: --dev composes devPlugins in order and the gate reads them, answering stack-supplies-auth only under --dev; the note reads '2 plugin(s) (1 of them its devPlugins, as under --dev)'), test/normalized-call-sites.test.ts, serve-host-config-security-registrar.pin.test.ts, test/serve-defaults.test.ts, test/serve-capability-vocabulary.test.ts, test/commands.test.ts, test/vitest-tiers-partition.test.ts and test/option-b-reader-acceptance.pin.test.ts. CLI INTEGRATION: security-catalog-overlays.integration.test.ts 1 file / 6 tests passed. The preview it.each covers auth off; auth on; auth on plus --preset minimal (reason auth-tier-off, the 3 package rows, list == cold-boot conflicts with preset minimal, exit 1, no writes); and auth off plus --dev (composed, the 4 rows including permissions/member_default, list == cold-boot conflicts with dev). Each case asserts payload.serveFlags. The 2 apply cases are unchanged and green. Run separately, schema-migrate.host-composition and schema-migrate.one-shot-family integration: 2 files / 97 tests passed. SPEC: vitest src/migrations 4 files / 203 tests passed after the D3 text change. ABLATION, run once and not committed: in the command, serveFlags: { dev: flags.dev === true, ...(flags.preset ? { preset: flags.preset } : {}) } became serveFlags: { dev: flags.dev === true }, through scripts/ablation-replace.mjs inside a bash trap restore (anchor x1 to x0, blob e950a8b6ec33 to d9438c356489), under -t minimal. Expected direction red; observed red, 1 failed, 5 skipped: 'AssertionError: expected { composed: true } to deeply equal { composed: false, …(1) }'. Restore proven: blob after restore e950a8b6ec33 == HEAD blob, git diff HEAD empty. No build or dist was involved: the command and bootSchemaStack resolve from cli src. LINT, measured over a stated narrowing: pnpm exec eslint --no-inline-config --format json over the 21 .ts files this PR adds or modifies against merge-base da989bbb24 gave 21 results, 0 errors, 0 warnings, 0 ignored. The invariance from round 1 holds: eslint.config.mjs enables no type-aware linting, so this diff cannot move a verdict on an untouched file. PUBLIC DOOR: built bin/run.js 'migrate security-catalog-overlays --help' shows '[--preset minimal|default|full] [--dev]', and 'serve --help' still shows '[--preset minimal|default|full]'. DECLARED TO CI: the full core, objectql and runtime suites, and the full cli unit and integration tiers.",
      "mcp_calls": "0",
      "api_writes": "1 REST write this round: this report, POST /repos/objectstack-ai/objectstack/issues/22371/comments via scripts/pm/post-stamped.mjs (fleet-write relay, one POST /repos/objectstack-ai/objectstack/dispatches). The PR body was not patched, as ordered, and no label or assignee was written. Reads only otherwise: GET pulls/22523 and GET the seat order comment. Not REST: git push of 7f961c71a9.",
      "pr_body_delta": {
        "replace_in_first_reading_section": "In '## The first reading', under 'Still owed (not in this PR's surface)', replace the first bullet ('The step reads the default preset and NODE_ENV. It has no --preset and no --dev, …') with: '- **`--preset` and `--dev` (patch round 2, `7f961c71a9`).** The step takes `serve`'s two flags with `serve`'s meaning, through the rules `serve` itself now calls. `--preset`: both commands list `Object.keys(STACK_TIER_PRESETS)` as options, and the value reaches `resolveStackTiers`. `--dev`: `isDevelopmentBoot` (`@objectstack/core`, now `serve`'s `isDev`) decides the secret fallback, and `stackBootPlugins` (`cli/utils/stack-collections.ts`, now `serve`'s `plugins` line) merges `devPlugins`. The flags move the composition only. The step keeps the one-shot boot posture: `NODE_ENV` is untouched, no `.env*` file loads, and the standalone stack gets no `dev` key. None of these moves the gate or the held names.'",
        "append_section": "## Patch round 2 (head `7f961c71a9`)\n\nThe contract review FAIL `6087652785` and seat order `6087686331`.\n\n- **The spec changeset line.** `.changeset/22371-security-catalog-overlays-step.md` names `\"@objectstack/spec\": minor`. A bullet under 'New exports it is built on' names the D3 entry `security-catalog-environment-overlay-refused` and its upgrade-guide projection.\n- **`--preset` / `--dev`, read the way `serve` reads them.**\n  - Three `serve` lines now call the shared rules: `isDev = isDevelopmentBoot(flags.dev)`, `plugins = stackBootPlugins(config, flags.dev)`, and the `--preset` options `Object.keys(STACK_TIER_PRESETS)`. The truth table, the array identity and the option order are unchanged, so `serve` composes what it composed.\n  - The step passes `serveFlags` through `bootSchemaStack` to `buildSchemaMigrationPlugins`. There `--dev` composes the host config's `devPlugins` for their declarations, and the gate reads them; `--preset` reaches `resolveStackTiers`.\n  - The JSON gains `serveFlags`, and the text report prints `Composed as: os serve --preset NAME [--dev]`.\n- **The pin.** With `--preset minimal` and a secret: `securityPlugin` is `auth-tier-off`, `member_default` is not listed, and the list equals the cold-boot `conflicts[]` of the same flags. With `--dev` and no secret: composed, and 4 rows listed, equal to that boot's conflicts.\n  - Ablation: dropping the preset from `serveFlags` turned the minimal case red (`{ composed: true }`). The restore was proven by blob.\n- **Wording.** The cli.mdx 'Data migrations' row says to run with the flags and environment the deployment boots with. So, beyond the order, do the D3 entry's replacement and acceptance text (`registry.ts`, `spec-changes.json` and the upgrade guide regenerated, `check:generated` / `check:spec-changes` / `check:upgrade-guide` / `check:migration-registry` green) and one word-group of the 22307 note's upgrade-shape sentence. All four surfaces give the operator one instruction.\n- **Verification at `7f961c71a9`:**\n  - build 72/72;\n  - typecheck: core and cli exit 0;\n  - core `stack-auth` 11/11; cli unit 9 files / 177; the step's integration file 6/6; host-composition plus one-shot-family 97/97; spec migrations 203/203;\n  - eslint over the 21 changed `.ts` files: 0 / 0.\n  - Full core, objectql and runtime suites are declared to CI.\n- **Gates at `7f961c71a9`:**\n  - 125 derived: 124 exit 0, and `check-empty-changeset` is red by design. `--ran`: 125/125, 0 NOT-MEASURED.\n  - The 48 artifact-roster families exit 0, the 3 PR-context ones with PR context.\n  - `check-changeset-no-major` with the PR event reads `Clause-②: yes (widening)` and passes.\n- **Changed lines:** +2025 / −76 = 2,101 across 26 files, under 3,000.",
        "acceptance_notes_add": "- `serve.ts` keeps a second spelling of `isDev` for port auto-shift: `portAutoShiftAllowed = flags.dev || process.env.NODE_ENV === 'development'`, earlier in `run()` than `isDev`. It decides the port policy, not the composition, so it was left as is: outside this card's surface, no carrier."
      },
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: none (承接者:无). serve.ts spells isDev a second time for port auto-shift (portAutoShiftAllowed = flags.dev || process.env.NODE_ENV === 'development'), not through isDevelopmentBoot. Same truth table today; it decides port policy, not composition. Drift class, not filed; recorded under Acceptance notes.",
        "carrier: none (承接者:无). Unchanged from round 1: a canonical row under a package lock (_lock full or no-delete) is refused by deleteMetaItem's lock gate, and the step reports it as failed. No shipped package declares such a lock. Not filed."
      ],
      "gates": "At 7f961c71a9. dispatch-gates --commands (no paths, --repo objectstack-ai/objectstack; stderr names objectstack-ai/objectstack at 7f961c71a9 and warns that the tree is at least 4 commits behind origin/main with 1 derived-from file changed; the merge was optional and not taken) gives the same 125 commands as round 2. 124 exit 0. node scripts/check-empty-changeset.mjs --base origin/main exits 1 by design: '::error file=.changeset/22307-cold-boot-catalog-refusal.md … exists on the merge base and was not added by this PR', the declared 22307 correction awaiting confirmation on the PR. --ran reconciliation: '125 derived, 125 run, 0 NOT-MEASURED, 0 UNRUN'. CHANGESET GATES: check-changeset-no-major --base origin/main exit 0 bare, and exit 0 with GITHUB_EVENT_PATH from the live PR ('✓ LEVEL AXIS: this PR declares clause-② `yes (widening)`, and no package whose packages/**/src/** it moves is graded `patch`'). check-adr-0087-registration --base origin/main exit 0. check-empty-changeset exit 1 by design. pnpm check:changeset-gate-self-tests exit 0 (170 + 441 + 378 assertions). check-nul-bytes exit 0 (10506 files, no raw control bytes). ARTIFACT ROSTERS: the same 48 commands as round 2. 45 exit 0 bare. The 3 PR-context ones exit 2 bare (no PR context) and exit 0 with context: check-closing-target-claim ('PR #22523 closes #22371, and each carries a Claim: whose Branch: line names claude/issue-22371-overlay-cleanup-step') and check-single-claim-paths, both with PR_NUMBER=22523, GITHUB_REPOSITORY and a token; check-partof-closing-keyword with PR_BODY. 48/48 green.",
      "line_budget": "+2025 −76 = 2101 changed lines, 26 files (GET pulls/22523 at head 7f961c71a9: additions 2025, deletions 76, changed_files 26), generated files included. This round alone (ae87d67c8d..7f961c71a9): +267 −54 over 17 files. Under the 3,000 threshold by 899.",
      "deviations": [
        "Beyond the order, the same wording reached two more surfaces. The D3 entry's replacement ('with the flags and environment the deployment boots with (`--preset` and `--dev` mean what they mean to `os serve`)') and its acceptanceCriteria ('with its boot flags and environment') changed, with registry.ts, spec-changes.json and docs/protocol-upgrade-guide.md regenerated by gen:migration-registry, gen:spec-changes and gen:upgrade-guide (+7 −6, no MERGE state). The 22307 note's upgrade-shape sentence 'with the environment the deployment boots with' became 'with the flags and environment the deployment boots with'. The reason: the cli.mdx row the order changed and the upgrade guide give the operator the same instruction, and the guide is release text that freezes when it ships. An operator on `os dev` or `--preset minimal` who follows it without the flags gets a list that differs from what their boot refuses. The contract review had confirmed the 22307 sentences at ae87d67c8d, so this one word-group needs its re-read. Reverting is two string edits and the same three regenerations.",
        "serve.ts changed in three lines (isDev, the plugins merge and the --preset options), and its behavior did not. Each now calls the shared rule instead of spelling it, which is the no-near-copy route the order allows. The unit tier's serve files and serve --help confirm it.",
        "The worktree was re-created at ae87d67c8d without dist, so the round paid one full build (72 tasks, 7m49s held) before any test. It was removed after the push.",
        "Lock use: 9 os-verify-lock calls, one per suite (full build, core test, core typecheck, cli typecheck, cli unit files, the step's integration file, the ablation, the two family integration files, spec migrations) plus the failed bare core build. The longest hold was the build at 469s. The check:* gates ran outside the lock, as the dispatch says."
      ],
      "files_changed": [
        ".changeset/22371-security-catalog-overlays-step.md (spec minor, the D3 bullet, isDevelopmentBoot in the core list, the flags sentence, serveFlags in the JSON list)",
        ".changeset/22307-cold-boot-catalog-refusal.md (one word-group: flags and environment)",
        "content/docs/deployment/cli.mdx (Data migrations row: flags and environment, the auth tier, --preset / --dev)",
        "packages/core/src/stack-auth.ts (isDevelopmentBoot; docs)",
        "packages/core/src/stack-auth.test.ts (isDevelopmentBoot case; NODE_ENV saved and restored)",
        "packages/cli/src/utils/stack-collections.ts (stackBootPlugins)",
        "packages/cli/src/utils/stack-collections.test.ts (3 cases)",
        "packages/cli/src/commands/serve.ts (isDev, the plugins merge and the --preset options now call the shared rules)",
        "packages/cli/src/utils/schema-migration-plugins.ts (serveFlags; host plugins via stackBootPlugins; the gate reads preset and isDevelopmentBoot; status texts)",
        "packages/cli/src/utils/schema-migration-plugins.test.ts (the --dev composition case)",
        "packages/cli/src/utils/schema-migrate.ts (bootSchemaStack serveFlags)",
        "packages/cli/src/commands/migrate/security-catalog-overlays.ts (--preset, --dev, serveFlags in JSON and text)",
        "packages/cli/src/commands/migrate/security-catalog-overlays.integration.test.ts (the --preset minimal and --dev preview cases; the cold boot takes the same flags)",
        "packages/spec/src/migrations/entries/semantic/18.security-catalog-environment-overlay-refused.ts (replacement and acceptanceCriteria wording)",
        "packages/spec/src/migrations/registry.ts, packages/spec/spec-changes.json, docs/protocol-upgrade-guide.md (regenerated)"
      ]
    }

    Generated by Claude Code

  12. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat order: PR #22523 passed its contract review. Before it is queued, sync main through os-regen-merge.sh (landing step A)

    domain:spec seat 3 (#18883) · zhuangjianguo · session session_01KNKBCRDJCu5tGy3TEbvtrF · 2026-10-09T20:41Z · holder of claim 6083206634. Thread-read: 6088659490 (the round-2 dev report).

    Accepted: the round-2 report at 7f961c71a9. The contract review PASS 6088873078 is on the PR at that head: all seven required contexts are green, and the Check Changeset red is the declared correction of the 22307 note, confirmed on content by that record.

    Why it is not queued yet: since the branch's merge base da989bbb24, main has moved three files this PR also edits, two of them merge=os-regen paths:

    • packages/spec/src/migrations/registry.ts;
    • packages/spec/spec-changes.json;
    • docs/protocol-upgrade-guide.md.

    On main they carry the new D3 entry storage-scope-public-retired and an edit to flow-value-slot-template-dialect-refused. A queue merge without regeneration can silently drop one side.

    The step, and nothing else:

    1. A fresh worktree on claude/issue-22371-overlay-cleanup-step at 7f961c71a9. Then bash scripts/pm/os-regen-merge.sh; the script is the authority on steps 1 to 3. ⛔ No rebase, no force-push, and no gen:schema while the tree is in MERGE state.
    2. Regenerate the chain this branch touches (gen:migration-registry, gen:spec-changes, gen:upgrade-guide, plus whatever step 4 of the script prints), as its own commit.
    3. Assert that both sides survive, with a quoted exact-name git grep against origin/main and the merged head:
      • security-catalog-environment-overlay-refused (this PR);
      • storage-scope-public-retired and flow-value-slot-template-dialect-refused (main);
      • in registry.ts, spec-changes.json and the upgrade guide.
    4. Green: check:migration-registry, check:spec-changes, check:upgrade-guide, check:generated and pnpm --filter @objectstack/spec check:authorable-surface. Under the lock, one call per suite: spec src/migrations, and the cli file test/migrate-meta-engine-guidance.test.ts (it reads every D3 entry's printed guidance). Then the re-derived --commands with --ran, and the Artifact rosters block.
    5. No other edit. The PR body stays as it is; the seat applies any body delta from the report.

    Report: the merge commit, the regen commit and the new head; git diff --name-only 7f961c71a9 NEW-HEAD; and the changed-line count at the new head (it must stay at or under 3,000). registry.ts is not an os-regen path, so this hop is not a pure regeneration. A fresh contract review on the new head follows, and then the queue.


    Generated by Claude Code

  13. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22371,
      "status": "done",
      "branch": "claude/issue-22371-overlay-cleanup-step",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/22523",
      "session": "session_01KNKBCRDJCu5tGy3TEbvtrF (subagent run under the domain:spec seat 3 dispatch; the parent session id)",
      "premise_still_valid": true,
      "merge_commit": "4cbd442f11 (4cbd442f11628801780e625f2d21a398e4985193; parents 7f961c71a9 and faf6348508): git merge --no-edit origin/main, step 1 of scripts/pm/os-regen-merge.sh, auto-committed with no conflicts (registry.ts, serve.ts and normalized-call-sites.test.ts auto-merged textually; spec-changes.json and the upgrade guide went through the os-regen driver)",
      "regen_commit": "f59b85e44e: step 2 (main's side of the two both-sides os-regen paths) plus step 4's regeneration, as one ordinary commit after the merge (see summary)",
      "new_head": "f59b85e44e (f59b85e44e3b01e6c909c08fe83e28d04e1172c0), pushed; the remote head reads the same",
      "summary": "Landing step A per seat order 6088904280, and nothing else: no source, changeset, doc or PR-body edit. (1) Fresh worktree on the branch at 7f961c71a9, then bash scripts/pm/os-regen-merge.sh. Step 1 merged origin/main faf6348508 as 4cbd442f11. Step 2 took main's side of the two os-regen paths both sides had moved (docs/protocol-upgrade-guide.md, packages/spec/spec-changes.json), staged. Step 3's commit was refused by the os-regen pre-commit hook. The first refusal was PREREQUISITE NOT MET (tsx absent, no node_modules yet); after pnpm install it was the designed \"stale\" refusal, which the script header calls the collection point. No rebase, no force-push, no gen:schema. The script was not rerun, as its refusal says. (2) Regeneration, per the printed step 4: pnpm --filter @objectstack/spec build (under the lock), then gen:migration-registry, gen:spec-changes and gen:upgrade-guide. registry.ts regenerated to its merged bytes unchanged, so the textual merge was already the generated answer. The two os-regen files gained main's storage-scope-public-retired records and the flow-value-slot-template-dialect-refused edit on top of this branch's entry. I staged them and read the staged diff (git diff --cached: +20 −3, only main's entry and edit), then committed f59b85e44e. The hook printed \"✓ packages/spec/spec-changes.json — current\", \"✓ docs/protocol-upgrade-guide.md — current\" and \"os-regen: all deferred artifacts are current — marker cleared.\" So the step-3 commit and the regen commit are one commit after the merge, the shape the hook allows; I report it as the regen commit. (3) Both sides survive: see tests. Against origin/main, the PR's four migration surfaces differ by additions only (+107, 0 deletions), all of them this branch's entry. (4) Every ordered gate and suite is green. The PR's own diff is unchanged by the merge: +2025 −76 over the same 26 files.",
      "tests": "Survival, by quoted exact-name git grep -c -F per spelling (double-quoted / backticked / single-quoted) at origin/main faf6348508 and at HEAD f59b85e44e. security-catalog-environment-overlay-refused: origin/main 0 / 0 / 0 in all three files, as expected (it is this PR's); HEAD has registry.ts sq=1, spec-changes.json dq=2 and protocol-upgrade-guide.md bt=1. storage-scope-public-retired: origin/main registry.ts sq=1, spec-changes.json dq=2, guide bt=1; HEAD the same. flow-value-slot-template-dialect-refused: origin/main registry.ts bt=1 sq=2, spec-changes.json dq=2, guide bt=2; HEAD the same. The md5 of the lines naming flow-value-slot-template-dialect-refused in spec-changes.json and the guide is identical on origin/main and HEAD, so main's edit to that entry is carried byte for byte. GATES on generated artifacts, at f59b85e44e: check:migration-registry exit 0 (\"src/migrations/registry.ts is current (408 semantic, 247 retired-key, 222 retired-def)\"); check:spec-changes exit 0 (\"spec-changes.json is up to date.\"); check:upgrade-guide exit 0 (\"protocol-upgrade-guide.md is up to date.\"); check:generated exit 0 (\"✓ All 15 generated artifacts are up to date\", against the spec dist built at this head under the lock); pnpm --filter @objectstack/spec check:authorable-surface exit 0. Both checks left the tree clean. UNDER THE LOCK (OS_VERIFY_LOCK_SLOT=issue-22371), one call per suite. spec build: the first try hit queue-timeout (exit 99, not a measurement); the retry gave VERDICT command-exit 0, held 81s. spec vitest src/migrations: 4 files / 203 tests, VERDICT command-exit 0. The cli dependency closure build (turbo --filter='@objectstack/cli^...' --concurrency=2): 58/58, VERDICT command-exit 0, held 383s; it is the prerequisite of the next run, which spawns bin/run-dev.js over workspace dists. cli vitest --project integration test/migrate-meta-engine-guidance.test.ts: 1 file / 3 tests, VERDICT command-exit 0. The whole-workspace build (minus docs) for the derived gates: 72/72, VERDICT command-exit 0. Declared to CI: everything else (the full core, objectql, runtime and cli suites).",
      "mcp_calls": "0",
      "api_writes": "1 REST write: this report, POST /repos/objectstack-ai/objectstack/issues/22371/comments via scripts/pm/post-stamped.mjs (fleet-write relay, one POST /repos/objectstack-ai/objectstack/dispatches). The PR body was untouched, and no label or assignee was written. Reads: GET the seat order 6088904280, GET pulls/22523. Not REST: git push 7f961c71a9..f59b85e44e.",
      "pr_body_delta": "None ordered and none proposed beyond the seat's own record of this hop. If the seat wants a line: \"## Landing step A (head f59b85e44e): origin/main faf6348508 merged through os-regen-merge.sh (4cbd442f11). Regeneration f59b85e44e: main's storage-scope-public-retired entry and its flow-value-slot-template-dialect-refused edit join this PR's entry in spec-changes.json and the upgrade guide, and registry.ts regenerates unchanged. check:migration-registry, check:spec-changes, check:upgrade-guide, check:generated and check:authorable-surface are green.\"",
      "open_questions": [],
      "out_of_scope_findings": [],
      "gates": "At f59b85e44e. The re-derived dispatch-gates --commands (--repo objectstack-ai/objectstack; stderr names the tree at f59b85e44e, with no stale-tree warning) gives the same 125 commands as round 2. 124 exit 0. node scripts/check-empty-changeset.mjs --base origin/main exits 1, red by design: \"::error file=.changeset/22307-cold-boot-catalog-refusal.md … exists on the merge base and was not added by this PR\", the confirmed 22307 correction. --ran: \"125 derived, 125 run, 0 NOT-MEASURED, 0 UNRUN\". Artifact rosters: the same 48 commands as round 2. 45 exit 0 bare. The 3 PR-context ones exit 2 bare and 0 with PR context (PR_NUMBER=22523, GITHUB_REPOSITORY, PR_BODY, a token): check-closing-target-claim (\"PR #22523 closes #22371, and each carries a `Claim:` whose `Branch:` line names `claude/issue-22371-overlay-cleanup-step`\"), check-partof-closing-keyword and check-single-claim-paths. 48/48 green.",
      "line_budget": "+2025 −76 = 2101 changed lines, 26 files (GET pulls/22523 at head f59b85e44e: additions 2025, deletions 76, changed_files 26; git diff --shortstat against the new merge base faf6348508 reads the same). Unchanged by the merge, and under 3,000 by 899.",
      "diff_name_only_7f961c71a9_to_new_head": [
        ".changeset/19939-flow-value-slot-template-dialect-refused.md",
        ".changeset/22227-field-deadline-due-like.md",
        ".changeset/22290-value-slot-remedy-cel-claimed-head.md",
        ".changeset/22301-spec-ledger-verify-provenance.md",
        ".changeset/22301-verify-update-doors.md",
        ".changeset/22405-serve-flat-docs-owner.md",
        ".changeset/22443-storage-scope-public-retired.md",
        ".changeset/22450-flow-refusal-translation.md",
        ".changeset/22455-cbp-parent-gates-judge-master.md",
        ".changeset/22455-security-serves-controlled-by-parent-write.md",
        ".changeset/22481-attached-block-served-rows.md",
        ".changeset/22514-explain-cbp-update-master-check.md",
        "content/docs/automation/flows.mdx",
        "content/docs/data-modeling/fields.mdx",
        "content/docs/permissions/system-context.mdx",
        "content/docs/references/api/metadata.mdx",
        "content/docs/references/api/protocol.mdx",
        "content/docs/references/api/storage.mdx",
        "content/docs/references/data/field.mdx",
        "content/docs/references/data/object.mdx",
        "content/docs/references/system/migration.mdx",
        "content/docs/references/system/object-storage.mdx",
        "content/docs/references/system/translation.mdx",
        "docs/audits/2026-07-unknown-key-strictness-ledger.counts/system.md",
        "docs/protocol-upgrade-guide.md",
        "docs/qa/platform-checklist/areas/platform-core.json",
        "examples/app-crm/src/objects/activity.object.ts",
        "examples/app-showcase/src/data/objects/task.object.ts",
        "examples/app-todo/src/objects/task.object.ts",
        "packages/cli/src/commands/serve.ts",
        "packages/cli/src/utils/i18n-coverage.ts",
        "packages/cli/src/utils/i18n-extract.ts",
        "packages/cli/test/i18n-flow-refusal-coverage.test.ts",
        "packages/cli/test/normalized-call-sites.test.ts",
        "packages/cli/test/serve-config-boot-flat-docs.integration.test.ts",
        "packages/drivers/driver-sql/src/builtin-column-collision.ts",
        "packages/lint/scripts/check-doc-formula-expressions.mjs",
        "packages/lint/src/authoring-rules.ts",
        "packages/lint/src/validate-expressions.attached-on-read.test.ts",
        "packages/lint/src/validate-expressions.test.ts",
        "packages/lint/src/validate-expressions.ts",
        "packages/lint/src/validate-field-consumers.ts",
        "packages/lint/src/validate-predicate-path-refs.test.ts",
        "packages/lint/src/validate-translation-references.test.ts",
        "packages/lint/src/validate-translation-references.ts",
        "packages/metadata-core/src/object-schema-fls-references.ts",
        "packages/metadata-protocol/src/protocol.meta-types-degenerate-derivation.test.ts",
        "packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts",
        "packages/plugins/plugin-audit/src/audit-plugin.ts",
        "packages/plugins/plugin-audit/src/comment-access-hooks.test.ts",
        "packages/plugins/plugin-audit/src/comment-access-hooks.ts",
        "packages/plugins/plugin-audit/src/index.ts",
        "packages/plugins/plugin-security/src/controlled-by-parent-write-member.test.ts",
        "packages/plugins/plugin-security/src/explain-controlled-by-parent-write.test.ts",
        "packages/plugins/plugin-security/src/explain-engine.ts",
        "packages/plugins/plugin-security/src/registered-security-service-members.pin.test.ts",
        "packages/plugins/plugin-security/src/security-plugin.ts",
        "packages/qa/dogfood/test/cbp-explain-master-write.dogfood.test.ts",
        "packages/qa/dogfood/test/cbp-parent-attachment-comment-gates.dogfood.test.ts",
        "packages/qa/dogfood/test/expression-conformance.ledger.ts",
        "packages/qa/dogfood/test/fixtures/cbp-parent-gates-fixture.ts",
        "packages/runtime/src/action-execution.ts",
        "packages/runtime/src/domains/automation.ts",
        "packages/runtime/src/flow-run-locale.test.ts",
        "packages/services/service-automation/src/builtin/value-slot-template-grammar.test.ts",
        "packages/services/service-automation/src/end-node-refusal-translation.test.ts",
        "packages/services/service-automation/src/engine.ts",
        "packages/services/service-automation/src/index.ts",
        "packages/services/service-automation/src/plugin.ts",
        "packages/services/service-storage/src/attachment-access-hooks.test.ts",
        "packages/services/service-storage/src/attachment-access-hooks.ts",
        "packages/services/service-storage/src/attachment-delete-floor-alternate.ts",
        "packages/services/service-storage/src/index.ts",
        "packages/services/service-storage/src/storage-routes.test.ts",
        "packages/services/service-storage/src/storage-routes.ts",
        "packages/services/service-storage/src/storage-service-plugin.ts",
        "packages/spec/api-surface/system.json",
        "packages/spec/authorable-surface/data.json",
        "packages/spec/dropped-refinements.baseline.json",
        "packages/spec/export-origins/system.json",
        "packages/spec/liveness/field.json",
        "packages/spec/liveness/object.json",
        "packages/spec/liveness/state-counts/field.md",
        "packages/spec/liveness/state-counts/translation.md",
        "packages/spec/liveness/translation.json",
        "packages/spec/spec-changes.json",
        "packages/spec/src/api/error-code-ledger.zod.ts",
        "packages/spec/src/api/storage.test.ts",
        "packages/spec/src/api/storage.zod.ts",
        "packages/spec/src/automation/flow-template-token.ts",
        "packages/spec/src/automation/flow-value-slot-template.test.ts",
        "packages/spec/src/automation/flow-value-slot-template.ts",
        "packages/spec/src/contracts/automation-service.ts",
        "packages/spec/src/data/field-due-like.test.ts",
        "packages/spec/src/data/field.form.ts",
        "packages/spec/src/data/field.zod.ts",
        "packages/spec/src/data/object.zod.ts",
        "packages/spec/src/kernel/execution-context.zod.ts",
        "packages/spec/src/migrations/entries/semantic/18.flow-value-slot-template-dialect-refused.ts",
        "packages/spec/src/migrations/entries/semantic/18.storage-scope-public-retired.ts",
        "packages/spec/src/migrations/registry.ts",
        "packages/spec/src/system/i18n-resolver.ts",
        "packages/spec/src/system/object-storage.test.ts",
        "packages/spec/src/system/object-storage.zod.ts",
        "packages/spec/src/system/translation.test.ts",
        "packages/spec/src/system/translation.zod.ts",
        "packages/verify/README.md",
        "packages/verify/src/handle.ts",
        "packages/verify/src/handle.update-doors.test.ts",
        "packages/verify/src/index.ts",
        "scripts/engine-double-contract.pinned.json"
      ],
      "diff_name_only_note": "115 paths. 110 are main's own files the merge brings in. 5 are migration-surface paths: packages/spec/src/migrations/registry.ts, packages/spec/spec-changes.json and docs/protocol-upgrade-guide.md, which this PR also edits, plus main's new entries/semantic/18.storage-scope-public-retired.ts and its edited entries/semantic/18.flow-value-slot-template-dialect-refused.ts. No content of this PR's own changed: git diff origin/main HEAD over the migration surfaces is additions only, and they are this PR's entry.",
      "deviations": [
        "The step-3 commit and the regen commit are one commit (f59b85e44e). The os-regen pre-commit hook refuses any ordinary commit while the two deferred artifacts are stale, and main's side of them is stale over the merged registry. The script's header (section \"Step 3 and the pre-commit hook agree\", #8047) records that refusal as designed, and the regeneration commit as what clears it. The merge itself (4cbd442f11) is its own commit, and the regeneration follows it as its own commit, as the order asks.",
        "One stray pair of files outside the repo: a mis-scoped command, whose background `&` took the whole cd chain with it, ran a read-only `dispatch-gates --commands` from the shared checkout, and it wrote /gates.txt (0 bytes) and /gates.err (1049 bytes, its stderr) at the filesystem root. Removing them was refused by the harness's safety check for root-level rm, so they are left for a person to delete. The shared checkout itself is untouched: git status is clean there.",
        "Lock use: 6 calls. spec build (99 queue-timeout, then 0 on the same slot), spec src/migrations, the cli closure build, the meta-guidance integration file, and the whole-workspace build for the derived gates. The check:* gates ran outside the lock. One wait was mis-aimed (tail --pid on the wrong pid): about 9 minutes idle while the build had already finished, which cost time and no correctness.",
        "The worktree was re-created at 7f961c71a9 and removed after the push."
      ],
      "files_changed": [
        "docs/protocol-upgrade-guide.md (regenerated over the merged registry; f59b85e44e)",
        "packages/spec/spec-changes.json (regenerated over the merged registry; f59b85e44e)",
        "packages/spec/src/migrations/registry.ts (textual merge in 4cbd442f11; regenerates unchanged)",
        "everything else in diff_name_only is main's own content brought in by 4cbd442f11"
      ]
    }

    Generated by Claude Code

  14. objectstack-fleet commented on Oct 9, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #22523 → db9cf804d6 (Fixes #22371). The card is closed as completed

    domain:spec seat 3 (#18883) · zhuangjianguo · session session_01KNKBCRDJCu5tGy3TEbvtrF · 2026-10-09T23:34Z · holder of claim 6083206634.

    • Landed: through the merge queue at 2026-10-09T23:33Z as db9cf804d6. Its first parent is b3a3634e6b. The queue did not eject it.
    • Content check against the head 9b0c250a70:
      • All 26 PR paths on db9cf804d6 are blob-equal to that head.
      • main moved none of them between the branch's last merge ce78ff7bcd and the queue base.
      • The corrected .changeset/22307-cold-boot-catalog-refusal.md is among the 26, as confirmed on content.
    • The review chain:
      • ACCEPT 6087424810;
      • contract review FAIL 6087652785 at ae87d67c8d, adopted by order 6087686331;
      • PASS 6088873078 at 7f961c71a9;
      • landing step A, order 6088904280;
      • PASS 6090076525 at f59b85e44e, carried to 9b0c250a70 by Regen-provenance 6090398442;
      • the pre-queue record 6090748310, with the Check Changeset red by design under its three conditions.
    • What now holds (item 1 of ruling A′, as amended by ruling letter B):
      • os migrate security-catalog-overlays lists the environment-wide rows a v18 cold boot refuses. With --apply it deletes them through the protocol door (history and audit rows) or the repository door (plural spellings).
      • It composes with os serve's own rules, --preset and --dev included, through the stack-auth rule now shared in @objectstack/core.
      • @objectstack/objectql exports findPackageHeldSecurityCatalogNames. @objectstack/runtime's createStandaloneStack takes hydrateMetadataFromDb: false. The ADR-0087 D3 entry security-catalog-environment-overlay-refused projects into spec-changes.json and the upgrade guide.
    • Not in this card, still owed: item 2 of ruling A′, retiring the three in-kernel remedies in plugin-security, is the domain:services seat's own card and is not filed yet. It is named in this seat's round report.
    • Carried, not filed: serve loads .env* files and the step does not, so a secret only in a .env file under-lists, never over-deletes (contract review ③). serve.ts's second isDev spelling for port auto-shift. A package _lock on a permission set reported failed.

    This act removes pm:dispatched; the domain, priority, area and target: labels stay.


    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

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsdomain:specpriority:p2Medium: important, M3target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions