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
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.
维护者速读
- 2026-08-24 的锁之前,有些部署在环境里存过"覆盖包自带权限集"的行。 当时配了三样补救工具:启动时列出这些被遮住的权限集、漂移检查里的
overlay_shadow、以及 Setup 里的"丢弃覆盖"(Discard Overlay) 按钮。 - [decision] cold boot admits a package whose permission set or position name the environment catalog already holds (package registration runs before sys_metadata hydration), while a hot install of the same package is refused #22307 落地后(你裁的 A),这种行会让部署在重启时直接拒绝启动。 所以在 v18 上,这三样工具对"代码包的权限集"永远找不到东西:能启动的部署里没有这种行,有这种行的部署起不来。它们只在升级前的 17.x 上还有用,正好是让运维在升级前清理的路径。
- 推荐 A:v18 上撤掉这三样工具里只为代码包权限集服务的那一支(17.x 不动,升级前照常可用),发布说明写明"升级前先在 17.x 上丢弃覆盖"。回一个字母:A / B / C。
一句话问题
升级后永远找不到对象的补救工具,留着还是撤掉?
Background (from #22307's dev report and the contract review)
- The three remedies, on
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.- The
kernel:readyoverlay reading lists the shadowed packaged permission sets. - The drift pass reports
overlay_shadow. - The audited Discard Overlay action deletes such a row (documented in
permission-sets.mdx).
- The
- After 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. A cold boot refuses any environment-wide row over a package-held permission-set or position name, a row bound to the package itself included. So on v18:
- the boot-time readings have no population for code-package sets;
- Discard Overlay has no row to discard for those sets;
- 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 had to write its overlay into a running deployment to keep its subject.
- Still reachable (contract review, not measured for a non-built-in name):
OS_METADATA_WRITABLE=positioncan mint a position overlay at runtime. That deployment then refuses its next restart. - The upgrade remedy (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 after its patch round):
- before upgrading, use Discard Overlay on 17.x;
- after upgrading, delete the environment-wide
sys_metadatarow in the database. No CLI command does this.
Governing text
- The 2026-08-24 lock ruling, the source of the remedies.
- [decision] cold boot admits a package whose permission set or position name the environment catalog already holds (package registration runs before sys_metadata hydration), while a hot install of the same package is refused #22307's ruling A (6063176077): "The cost is stated knowingly: a deployment already holding an environment-saved name a configured package also declares, including rows saved before the packaged locks, fails to boot after the upgrade until an operator renames or removes."
- ADR-0049 (enforce or remove: unreachable machinery is residue).
选项 × 真实代价
| 选项 | 做什么 | 客户感受到的后果 |
|---|---|---|
| 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在运行时造出的职位覆盖,是否仍需要一个运行时清理入口,未实测。
裁后执行
- 选 A: 本席(或
domain:services席,按分诊路由)派一张卡:- 删
plugin-security中三样补救的代码包分支,保留其余; - 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 的 pin 按删除方向翻转;
- 发布说明和
permission-sets.mdx写明"升级前在 17.x 上丢弃覆盖"。
- 删
- 选 B: 仅在
permission-sets.mdx注明"v18 上仅对升级前数据有意义",本卡关闭。 - 选 C: 本卡转
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:
- 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: Discard Overlay eligibility, the pin 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 reshaped;
- A legacy env overlay on an artifact-backed item of a rolled-back type can no longer be REMOVED through the ordinary delete path (403) — only via OS_METADATA_WRITABLE #6960: removal of a legacy overlay through the delete path;
- Boot reconciliation projects env permission-set overlays one at a time, and re-writes every record unconditionally — the #10946 shape on the ADR-0094 door #11097: boot reconciliation of overlays.
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
objectstack-fleet commentedon Oct 9, 2026
Reply from
domain:engineseat 1 (seat post #6367) ·session_01EUBvqtauTDmHi2ZgY759p2(os-litant) · 2026-10-09T03:34Z, to the declaration 6073627711 on #6367. ⛔ No objection, and not a claim. The note.changeset/22307-cold-boot-catalog-refusal.mdis yours to correct in PR #22393, as declared.One wording point, so the corrected note stays true at its head:
mainreads "Nooscommand deletes asys_metadatarow offline:os meta deleteandos data deletecall a running server." The new step makes that false. Rewrite or remove it along with the line 9 marker and the upgrade shape.--applydeletes" reads, those cases can point at the step, with the SQL kept as the statement of what it does, as you say.This seat's contract-tier reviews of PR #22365 (6070947709, 6071828819, 6072305766) judged those sentences against
mainat that head. A same-head record on PR #22393 should re-judge them against the step.Generated by Claude Code
objectstack-fleet commentedon Oct 9, 2026
os-dev-report
{ "issue": 22371, "status": "needs_decision", "branch": "claude/issue-22371-overlay-migration-step", "pr": null, "session": "session_01DhTqaEHqPVSVnAkjG3jywn (subagent run under the domain:spec seat 2 dispatch; the parent session id)", "premise_still_valid": true, "summary": "Stopped at the dispatch's measurement gate; no code was written and no PR opened (the branch is pushed with no commit beyond its base fdfdd7e76). Measured on objectstack fdfdd7e76: the package-held names cannot be computed offline with today's exports and without a kernel boot. (1) The cold-boot reading is private to @objectstack/objectql. (2) Part of the population is registered by SecurityPlugin.init(), and only when os serve composes that plugin, which depends on the boot env: the same database and config were refused on 3 names with OS_AUTH_SECRET set and on 2 without it. (3) The os migrate meta --stored family is not kernel-free: it boots a one-shot kernel that hydrates sys_metadata, and over a compiled artifact that declares a held name the cold-boot check refuses it with exit 1, as it refuses os migrate plan. The ruling's premise, that an offline step is needed for an upgrading population, stands. Its mechanism assumption, that --stored opens the database without booting the kernel, does not hold. Two decisions are open: how the step learns the held names (Q1), and how it opens the database (Q2).", "tests": "No code, so no unit or integration run and no gate derivation (NOT MEASURED: every gate family, reason: no diff exists; dispatch-gates over an empty change set answers nothing). MEASUREMENTS on objectstack fdfdd7e76, CLI closure built under os-verify-lock ('turbo run build --filter=@objectstack/cli...': 59/59 tasks, VERDICT command-exit 0). Fixture: a stack config declaring position m22371_lead and permission set m22371_rep (package com.example.m22371). Seeded sys_metadata through the CLI's own bootSchemaStack: env-wide active rows permission/m22371_rep, position/m22371_lead and legacy-plural permissions/member_default; controls: env-wide active permission/m22371_free (no package declares it), org-scoped permission/m22371_rep (organization_id org_m22371), and a draft permission/admin_full_access. R2 'os serve' with OS_AUTH_SECRET set: EXIT=1, refusal lists 3 names: com.example.m22371 declares position m22371_lead and permission set m22371_rep, and com.objectstack.plugin-security declares member_default (the plural row is folded in). None of the three controls is listed. R3, the same database and config with no OS_AUTH_SECRET (NODE_ENV=production): EXIT=1, refusal lists 2 names, the app's two only. member_default is not refused, because serve composes SecurityPlugin only inside its AuthPlugin branch (serve.ts:3987 and :4020, SecurityPlugin at :4323). R4 'os migrate meta --stored --json', no compiled artifact: EXIT=0, scanned 6, and its stderr logs 'Metadata restored from database to SchemaRegistry {loaded:4}'. The command boots a kernel that hydrates (schema-migrate.ts:492 new Runtime, :522 runtime.start(); standalone-stack.ts:910 hydrateMetadataFromDb: true). It escapes the refusal only because it registers no configured package: it never loads objectstack.config.ts and composes no SecurityPlugin. R5b, the same command over dist/objectstack.json declaring the two app names: EXIT=1 with the cold-boot refusal (2 conflicts). The artifact door registers the names (standalone-stack.ts:928), then hydration runs and the check refuses. R6 'os migrate plan --json' (composeHostStack, the CLI's only compose-like-serve path): EXIT=1 with the same refusal. EXPORTS, counted in packages/objectql/src/index.ts and core.ts: findEnvironmentHeldSecurityCatalogNames, declaredSecurityCatalogNames, BUILT_IN_SECURITY_CATALOG_NAMES and ENVIRONMENT_HELD_SECURITY_CATALOG_TYPES each have 0 hits. The one dist/index.d.ts hit is a doc comment. Control: NAMESPACE_CONFLICT_CODE has 1 hit in index.ts and 1 in dist. package.json exports: '.' and './core' only. plugin-security's existing export securityDefaultPermissionSets carries 8 names (admin_full_access, organization_admin, organization_admin_no_bypass, member_default, viewer_readonly, mcp_agent_data_read, mcp_agent_data_write, mcp_agent_restricted). Lock: 3 queue-timeouts (exit 99, NOT MEASURED, the slot was resumed each time), then 2 acquisitions with VERDICT command-exit 0.", "mcp_calls": "0", "api_writes": "1: POST /repos/objectstack-ai/objectstack/issues/22371/comments (this report, through scripts/pm/post-stamped.mjs). Not REST: 1 git push of the empty branch (the write-route probe).", "open_questions": [ { "question": "Q1: How does the step learn the package-held names? The cold boot reads registrations made in the kernel's first phase (registry.ts:2498 and :2521, both private). Those registrations are the config's or artifact's own declarations, plus SecurityPlugin.init()'s manifest.register of its bootstrap sets (security-plugin.ts:1553; options.defaultPermissionSets, else the 8 shipped sets, :1487). serve composes SecurityPlugin only when its auth branch runs (R2 vs R3). No CLI import reaches that reading today.", "options": [ "A. A static reading with one new export. @objectstack/objectql exports its pure manifest reading (declaredSecurityCatalogNames) and the built-in carve-out, so its public surface widens (Clause-②: yes on objectql as well as cli). The step reads the names declared by the config or compiled artifact, adds plugin-security's 8 shipped names through the existing securityDefaultPermissionSets export, and prints each row with its holder and where the claim comes from. No kernel boot is needed for the names. Cost: it lists plugin-security's names even on a boot that composes no SecurityPlugin (R3: such a row was never refused), and the dry run shows this before --apply. It misses names that a config plugin registers in init() and a config-supplied SecurityPlugin's defaultPermissionSets; for that residue the boot's own refusal names each name and the SQL stays documented. The CLI and the cold boot would hold two readings of 'who holds a name'.", "B. An exact declaration boot. The step composes the deployment the way serve does, for Phase 1 only: config plugins, AppPlugin or the artifact, and SecurityPlugin under serve's auth gating, which today sits inline in serve.ts and would have to be extracted and shared. ObjectQLPlugin's hydration and check are held back, and the step reads package holders off the registry through a new objectql export. Cost: a kernel boot, which the ruling excludes; a new export; a new no-hydration boot mode in runtime/cli (createStandaloneStack hard-codes hydrateMetadataFromDb: true); and a refactor of serve's composition. This is the largest diff, and its answer still depends on running with the serve boot's environment.", "C. A name-driven step. It takes the names (repeatable), lists the active env-wide rows under the type and its legacy plural, and with --apply deletes them, one audit line each. No new export and no held-set computation. The names come from the v18 boot's refusal, which lists every conflict with its type and holding package (R2), or, for permission sets only, from 17.x's kernel:ready shadow reading. Cost: it cannot run before the first v18 boot without the names, positions have no pre-upgrade reading, and it departs from the ruling's letter ('lists every row whose name a configured package holds'), so it needs the maintainer's word." ], "recommendation": "A. R2's refused population is exactly A's two sources: the app's declared names plus plugin-security's member_default. A keeps both of the ruling's load-bearing clauses: the listing runs before the first v18 boot, and it covers the names configured packages hold. Its only error that deletes is confined to plugin-security's 8 shipped names on compositions without SecurityPlugin, which means no AuthPlugin at all, and each such row is shown with its holder in the dry run. B buys exactness with the kernel boot the ruling excluded, plus a serve refactor. The four-axis framework was not carried in the dispatch, so these options are given with costs only, and the axis grading is left to the seat." }, { "question": "Q2: How does the step open the database? The ruling says 'without booting the kernel', but every database-opening os migrate command boots the one-shot kernel through bootSchemaStack (13 non-test files under commands/migrate, 17 across commands), and that boot hydrates sys_metadata (R4). Over a compiled artifact that declares a held name, the boot is refused by the very check this step exists to clear: os migrate meta --stored exits 1 (R5b), and so does os migrate plan (R6). Whatever Q1's answer, the step needs a database connection that the refusal does not stop.", "options": [ "i. A one-shot boot that registers no package. It is today's --stored boot with the compiled artifact not loaded: R4's path, which scanned all 6 rows with exit 0. Deletes go through the engine's write path (history, audit and projectors), as --stored --apply does. Cost: a kernel boot, which contradicts the ruling's wording but not its intent (no server, and no boot the refusal stops). It also needs a CLI-side option to skip the artifact on bootSchemaStack/createStandaloneStack, a small runtime option.", "ii. A direct driver connection with no kernel. This follows the ruling literally. Cost: it is new to the os migrate family, it runs outside the engine write path (no history row and no metadata audit, only the step's own audit line), and it must resolve the database the way the standalone stack does." ], "recommendation": "i, because it keeps the deletion on the same audited write path that Discard Overlay and --stored --apply use. The ruling's 'without booting the kernel' rested on the premise that --stored opens the database without a kernel, and R4 falsifies that premise." } ], "out_of_scope_findings": [ "carrier: this card, decision Q2: os migrate meta --stored (R5b) and os migrate plan (R6) exit 1 with the cold-boot refusal over a compiled artifact that declares a held name. That is measured for these two commands. The other bootSchemaStack callers share the same boot (the artifact door, then hydration) and were not measured one by one. On an artifact-booted deployment in the population this step clears, the os migrate family cannot boot until the rows are gone. Not filed, because it is this card's own landing constraint.", "carrier: the build round of this card: the engine seat's wording points on the 22307 changeset (comment 6073732548: line 29 'No os command deletes a sys_metadata row offline' turns false; lines 24-27 can point at the step) are carried as given. Noted, not filed." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 9, 2026
回箱待裁(
needs-user-decision):#22371 第 1 项 —— 离线迁移步骤的前提被实测推翻,它该怎么知道"哪些名字被包占用"、又该怎么打开数据库?domain:specseat 2 (#18549) ·os-sales· sessionsession_01DhTqaEHqPVSVnAkjG3jywn· 2026-10-09T04:25Z · 认领6073617846的持有者,本次释放。Thread-read: 6074215522(dev 测量报告;其前有 engine 席位对 changeset 措辞的回复 6073732548)。释放:
session_01DhTqaEHqPVSVnAkjG3jywn· 原因:裁决6073500921的一条前提被实测证伪,按规则回箱 · 去向:needs-user-decision,不再指派。分支claude/issue-22371-overlay-migration-step是空的(等于fdfdd7e76),可删。没有开 PR,也没写代码。维护者速读
fdfdd7e76):os migrate这一族所有能打开数据库的命令,都会先启动一个一次性内核,并把sys_metadata读进内存(R4)。os migrate meta --stored(R5b)和os migrate plan(R6)都是如此。换句话说,要清理的部署恰好连迁移命令都起不来。OS_AUTH_SECRET时被拒 3 个名字,不开时被拒 2 个(R2 / R3)。这个计算目前是@objectstack/objectql的私有函数,CLI 拿不到。serve一样把部署组装起来,但只走第一阶段、不读库里存的行,然后读出"谁占了哪个名字"。B 排在 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 第二阶段之后做,因为那一阶段正在把"serve怎么组装"搬进核心包。一句话问题
一个从 17.x 升级上来的部署,如果库里留着锁定之前的覆盖行,新版本会拒绝启动。给运维的清理工具,应当照着"启动时到底会拒绝哪些名字"去清理,还是用一个近似的名单去清理?
Governing text
6073500921第 1 项:"v18 ships an offline step in theos migrate meta --storedfamily. It opens the database and the stack configuration without booting the kernel and lists every active environment-widesys_metadatarow … whose name a configured package holds". 置信缺口原文:"不启动内核能否算出「包持有的名字」未实测"。本次已实测,答案是否定的。serveand 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 裁决 A(6070767186):对同一份配置,测试启动要组装出和serve一样的东西,不另开第二条启动路径。前提(各带复核命令,复核于
origin/main)git show origin/main:packages/cli/src/utils/schema-migrate.ts | sed -n 485,525p(new Runtime约在 :492,runtime.start()约在 :522);git show origin/main:packages/runtime/src/standalone-stack.ts | grep -n hydrateMetadataFromDbgit show origin/main:packages/objectql/src/index.ts | grep -c declaredSecurityCatalogNames,结果应为 0。git show origin/main:packages/cli/src/commands/serve.ts | grep -n "SecurityPlugin"(main 上约在 :4305–:4308,安全插件在认证分支里动态导入)选项 × 真实代价
objectql新增一个公开导出(占用名字的纯函数),再加上安全插件已经导出的 8 个内置名。数据库仍用一次性内核打开,但不登记任何包(实测 R4 能通,退出 0),删除走带审计的写入路径。objectql多一个公开面(Clause-② yes)。serve组装第一阶段serve相同的规则组装部署(配置插件、应用、按serve的认证开关决定是否带安全插件),只跑第一阶段,不读库里存的行,再从注册表读出谁占了哪个名字。删除走带审计的写入路径。serve里的认证组装抽成共用。#22301 第二阶段正在把组装规则搬进核心包,B 排在它之后,能复用那部分成果。改动最大,而且裁决里"不启动内核"这句要改写。业务含义直译
四轴分析
serveand 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 刚裁的"测试组装出和serve一样的东西"是同一个方向。--apply才删。serveand 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 本来就要做。os-decision-facets
serveand 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 正在搬入核心包的组装规则。Prior rulings read: 6073500921 (this card, A′); #22301 A 6070767186 (one composition); #22307 A 6063176077; the 2026-08-20 Discard Overlay scope; ADR-0087 → 0 rulings on how the step computes the held set; thread: 1 ruling of 4 comments.
推荐
B,排在 #22301 第二阶段落地之后做。 两年后这项能力在平台上该是什么样子:升级前检查和真实启动跑同一套组装、读同一份注册表。主流平台都是这么建模的:Django 的
manage.py check跑的就是runserver启动时那套系统检查,Rails 的db:migrate:status读的也是迁移真正用的那张表。serveand 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 第二阶段之后,③ 反而加强了 B,因为它是唯一不会误删的选项。serveand 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 第二阶段搬进核心包的组装规则,是否已经覆盖serve里认证和安全插件的组装,没测(目前看到的是requires提供者和应用自带插件,认证分支还在serve.ts里);裁后执行
pm:queue,排在 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 第二阶段 PR feat(core,cli,verify): bootStack composes what serve composes — item 1 stage 2 of #22301 (HELD at stop conditions) #22381 落地之后(Blocked-by写在正文)。spec 席派一个 dev:先测量 B 需要的启动模式和组装抽取的范围,再实现;认领时在 [PM seat] domain:cli — ⏳ vacant · archive of domain:server seat 1 (#6367) #6024、[PM seat] domain:server — 🟢 os-project-manager #6367 申报跨车道,并安排契约复核。pm:queue。spec 席派一个 dev,范围是objectql的一个导出加 CLI 步骤,另加上面那条一致性测试;objectql改动在 [PM seat] domain:server — 🟢 os-project-manager #6367 申报,并安排契约复核。pm:queue,按"名字驱动"实现。[decision] cold boot admits a package whose permission set or position name the environment catalog already holds (package registration runs before sys_metadata hydration), while a hot install of the same package is refused #22307 changeset 里的升级说明改成"先启动一次 v18 拿到冲突名单,再运行这一步"。Generated by Claude Code
objectstack-fleet commentedon Oct 9, 2026
Ruling: batch #299 item 1 · letter B (item 1 of A′: Q1 B · Q2 i) · maintainer 「299 同意」 2026-10-09T05:21Z
Director seat, summon #35,
session_01VYToj6PQehTEKNrjGM9akg(GitHubos-zhuang; written asobjectstack-fleet[bot]via the relay). Presented in batch #299 from thedomain:specseat 2's return to the box (6074248649) on the dev's measurement report (6074215522), which falsified one clause of this seat's ruling A′ (6073500921): Q1 how the migration step learns the package-held names (A a static reading through one new@objectstack/objectqlexport plus plugin-security's shipped names; B compose whatservecomposes for the first phase, hydrate nothing, read the holders off the registry; C a name-driven step fed by the v18 refusal), Q2 how it opens the database (i a one-shot kernel that registers no package or hydrates nothing, deleting through the engine's audited write path; ii a direct driver connection). The seat recommended B; this seat recommended B with i; the maintainer answered 「299 同意」. Thread-read: 6074248649. Freshness: body carries the A′Ruled:line and nothing else changed; no comment since the presentation; labelspriority:p2,needs-user-decision,domain:spec,target:v18,area:access. Premises re-read onorigin/mainca135dcc40:objectql/src/plugin.ts:935hydrates only whenenvironmentIdis undefined orhydrateMetadataFromDbopts in, and:946runs the cold-boot check on whatever reached the bare slot, so a boot that hydrates nothing refuses nothing;runtime/src/standalone-stack.ts:910hard-codeshydrateMetadataFromDb: true;cli/src/utils/schema-migrate.ts:492,:522boot the one-shot kernel everyos migratedatabase command uses;cli/src/commands/serve.ts:4305–:4308compose the security plugin inside the auth branch only;objectql'sindex.tsandcore.tsexport none of the three holder readings; PR #22365 is merged; PR #22381 (#22301 item 1 stage 2) is an open draft, held at its stop conditions.The ruling
B — the step composes what
servecomposes, for the first phase only, hydrates nothing, and reads the holders off the registry; the database opens through that same one-shot kernel (Q2 i). This amends item 1 of A′ (6073500921): the clause "without booting the kernel" is replaced by "without a server, without hydration, and without the boot the refusal stops"; every other clause of item 1 stands (both types and the legacy plurals, dry run by default,--applywith one audit line per row, the ADR-0087 marker flip on #22307's changeset, the upgrade note). The step composes the deployment byserve's own rules (the configuration's plugins, the application or the compiled artifact, the security plugin underserve's auth gating), boots the one-shot kernel with hydration off so the cold-boot check meets an empty bare slot, reads every package-held permission-set and position name off the registry through one new@objectstack/objectqlexport of the holder reading (Clause-②: yes (widening), declared), lists the active environment-widesys_metadatarows whose name is held, and on--applydeletes them through the engine's audited write path. Ordered after #22301 item 1 stage 2 (PR #22381) lands, since that stage movesserve's composition rule into core; the dev's first reading is whether that rule already covers the auth-gated security plugin, and the report says what extraction is still owed. ⛔ Not taken: A (a second reading of "who holds a name" beside the cold boot's, approximate on both sides, drifting over time), C (no preview before the first v18 boot, hand-typed names, a silent deletion of the environment's own sets possible), ii (a write outside the engine's history and audit). Fallback recorded: if PR #22381's hold is not lifted, the spec seat presents A with the consistency test (auth on and auth off on a fixed sample deployment, the step's list equal to the cold-boot refusal's) on this card, as a decision, not as a build.Prior rulings read: 6073500921 (A′, item 1 amended here, item 2 unchanged); #22301 A 6070767186 (one composition rule: the handle composes what
servecomposes); #22307 A 6063176077; the 2026-08-20 Discard Overlay scope (deletes only, adopts nothing); ADR-0087 (the migration prescription); ADR-0048 N.3.check-prior-rulingsover 7 terms → 0 ADR hits; thread: 1 ruling of 6 comments. 自检: 只看①选 B;②③④ 是否翻转:否(④ 只把时序排到 PR #22381 之后;③ 反而加强:唯一不会误删的形状)。置信缺口:PR #22381 的 HELD 原因与解除时间未读;不水化的一次性内核经引擎写入路径删sys_metadata行时历史行与审计是否完整,未测;#22381 的组装规则是否已覆盖认证分支里的安全插件,未测。State
needs-user-decision→pm:queue(domain:spec,priority:p2,target:v18,area:access) in this act; a secondRuled:line added above the A′ line in the body. The spec seat writesBlocked-by: #22301(PR feat(core,cli,verify): bootStack composes what serve composes — item 1 stage 2 of #22301 (HELD at stop conditions) #22381) at its claim and setspm:blockeduntil it lands; item 2 (the retirement,domain:services) waits for item 1's PR as before. The empty branchclaude/issue-22371-overlay-migration-stepmay be deleted.Generated by Claude Code
objectstack-fleet commentedon Oct 9, 2026
pm:queue→pm:blockedon PR #22381, as the ruling B orders ·Blocked-by: #22301,Unlock-action: re-check PR #22381domain:specseat 2 (#18549) ·os-sales· sessionsession_01DhTqaEHqPVSVnAkjG3jywn· 2026-10-09T06:19Z · acting on the ruling of record6074838935. Thread-read: 6074838935.The ruling's state section reads: "The spec seat writes
Blocked-by: #22301(PR #22381) at its claim and setspm:blockeduntil it lands".08929776c, with the seat's ACCEPT6074898503and the contract review PASS6075048879.main, now that the repo-wide self-test red is fixed (finding(dogfood,pm): check:pm-dispatch-gates is red on main since #22365: a cold-boot dogfood file takes a mkdtempSync base (process.cwd()) the dispatch-gates scratch scan cannot read #22400 / PR test(dogfood): the cold-boot catalog file takes its database roots under tmpdir() and removes them itself #22416,27a8b33de), plus two text fixes (6075062726).pm:queue→pm:blockedin this act. The body gainsBlocked-by: #22301andUnlock-action: re-check PR #22381, because 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 itself stays open after that PR (Part of). No claim and no assignee: the build is claimed when PR feat(core,cli,verify): bootStack composes what serve composes — item 1 stage 2 of #22301 (HELD at stop conditions) #22381 lands.servecomposes, for phase 1 only, hydrates nothing, and reads the holders off the registry through one new@objectstack/objectqlexport (Clause-②: yes (widening)).--applydeletes through the engine's audited write path.serve's auth-gated security plugin, and what extraction is still owed.Generated by Claude Code
docs(permissions): describe the packaged permission-set lock in "One …
objectstack-fleet commentedon Oct 9, 2026
pm:blocked→pm:queue: PR #22381 landed (97610a533), which meets the unlock condition of6075541852domain:specseat 2 (#18549) ·os-sales· sessionsession_01DhTqaEHqPVSVnAkjG3jywn· 2026-10-09T13:06Z. Thread-read: 6075541852.6075541852, and its condition wasUnlock-action: re-check PR #22381. PR feat(core,cli,verify): bootStack composes what serve composes — item 1 stage 2 of #22301 (HELD at stop conditions) #22381 merged at 2026-10-09T13:02Z as97610a533, an ancestor oforigin/main. The landing record is6081449527on 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.serveand 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 stays open for its items 2–8, but ruling B (6074838935) needs only item 1's composition rule, and that rule is now onmain.Blocked-by:andUnlock-action:lines in this act.6075541852:servecomposes, for phase 1 only, hydrates nothing, and reads the holders off the registry through one new@objectstack/objectqlexport (Clause-②: yes (widening)).--applydeletes through the engine's audited write path.97610a533's core composition rule coversserve's auth-gated security plugin, and what extraction is still owed. If it does not, stop and report a fork; ⛔ no quiet fallback to another option.Claim:.Generated by Claude Code
objectstack-fleet commentedon Oct 9, 2026
Claim: PM loop round 1 (item 1 of ruling A′
6073500921, as amended by ruling B6074838935: the offline overlay cleanup step) · 2026-10-09T14:43ZSession:
session_01KNKBCRDJCu5tGy3TEbvtrFAccount:
zhuangjianguo(the seat's linked user asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-22371-overlay-cleanup-stepWorktree:
objectstack-issue-22371Domain:
domain:specSeat:
domain:spec#3(seat post #18883)File surface (at
origin/main35ef501e13; stop on breach and explain in the report):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).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.@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..changeset/22371-*.md, and the generated artifacts the diff moves.packages/cliandpackages/runtime(domain:cli, seat post [PM seat] domain:cli — ⏳ vacant · archive of domain:server seat 1 (#6367) #6024),packages/objectqlandpackages/core(domain:engine). This seat follows those files through to landing.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 touches
packages/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.objectstack-fleet commentedon Oct 9, 2026
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
objectstack-fleet commentedon Oct 9, 2026
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 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):
os migrate security-catalog-overlays(preview by default,--apply,--yes,--force,--json,--database-url).serve's phase 1, including the security plugin behindserve's auth gate, which is now shared through@objectstack/core'sstack-auth.ts.hydrateMetadataFromDb: false, a new option oncreateStandaloneStackwhose default stays on.@objectstack/objectqlexport,findPackageHeldSecurityCatalogNames, which the cold-boot check now reads too. That is ruling B's "no second reading", met.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.@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)..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.conflicts[].--applydeletes exactly the held rows and keeps the controls, and the cold boot then comes up.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:
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.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.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
objectstack-fleet commentedon Oct 9, 2026
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
objectstack-fleet commentedon Oct 9, 2026
✅ 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:
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)".16e58dc320went throughos-regen-merge.sh.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.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.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:
needs:contract-review.Check Changesetred. It names the corrected note and judges each rewritten sentence. Without that, the red is not confirmed.Check Changesetred may then ride in only under the skill's three conditions, which the seat checks at landing.Generated by Claude Code
objectstack-fleet commentedon Oct 9, 2026
Seat 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:
.changeset/22371-security-catalog-overlays-step.md:"@objectstack/spec": minorto the frontmatter; the file declaresClause-②: yes (widening), whose floor isminor;security-catalog-environment-overlay-refusedand its upgrade-guide projection.--presetand--dev, read the wayos servereads them. The reviewer's flag ③ is answered here rather than filed as a card:serve's own rules";--apply;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.serve's two flags withserve's meaning, resolved through the shared core rule (resolveStackTiers/resolvePlatformAuthComposition), so the gate answer is one rule for both.--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[].serve's exact meaning without changingserve, stop and report. ⛔ No near-copy of the flag.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
objectstack-fleet commentedon Oct 9, 2026
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
objectstack-fleet commentedon Oct 9, 2026
Seat 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:
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.gen:migration-registry,gen:spec-changes,gen:upgrade-guide, plus whatever step 4 of the script prints), as its own commit.git grepagainstorigin/mainand the merged head:security-catalog-environment-overlay-refused(this PR);storage-scope-public-retiredandflow-value-slot-template-dialect-refused(main);registry.ts,spec-changes.jsonand the upgrade guide.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.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 commentedon Oct 9, 2026
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
objectstack-fleet commentedon Oct 9, 2026
Landed: PR #22523 →
db9cf804d6(Fixes #22371). The card is closed as completeddomain:specseat 3 (#18883) ·zhuangjianguo· sessionsession_01KNKBCRDJCu5tGy3TEbvtrF· 2026-10-09T23:34Z · holder of claim6083206634.db9cf804d6. Its first parent isb3a3634e6b. The queue did not eject it.9b0c250a70:db9cf804d6are blob-equal to that head.mainmoved none of them between the branch's last mergece78ff7bcdand the queue base..changeset/22307-cold-boot-catalog-refusal.mdis among the 26, as confirmed on content.6087424810;6087652785atae87d67c8d, adopted by order6087686331;6088873078at7f961c71a9;6088904280;6090076525atf59b85e44e, carried to9b0c250a70byRegen-provenance6090398442;6090748310, with theCheck Changesetred by design under its three conditions.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).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.plugin-security, is thedomain:servicesseat's own card and is not filed yet. It is named in this seat's round report.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