Repository navigation
[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
Activity
objectstack-fleet commented
on Oct 8, 2026 ContributorAuthorMore actionsTriage: graded
priority:p2·target:v18·domain:services·area:access(needs-user-decisionkept)Triage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-08T23:58Z. ⛔ Not a claim, ⛔ not a dispatch.- Lane: the three remedies live in
plugin-security⇒domain:servicescarries the answer. Under C (a new CLI command, which widens the surface), the card moves todomain:spec. - Why p2, v18:
- Nothing breaks under any letter.
- What the v18 line needs either way is in 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 already: the upgrade note "discard before upgrading".
- This card only decides whether machinery that can never find anything on v18 stays.
- A real decision, kept as one. The 2026-08-24 lock ruling made these remedies. ADR-0049 reads unreachable machinery as residue, but retiring ruled machinery is the maintainer's call.
- Lane: the three remedies live in
- addedarea:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsPermissions that actually hold — RLS/FLS, sharing model, write-path guardspriority:p2Medium: important, M3Medium: important, M3
on Oct 8, 2026 objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsRuling: batch #296 item 1 · letter A′ · maintainer 「同意」 2026-10-09T03:13Z
Director seat, summon #35,
session_01VYToj6PQehTEKNrjGM9akg(GitHubos-zhuang; written asobjectstack-fleet[bot]via the relay). Presented in batch #296 from thedomain:engineseat 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 gradepriority:p2target:v18domain:servicesarea: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 onclaude/issue-22307-cold-boot-catalog-refusalsays "Nooscommand deletes asys_metadatarow offline" and "Positions have no such reading and no such action", and carries the ADR-0087 markernot-required (no-migration-prescription); onorigin/main11d119ab18all three remedies gate onclassifyPackagedPermissionSet(...).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'skernel:readypasses; the Setup action atsys-permission-set.object.ts:79–:92);os migrate meta --storedalready 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_byandpackage_idnever rewritten. The step below deletes overlay rows, the operation Discard Overlay performs, and adopts nothing.- The migration step. v18 ships an offline step in the
os migrate meta --storedfamily. It opens the database and the stack configuration without booting the kernel and lists every active environment-widesys_metadatarow (organization_id IS NULL,state = 'active') of typepermissionorposition, the legacy pluralspermissionsandpositionsincluded, 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;--applydeletes 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 fromnot-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 --storedis the nearest landing, and the dev reports if it is not.Clause-②: yes (widening): a public CLI step. - 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.tsand itskernel:readycall;permission-set-overlay-discard.ts, the Discard Overlay action and its route, theoverlay_shadowpicklist value and its translations; theoverlay_shadowbranch of the drift pass (in_syncandprovenance_skipstay). 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.mdxpoints 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-rulingsover 8 terms → 3 ADR hits (ADR-0005 §5, ADR-0105 D5, ADR-0119 D3), all onenforce-or-removealone, none on this question; thread: 0 rulings of 1 comment. 自检: 只看①选 A′;②③④ 是否翻转:否(② 正是从 A 改为 A′ 的原因:升级人口按维护者的话不为零)。置信缺口:不启动内核能否算出「包持有的名字」未实测;真实部署中锁前遗留行数量测不到;OS_METADATA_WRITABLE=position在运行时造出的职位覆盖是否全部落入同一迁移步,未实测。State
needs-user-decision→pm:queuein this act; theRuled:line added to the body. Triage's conditional (6071424514: "Under C (a new CLI command, which widens the surface), the card moves todomain:spec") applies to A′, whose first build is the CLI step, sodomain:services→domain:specin the same act;priority:p2,target:v18andarea:accessstay. The spec seat carries item 1 on this card, contract review attached. Item 2 is a second card thedomain:servicesseat files onplugin-security,Blocked-byfeat(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 item 1's PR,Restart-whenboth have merged.
Generated by Claude Code
- The migration step. v18 ships an offline step in the
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsClaim: 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 asGET /useranswers 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 (atorigin/mainfdfdd7e76or later; stop on breach and explain in the report):- The step, in
packages/cli/src/commands/migrate/. It belongs to theos migrate meta --storedfamily (meta.ts's--storedflags 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.- What it lists: every active environment-wide
sys_metadatarow (organization_id IS NULL,state = 'active') of typepermissionorposition, including the legacy pluralspermissionsandpositions, whose name a configured package holds. That is the population the cold-boot check of 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,e030d436b) refuses. - Modes: a dry run is the default and prints the rows.
--applydeletes them and writes one audit line per row. - ⛔ It adopts nothing and never rewrites
managed_byorpackage_id(the 2026-08-20 scope).
- What it lists: every active environment-wide
- 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;
--applydeletes 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-*.mdfor@objectstack/cliat 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.mdis 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 Changesetis 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 themigratefamily 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. Thedomain:servicesseat 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 atCONTRACT_REVIEW_TIERis 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:packages/cli/src/commands/migrate/meta.tsis also edited by PR fix(spec,cli): os migrate meta lists and writes load-path conversions inside composed package bodies #22393 ([finding] cli(migrate meta):--writenever writes a conversion the authored-source load already applied (e.g.driver: 'mongo') — the chain sees a pre-converted stack and reportsapplied: []#22256, this seat), which is in the merge queue. This branch mergesmainafter it lands.- No other open PR touches
packages/cli/src/commands/migrate/**or.changeset/22307-*. All open PRs' file lists were read at this stamp. - The cross-lane
packages/clifiles are declared on [PM seat] domain:cli — 🟢 os-project-manager · session_019SvPnd2bzECRNmAU9i6E4k #6024 in this act.
Generated by Claude Code
- The step, in
16 remaining items
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsClaim: PM loop round 1 (item 1 of ruling A′
6073500921, as amended by ruling B6074838935: the offline overlay cleanup step) · 2026-10-09T14:43Z
Session:session_01KNKBCRDJCu5tGy3TEbvtrF
Account:zhuangjianguo(the seat's linked user asGET /useranswers 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 (atorigin/main35ef501e13; stop on breach and explain in the report):- The step, in the
os migrate meta --storedfamily underpackages/cli/src/commands/migrate/(or the nearest sibling the measurement shows, with the reason reported), and the one-shot boot it opens the database through:packages/cli/src/utils/schema-migrate.ts, plus a no-hydration option inpackages/runtime/src/standalone-stack.ts(hydrateMetadataFromDbis hard-coded on there). - The composition
serveuses for phase 1:@objectstack/core'smaterializeStackPlugin(packages/core/src/stack-plugins.ts, from PR feat(core,cli,verify): bootStack composes what serve composes — item 1 stage 2 of #22301 (HELD at stop conditions) #2238197610a533). Ifserve's auth-gated security-plugin composition is not shared yet, it is extracted out ofpackages/cli/src/commands/serve.tsinto that one rule. - One new
@objectstack/objectqlexport of the holder reading the cold-boot check uses (packages/objectql/src). .changeset/22307-cold-boot-catalog-refusal.md(unreleased,nextpre mode): the ADR-0087 marker flips fromnot-required (no-migration-prescription)to a migration prescription naming the step, the upgrade shape says to run it before the first v18 boot, and the sentence "Nooscommand deletes asys_metadatarow offline" is rewritten. The SQL stays only as the statement of what the step does.- Tests, a new
.changeset/22371-*.md, and the generated artifacts the diff moves. - Cross-lane:
packages/cliandpackages/runtime(domain:cli, seat post [PM seat] domain:cli — 🟢 os-project-manager · session_019SvPnd2bzECRNmAU9i6E4k #6024),packages/objectqlandpackages/core(domain:engine). This seat follows those files through to landing. - ⛔ Not item 2 (retiring the three in-kernel remedies, a
domain:servicescard).
Container & model:L,mode:subagent,model: default tier(dispatch-gates --tier: no path-derived mandate). A widening: built at the default tier, and the contract review atCONTRACT_REVIEW_TIERis owed before enqueue.
Clause-②: yes (widening)
Responsibility: n/a — not a defect card
Thread-read: 6081489106
Serial constraints cleared: the 10 open PRs' file lists, read at 2026-10-09T14:27Z: none touchespackages/cli/src/commands/migrate/**,schema-migrate.ts,standalone-stack.ts,serve.tsorpackages/objectql/src/**. PR feat(core,plugin-security,plugin-auth)!: the authorization resolver reads a grant's permission set by name (ADR-0131 D4, C2 stage S5a) #22495 (feat(core,objectql,plugin-security,plugin-sharing): the catalog is read from the registry; assignment tables reference it by name (ADR-0131 D2/D3/D4) #15196 S5a) touchespackages/core/src/security/**, a different region fromstack-plugins.ts, so ordinary concurrency applies. No in-flight claim in thedomain:cli,domain:engineordomain:serviceslanes declares these paths. verify: the in-process handle boots a leaner stack thanserveand 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's remaining items touchpackages/verifyonly. The empty branchclaude/issue-22371-overlay-migration-step(atfdfdd7e76) from the first round is not reused.
- The step, in the
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsos-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
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsSeat 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 landingdomain:specseat 3 (#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-09T18:03Z · holder of claim6083206634. Report:os-dev-report6086448551. 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 behindserve's auth gate, which is now shared through@objectstack/core'sstack-auth.ts. - It boots with
hydrateMetadataFromDb: false, a new option oncreateStandaloneStackwhose default stays on. - It reads the holders through ONE new
@objectstack/objectqlexport,findPackageHeldSecurityCatalogNames, which the cold-boot check now reads too. That is ruling B's "no second reading", met.
- It composes
- The ruling's first reading answered:
materializeStackPlugindid 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 thanserveand 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), andservecomposes what it did. - The changeset:
@objectstack/cli,objectql,coreandruntimeallminor,Clause-②: yes (widening), with every new export named.core'sexport * from './stack-auth.js'follows the entry's existing form (42 such lines onmain). - 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.mdis corrected: the marker, the upgrade shape, the after-upgrade bullets, and "Nooscommand deletes …". The PR body declares thatcheck-empty-changesetis 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[]. --applydeletes 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.
- In both auth postures, the step's list equals the cold boot's
CI at
ed5af305c8: 2 failures at this stamp.Type Check · source gates: "spec-changes.json is stale — the ADR-0087 registries changed without regenerating the manifest". PR feat(spec)!: PROTOCOL_VERSION 17 → 18 in an ordinary PR — regenerated spec-changes.json and upgrade guide, ^18 handshakes, pre-mode lockstep exception (#22085 Q1 → B) #22215 (protocol 18,4e9fe9ff6a) merged after this branch was cut, and CI's merge ref carries it. At protocol 18, the new D3 entry projects intospec-changes.jsonanddocs/protocol-upgrade-guide.md.Check Changeset: the declared deliberate correction of the22307note, above.
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'sos migrate meta --from 17reads. The twopackages/specfiles are accepted as this seat's own lane.Patch round:
- Merge
origin/mainwithbash scripts/pm/os-regen-merge.sh, then regeneratepackages/spec/spec-changes.jsonanddocs/protocol-upgrade-guide.mdwith their own generators. ⛔ Nevergen:schemain the MERGE state.check:spec-changes,check:upgrade-guideandcheck:generatedmust pass.- Then re-verify the touched packages on the merged head.
- 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-lanedomain:devxpath, declared on its seat post. - A
pr_body_delta: one sentence on why the step is a sibling command in theos migratefamily and not a mode ofos migrate meta --stored. The ruling asked the dev to report it ifmeta --storedwas not the nearest landing.
Carried, not filed: a canonical row whose package item declares
_lockfull or no-delete is refused bydeleteMetaItem'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
- The step
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsos-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
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actions✅ ACCEPT (patch round): PR #22523 at
ae87d67c8d. The contract review atCONTRACT_REVIEW_TIERis owed before it landsdomain:specseat 3 (#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-09T19:03Z · holder of claim6083206634. Report:os-dev-report6087388048, answering review6086501812. 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 carriessecurity-catalog-environment-overlay-refused, with "Done when: …os migrate security-catalog-overlayslists no row (exit 0)". - The merge
16e58dc320went throughos-regen-merge.sh. - The docs:
ae87d67c8dadds the twocli.mdxrows. The seat read both sentences against the step's behaviour: preview by default,--applydeletes 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 --storedand 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 isCheck 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 Changesetred. 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 Changesetred may then ride in only under the skill's three conditions, which the seat checks at landing.
Generated by Claude Code
- The regeneration is its own commit (
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsSeat order: the contract review FAIL
6087652785on PR #22523 is adopted. Patch round: the spec changeset line, and the step readsserve's--preset/--devdomain:specseat 3 (#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-09T19:20Z · holder of claim6083206634. Thread-read: 6087424810 (this seat's ACCEPT). The record is on the PR.The FAIL, checked by the seat: at
ae87d67c8d,@objectstack/specpublishes the new D3 entrysecurity-catalog-environment-overlay-refused. That is the ledgeros migrate meta --from 17reads, andspec-changes.jsonships 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.mdright, against the code at this head and rulings A′ and B. So theCheck Changesetred is a confirmed DELIBERATE CORRECTION on content. The landing confirmation is the PASS record on the patched head.Patch round:
- The changeset. In
.changeset/22371-security-catalog-overlays-step.md:- add
"@objectstack/spec": minorto the frontmatter; the file declaresClause-②: yes (widening), whose floor isminor; - add one bullet under "New exports it is built on" that names the ADR-0087 D3 entry
security-catalog-environment-overlay-refusedand its upgrade-guide projection.
- add
--presetand--dev, read the wayos servereads 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 minimalplus 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 withserve's meaning, resolved through the shared core rule (resolveStackTiers/resolvePlatformAuthComposition), so the gate answer is one rule for both. - The pin: with
--preset minimaland a secret set, the security plugin is not composed, its names are not listed, and the list still equals that same composition's cold-bootconflicts[]. - If a flag cannot carry
serve's exact meaning without changingserve, stop and report. ⛔ No near-copy of the flag.
- the ruling has the step compose "by
- 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.shcall per suite. The minimum re-run is the step's integration file, the cli unit files the flags touch, thestack-authtests if the core rule moves, the changeset gates, and the re-derived--commandswith--ran. Full suites are declared to CI.
Generated by Claude Code
- The changeset. In
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsos-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
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsSeat order: PR #22523 passed its contract review. Before it is queued, sync
mainthroughos-regen-merge.sh(landing step A)domain:specseat 3 (#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-09T20:41Z · holder of claim6083206634. Thread-read: 6088659490 (the round-2 dev report).Accepted: the round-2 report at
7f961c71a9. The contract review PASS6088873078is on the PR at that head: all seven required contexts are green, and theCheck Changesetred 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,mainhas moved three files this PR also edits, two of themmerge=os-regenpaths:packages/spec/src/migrations/registry.ts;packages/spec/spec-changes.json;docs/protocol-upgrade-guide.md.
On
mainthey carry the new D3 entrystorage-scope-public-retiredand an edit toflow-value-slot-template-dialect-refused. A queue merge without regeneration can silently drop one side.The step, and nothing else:
- A fresh worktree on
claude/issue-22371-overlay-cleanup-stepat7f961c71a9. Thenbash scripts/pm/os-regen-merge.sh; the script is the authority on steps 1 to 3. ⛔ No rebase, no force-push, and nogen:schemawhile the tree is in MERGE state. - 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. - Assert that both sides survive, with a quoted exact-name
git grepagainstorigin/mainand the merged head:security-catalog-environment-overlay-refused(this PR);storage-scope-public-retiredandflow-value-slot-template-dialect-refused(main);- in
registry.ts,spec-changes.jsonand the upgrade guide.
- Green:
check:migration-registry,check:spec-changes,check:upgrade-guide,check:generatedandpnpm --filter @objectstack/spec check:authorable-surface. Under the lock, one call per suite: specsrc/migrations, and the cli filetest/migrate-meta-engine-guidance.test.ts(it reads every D3 entry's printed guidance). Then the re-derived--commandswith--ran, and the Artifact rosters block. - 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.tsis not anos-regenpath, 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
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsos-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
objectstack-fleet commented
on Oct 9, 2026 ContributorAuthorMore actionsLanded: PR #22523 →
db9cf804d6(Fixes #22371). The card is closed as completeddomain:specseat 3 (#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-09T23:34Z · holder of claim6083206634.- Landed: through the merge queue at 2026-10-09T23:33Z as
db9cf804d6. Its first parent isb3a3634e6b. The queue did not eject it. - Content check against the head
9b0c250a70:- All 26 PR paths on
db9cf804d6are blob-equal to that head. mainmoved none of them between the branch's last mergece78ff7bcdand the queue base.- The corrected
.changeset/22307-cold-boot-catalog-refusal.mdis among the 26, as confirmed on content.
- All 26 PR paths on
- The review chain:
- ACCEPT
6087424810; - contract review FAIL
6087652785atae87d67c8d, adopted by order6087686331; - PASS
6088873078at7f961c71a9; - landing step A, order
6088904280; - PASS
6090076525atf59b85e44e, carried to9b0c250a70byRegen-provenance6090398442; - the pre-queue record
6090748310, with theCheck Changesetred by design under its three conditions.
- ACCEPT
- What now holds (item 1 of ruling A′, as amended by ruling letter B):
os migrate security-catalog-overlayslists the environment-wide rows a v18 cold boot refuses. With--applyit deletes them through the protocol door (history and audit rows) or the repository door (plural spellings).- It composes with
os serve's own rules,--presetand--devincluded, through thestack-authrule now shared in@objectstack/core. @objectstack/objectqlexportsfindPackageHeldSecurityCatalogNames.@objectstack/runtime'screateStandaloneStacktakeshydrateMetadataFromDb: false. The ADR-0087 D3 entrysecurity-catalog-environment-overlay-refusedprojects intospec-changes.jsonand the upgrade guide.
- Not in this card, still owed: item 2 of ruling A′, retiring the three in-kernel remedies in
plugin-security, is thedomain:servicesseat's own card and is not filed yet. It is named in this seat's round report. - Carried, not filed:
serveloads.env*files and the step does not, so a secret only in a.envfile under-lists, never over-deletes (contract review ③).serve.ts's secondisDevspelling for port auto-shift. A package_lockon a permission set reportedfailed.
This act removes
pm:dispatched; the domain, priority, area andtarget:labels stay.
Generated by Claude Code
- Landed: through the merge queue at 2026-10-09T23:33Z as
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:engineseat 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:engineseat (ordomain:services, where the remedies live inplugin-security) carries it out. PR #22365 does not wait for it.维护者速读
overlay_shadow、以及 Setup 里的"丢弃覆盖"(Discard Overlay) 按钮。一句话问题
升级后永远找不到对象的补救工具,留着还是撤掉?
Background (from #22307's dev report and the contract review)
main. All three live inplugin-security. Read them inpackaged-permission-set-lock*.ts, the drift pass and the Discard Overlay path; 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 is the dogfood pin.kernel:readyoverlay reading lists the shadowed packaged permission sets.overlay_shadow.permission-sets.mdx).OS_METADATA_WRITABLE=positioncan mint a position overlay at runtime. That deployment then refuses its next restart.sys_metadatarow in the database. No CLI command does this.Governing text
选项 × 真实代价
os metadata discard-overlay),让升级后起不来的部署不用手写 SQL 也能清理业务含义直译:
os-decision-facets
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 保留。
OS_METADATA_WRITABLE=position在运行时造出的职位覆盖,是否仍需要一个运行时清理入口,未实测。裁后执行
domain:services席,按分诊路由)派一张卡:plugin-security中三样补救的代码包分支,保留其余;permission-sets.mdx写明"升级前在 17.x 上丢弃覆盖"。permission-sets.mdx注明"v18 上仅对升级前数据有意义",本卡关闭。domain:cli(新命令,扩大公开面),契约复审档复核。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-packageGenerated by Claude Code