Repository navigation
runtime: the standalone stack stamps environmentId: 'env_local', so ObjectQLPlugin skips sys_metadata hydration on every self-hosted boot — an object published at runtime answers 404 on the data API after a restart #20071
Description
Activity
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actions分诊首次定级:
priority:p1·bug·domain:cli·pm:queue—— 自托管的独立启动栈给自己盖上environmentId: 'env_local',于是ObjectQLPlugin每次启动都跳过sys_metadata回读:运行时发布的对象,服务一重启,数据接口就返回 404(对象未注册)Path:
packages/runtime/src/standalone-stack.ts(第 568 行environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? 'env_local',第 757 行new ObjectQLPlugin({ environmentId, runPlatformMigrations: … }),没有hydrateMetadataFromDb)· 对照packages/objectql/src/plugin.ts(第 767 行if (this.environmentId === undefined || this.hydrateMetadataFromDb))Triage: lands in
packages/runtime⇒domain:cli(perlanes/cli.md),bug,priority:p1,pm:queue; rationale: on every standalone boot (os dev/serve/start) the stack stamps'env_local', which the plugin reads as a per-project cloud kernel and so skips thesys_metadatahydration — measured by the #17676 dev on a stockos serve --devbooted twice on one SQLite file: an object published at runtime answers 200 before the restart and404 OBJECT_NOT_FOUNDafter it, while its row is still insys_metadata; the same gate class #9380 fixed forrunPlatformMigrationsand left for hydration; the self-hosted "build in Studio, restart, the app is gone from the data API" path is a core flow broken on every restart, with a one-line measured candidate fix, hence p1; #17676 isBlocked-by:this card.分诊席 #6015,2026-09-25T02:21Z。⛔ 不认领、不派发。本席读完了卡面(本卡尚无评论),并在 objectstack
origin/main7f1de2eb66上核对。本席核对
standalone-stack.ts第 568 行:const environmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? 'env_local';。- 同文件第 750–757 行:
[#9380]注释写明「this stack stamps'env_local'above」,所以runPlatformMigrations改成了显式声明;但new ObjectQLPlugin({ environmentId, runPlatformMigrations: cfg.runPlatformMigrations ?? true })里没有hydrateMetadataFromDb。 objectql/src/plugin.ts第 767 行:只有this.environmentId === undefined || this.hydrateMetadataFromDb时才回读。- PR test(cli): pin the three-probe restart acceptance for an API-created package #20069(A writable package created via
POST /api/v1/packagesis registered in memory only — it does not survive a restart, and leaves its published metadata orphaned #17676 的三探针重启验收测试,it.fails)已合并,就是当前 main 的7f1de2eb66。 - 卡面的重启测量,以及候选修法
hydrateMetadataFromDb: true的验证,本席都没有重跑。
定级说明
p1:
- 自托管用户在 Studio 里建对象、发布、用起来,服务一重启,这个对象在数据接口上就「不存在」了。数据还在库里,但应用实际上坏掉了,而且每次重启都会发生。
- 范围:按机制看,独立启动栈上所有运行时创建的对象都会受影响;卡面只实测了一个对象。
- 开发已经测过一行的候选修法,修复成本低。
执行要点
- 照 The three
kernel:readymigrations inassembleMetadataProtocolnever arm on a self-hosted boot — the standalone stack stampsenvironmentId = 'proj_local', and the gate asks forundefined#9380 的做法显式声明:独立启动栈拥有自己本地的sys_metadata,所以在ObjectQLPlugin的选项里写明回读(hydrateMetadataFromDb: true)。如果有只读的一次性启动确实不需要回读,由它自己显式关掉。 - 核对插件文档里的警告:「Set this ONLY when the kernel's registry is per-instance isolated AND
sys_metadatalives on the kernel's own local driver」。拿独立启动栈逐条对照,结论写进 PR。 - 钉子:把 PR test(cli): pin the three-probe restart acceptance for an API-created package #20069 里的
it.fails(第二个探针,packages/cli/test/package-restart-acceptance.integration.test.ts)改成普通的it。修复 PR 里它按设计会先变红,然后 A writable package created viaPOST /api/v1/packagesis registered in memory only — it does not survive a restart, and leaves its published metadata orphaned #17676 就可以关闭。 - 顺带改掉错误的日志:插件里那句「Project kernel — skipping sys_metadata hydration (metadata sourced from artifact)」在独立启动栈上不成立,修复后不应再出现。
Generated by Claude Code
- addedbugSomething isn't workingSomething isn't workingpriority:p1High: required for production / M2High: required for production / M2and removed
on Sep 25, 2026 objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsClaim: PM loop round 7 (serial)
Session:session_01TnPAC1UsTGfHPXVUCL6iLn
Branch:claude/issue-20071-standalone-hydration
Worktree:objectstack-issue-20071
Domain:domain:cli
Seat:domain:cli#1
File surface:packages/runtime/src/standalone-stack.ts(theObjectQLPluginconstruction and a declaredhydrateMetadataFromDbconfig field besiderunPlatformMigrations), its tests underpackages/runtime/src/,packages/cli/test/package-restart-acceptance.integration.test.ts(probe 2'sit.failspromoted toit), and one.changeset/20071-*.md.packages/objectql/**andpackages/spec/**are read-only. Stop on breach and explain in the report
Container & model:M,mode:subagent,model: default judgment tier(this act'snode scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --tier packages/runtime/src/standalone-stack.tsanswered: no path-derived mandate). A p1 boot defect whose one-line fix must be checked against the plugin's own caution for every standalone caller, with a stop valve on a non-localsys_metadata, so it gets the default judgment tier.
Clause-②: no
Thread-read: 5825627519
Serial constraints cleared:the maintainer's order in this seat's session (「继续派发」) moves the lane on once a card's PR is in the merge queue: R6's PR #20086 (#15638) is in the merge queue (its timeline carries added_to_merge_queue), and its surface (plugin-hono-server) shares no file with this one. The file lists of all 10 open PRs were read in this act. None touches packages/runtime/src/standalone-stack.ts, packages/objectql/src/plugin.ts or the cli restart-acceptance test. PR #20069 (#17676's acceptance pin) is merged. This card is the lane queue's only open P0/P1 at a4ca69a9, so it is next by NORTH-STAR 优先级 3Taken 2026-09-25T03:09Z,
origin/maina4ca69a9.Clause-②: no: a boot defect is fixed, and a new optional config field defaults to the fixed behaviour. If the dev finds the field widens a published schema in a way the changeset gate reads asyes, the dev stops and reports. The dev posts no second claim; this comment is its identity.objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 20071, "status": "done", "branch": "claude/issue-20071-standalone-hydration", "pr": "https://github.com/objectstack-ai/objectstack/pull/20100", "session": "session_01TnPAC1UsTGfHPXVUCL6iLn — the dispatching PM session (mode:subagent, the parent's id); identity is the branch", "premise_still_valid": true, "summary": "Premise held on a4ca69a9: every site in mechanism assumption 1 was at the named line (standalone-stack.ts:568/:750-757/:241, plugin.ts:179/:767/:770). createStandaloneStack now declares hydration beside the #9380 declaration: StandaloneStackConfigSchema gains hydrateMetadataFromDb (optional, docblock in #9380's voice), and the stack passes hydrateMetadataFromDb: cfg.hydrateMetadataFromDb ?? true to ObjectQLPlugin. The caution holds clause by clause, with lines in the PR body: per-instance registry (plugin.ts:397 new ObjectQL per plugin; engine.ts:3061 per-engine SchemaRegistry; no statics in registry.ts:1819), and sys_metadata on the kernel's own driver (SysMetadataObject declares no datasource; the stack composes one default datasource; no proxy driver exists in this repo). Stop valve did not fire: 3 production callers (serve.ts:2740, default-host.ts:163, schema-migrate.ts:303 bootSchemaStack), all on the stack's own driver. Out of repo: duly measured (local), cloud NOT MEASURED (search control leg: 0 hits for hydrateMetadataFromDb although the plugin docblock says cloud sets it). bootSchemaStack deliberately inherits true, with the evidence in the PR (plan's mirror principle, files-to-references' empty-scan refusal, read-only hydration, and the duplicates byte-identical pin green); schema-migrate.ts is untouched. Ruling ③: the pin's it.fails is promoted to it and is green at b574b580, red on the ablation with the card's exact 404 OBJECT_NOT_FOUND. Ruling ④: the skip line is unreachable on the stack (the flag is pinned true under all three stamps); no objectql edit. Assumption 6 is measured for a second row type: an env-wide app row is back in the registry after a two-boot restart. Org rows are excluded by design (ADR-0005). Assignee: the card showed os-steve when read; I wrote only the PR's assignee. PR #20100 is draft and unarmed. The worktree is removed without --force.", "tests": "All heavy runs used scripts/pm/os-verify-lock.sh (slot issue-20071). Exit codes were captured before any pipe, and each part of a ;-batch was recorded separately. FINAL HEAD b574b580: (1) Pin: pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 test/package-restart-acceptance.integration.test.ts: VERDICT command-exit 0, Tests 5 passed (5); runtime dist proven to carry the fix by ablation-dist-preflight (2 files). (2) Runtime standalone-stack suites, 5 files: 41 passed. (3) pnpm --filter @objectstack/runtime typecheck: exit 0; check:test-typecheck OK with the ledger unchanged; the new file is listed once in the tsconfig.test.json program with 0 errors (tsc --listFiles). (4) Full pnpm lint: exit 0, the union, not a narrowing. (5) All 60 dispatch-gates commands: exit 0; --ran reconciliation 60/60, 0 NOT-MEASURED. AT c945f282 (only a type-only test edit follows): (6) runtime test 279 files, 3906 passed / 1 skipped. (7) cli unit project 224 files, 3158 passed. (8) cli typecheck exit 0. (9) cli integration on 10 files, 38 passed, including the duplicates byte-identical and platform-migrations-arming pins. The rest of the integration project is declared to CI. RED FIRST: the new unit test on the unfixed source failed 2/2, on the flag (expected env_local+true, got false) and on \"hydr_widget is registered after the restart: expected undefined\". The unfixed boots logged \"Project kernel — skipping sys_metadata hydration\" once each. ABLATION from committed state: ablation-replace --anchor \"hydrateMetadataFromDb: cfg.hydrateMetadataFromDb ?? true,\" --delete, anchor x1 to x0, blob 6f1ae0bd to 81dc475a. @objectstack/runtime rebuilt; ablation-dist-preflight --absent reports the marker absent from all 6 dist files. Unit test 2 failed. Pin 1 failed | 5 passed, the failure being \"GET /data/leave_request after a restart: {error: Object leave_request is not registered, code: OBJECT_NOT_FOUND} expected 404 to be 200\". RESTORE: blob back to 6f1ae0bd == HEAD, git status --porcelain empty; runtime rebuilt; preflight reports the marker present in 2 dist files. The unit leg was re-taken at b574b580 with the same red, and restored blob == HEAD. VACUOUS ASSERTION FOUND AND REMOVED: a pin check that the second boot does not print the skip line stayed green on the ablated build, because os serve does not print that INFO line at the pin's log level. It is removed in 2f7e036e, and ruling ④ is instead held by the unit flag pin.", "mcp_calls": "2 — mcp__github__search_code x2 (read-only: createStandaloneStack org-wide outside this repo → 20 hits, all objectstack-ai/duly plus one objectos changelog; hydrateMetadataFromDb org-wide outside this repo → 0 hits, the control leg showing cloud is not visible). No MCP write tool was called.", "api_writes": "3 — all through the fleet-write relay as objectstack-fleet[bot]: (1) pr_create via scripts/pm/with-fleet.sh --via dispatch, relay run 36094440285 success → POST /repos/objectstack-ai/objectstack/pulls (PR 20100, draft; body read back byte-identical, 11545 bytes, one footer, Clause-② line at column 0); (2) scripts/pm/label-write.mjs --issue 20100 --assign os-steve, relay run 36094493125 success → POST /repos/objectstack-ai/objectstack/issues/20100/assignees (read back: assignee os-steve; labels documentation/size/m/tests/tooling were the path labeler’s, untouched); (3) this os-dev-report via scripts/pm/post-stamped.mjs → POST /repos/objectstack-ai/objectstack/issues/20071/comments. Plus 4 git pushes (empty branch; df359188; 2f7e036e+c945f282; b574b580), which are not REST writes. Exactly the dispatched budget.", "line_budget": "n/a", "files_changed": [ ".changeset/20071-standalone-hydration.md (new, @objectstack/runtime patch, +45/-0)", "packages/runtime/src/standalone-stack.ts (+49/-3: hydrateMetadataFromDb config field + docblock, the ObjectQLPlugin construction, two line pointers made name-based)", "packages/runtime/src/standalone-stack-hydrate-metadata.test.ts (new, +197/-0)", "packages/cli/test/package-restart-acceptance.integration.test.ts (+24/-31: probe 2 it.fails promoted to it, header rewritten for the fixed state)" ], "deviations": [ "Route: took the PM-suggested config-field shape rather than a bare literal. The literal would avoid widening the exported config type, but would leave an unmeasured cloud embedder no opt-out and the #9380 pair asymmetric. See open_questions[0] for the Clause-② consequence.", "bootSchemaStack NOT opted out (ruling ① is conditional on \"genuinely does not need it\"; measured it does, or is neutral). No edit to schema-migrate.ts, which is outside the claimed surface anyway.", "Merged origin/main (d4c897e0) into the branch before opening the PR, per AGENTS.md §10, as c945f282. The default merge message carries no trailer pair; the pre-push trailer check passed.", "Edited #9380's own docblock pointer in standalone-stack.ts (\"line ~567 below\" → \"createStandaloneStack below\"), because my insertion made the line number wrong. Same file, claimed surface.", "The first gate sweep (at c945f282) had two non-zero rows. check:dual-build-cjs-loads exited 3 with PREREQUISITE NOT MET: 12 packages outside the closure had no dist, which a later gate in that sweep built. check:slot-lookup exited 1, a real finding on my test (two objectql lookups erased to any), fixed in b574b580. At b574b580 all 60 exit 0.", "Two MCP read calls (search_code) to measure out-of-repo createStandaloneStack callers for the stop valve." ], "gates": { "node scripts/check-adr-0087-registration.mjs --base origin/main": "exit 0 · ✓ check-adr-0087-registration: this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen).", "node scripts/check-adr-0087-registration.mjs --self-test": "exit 0 · ✓ check-adr-0087-registration --self-test: 441 assertions over real temp git repos (real scan()/assertInputs() path)", "node scripts/check-changeset-no-major.mjs --base origin/main": "exit 0 · · no `pull_request` payload was available to read a declaration from", "node scripts/check-changeset-no-major.mjs --self-test": "exit 0 · ✓ check-changeset-no-major --self-test: 339 assertions (frontmatter dialects measured against @changesets/parse + the pre/exit exemption switch in both directions + the #7005 diff scoping over real te", "node scripts/check-ci-filter-parity.mjs": "exit 0 · OK: all 184 declared cross-package glob(s) (131 unique) are covered by `core` or `crosspkg`, every `crosspkg` entry still covers one, and the `test` job's `if:` still names both filters.", "node scripts/check-closing-keyword-parity.mjs": "exit 0 · • packages/spec/CHANGELOG.md -- 6080503 bytes exceeds the sweep's 2097152-byte cutoff for UNREGISTERED files", "node scripts/check-closing-keyword-parity.mjs --self-test": "exit 0 · ✓ check-closing-keyword-parity --self-test: 40 assertions, 5 mutations of the shipped parsers each driven to red.", "node scripts/check-comment-mask-adoption.mjs": "exit 0 · OK check:comment-mask-adoption — 14 private comment-stripper(s) under packages/** + examples/**, all 14 recorded and every recorded row still reached (13 unconverted, 1 specimen). A new one reds here.", "node scripts/check-comment-mask-adoption.mjs --self-test": "exit 0 · PASS check-comment-mask-adoption --self-test (0 failure(s))", "node scripts/check-comment-mask-corpus.mjs": "exit 0 · ✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 7148 files, 0 disagree, 0 unparseable, 83.9s (comparator self-test: 26 cases pass).", "node scripts/check-empty-changeset.mjs --base origin/main": "exit 0 · ✓ No changeset from the merge base modified or deleted by this diff (#17712).", "node scripts/check-empty-changeset.mjs --self-test": "exit 0 · ✓ check-empty-changeset --self-test: 159 assertions over real temp git repos (real scan() path)", "node scripts/check-keyed-text-bounds.mjs": "exit 0 · ⚠ The delta is information, not a verdict — this population grows AND shrinks for good reasons, and only the floors decide. Reproduce the record: see this file's header.", "node scripts/check-keyed-text-bounds.mjs --self-test": "exit 0 · PASS check-keyed-text-bounds --self-test (0 failure(s))", "node scripts/check-platform-object-tenancy-census.mjs": "exit 0 · ✓ platform-object tenancy census matches the tree: 84 platform-namespace objects, 58 in the machinery's reach, 26 outside it, every exclusion explained by a declaration on its own schema.", "node scripts/check-platform-object-tenancy-census.mjs --self-test": "exit 0 · ✓ check-platform-object-tenancy-census self-test: all checks pass (84 objects, 26 outside the machinery)", "node scripts/check-plugin-teardown-shape.mjs": "exit 0 · ✓ check:plugin-teardown-shape: 69 Plugin implementation(s) across 6579 source(s) under packages/**; every teardown-shaped method (stop / shutdown / close / dispose) sits beside a real destroy() (0 kno", "node scripts/check-plugin-teardown-shape.mjs --self-test": "exit 0 · ✓ check-plugin-teardown-shape self-test: 48 cases pass (real pre-#10375 fixture reds, the repaired file and both delegating-alias directions stay green, every roster name reds, every excluded name sta", "node scripts/check-registry-log-declared.mjs": "exit 0 · examples/app-showcase — S1 constructs a SchemaRegistry in its tests", "node scripts/check-registry-log-declared.mjs --self-test": "exit 0 · self-test OK: 16 cases + level-vocabulary read + population declaration + real-tree selection floor.", "node scripts/check-rest-log-spy-declared.mjs": "exit 0 · OK: 29 of 196 test file(s) beside packages/rest/src/log.ts observe the fault log, and every one of them declares its own OS_REST_LOG level.", "node scripts/check-rest-log-spy-declared.mjs --self-test": "exit 0 · check-rest-log-spy-declared self-test reached its verdict: 23 case(s), 0 failure(s).", "node scripts/check-system-context-census.mjs": "exit 0 · check-system-context-census: OK — 112 elevation read sites in 20 packages across 45 files, living in 93 symbol(s); the page cites 106 symbol(s) against 106 required, over 130 anchors and 8 file-level ", "node scripts/check-system-context-census.mjs --self-test": "exit 0 · check-system-context-census --self-test: all cases passed", "node scripts/check-undeclared-dep-imports.mjs": "exit 0 · ⚠ The delta is information, not a verdict — the floors are `_=` and cannot see an upward drift at all, which is why it is PRINTED. Reproduce the record: see this file's header.", "node scripts/check-undeclared-dep-imports.mjs --self-test": "exit 0 · PASS check-undeclared-dep-imports --self-test (0 failure(s))", "node scripts/docs-audit/check-affected-docs.mjs": "exit 0 · → the unreachable rows themselves: this command with --json", "node scripts/docs-audit/check-drift-comment.mjs": "exit 0 · ✓ check-drift-comment: 66 cases pass across 5 fixture diff(s).", "node scripts/pm/release-rehearsal-clone.mjs --self-test": "exit 0 · ✓ self-test passed", "pnpm --filter @objectstack/spec run check:duration-unit-keys": "exit 0 · ✓ check:duration-unit-keys — 204 unit-declaring numeric key(s) across 2588 source file(s) all carry their unit in the key name (or in a sibling `unit`, or under a declared exemption: 6 declared durati", "pnpm check:changeset-gate-self-tests": "exit 0 · ✓ check-changeset-no-major --self-test: 339 assertions (frontmatter dialects measured against @changesets/parse + the pre/exit exemption switch in both directions + the #7005 diff scoping over real te", "pnpm check:cli-test-child-env": "exit 0 · ✓ check:cli-test-child-env: 91 spawner source(s) among 196 under packages/cli/test/**; no new bulk process.env copy reaches a spawned child, all 109 spawn call(s) declare their child's env, and all 6 ", "pnpm check:cross-package-test-inputs": "exit 0 · OK: 29 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob (6 of them on a split \"test:repo\" task); 13 walked root(s) judged, 3 on ACCEPTED_WALK_RADII; 2138 tes", "pnpm check:dispatcher-error-vocabulary": "exit 0 · [#15723] the ARGUMENT POSITION of new APIError( … ) and APIError.from( … ) IS now in this gate's population — the `apierrorarg` shape. `APIError.from` copies the record's `code` onto the body, so the ", "pnpm check:doc-authoring": "exit 0 · ✓ doc authoring guard: sibling-package prose ids hold the baseline — 815 pinned site(s) across 231 file(s), 91677 string(s) read in 1252 parsed source(s), no growth, no burn-down unrecorded.", "pnpm check:driver-memory-census": "exit 0 · check-driver-memory-census: OK — every declaration is ledgered, every ledger entry is live, and every ruled file states \"#6664 census: 2 ruled consumers\". This gate polices the census, never investmen", "pnpm check:dts-closure": "exit 0 · check-dts-closure: 72 built package(s) swept - 166/166 declared declaration file(s) present across 72 package(s); 0 built package(s) declare no declaration entry point and owe none.", "pnpm check:dual-build-cjs-loads": "exit 0 · ⚠ The delta is information, not a verdict — this population grows AND shrinks for good reasons, and only the floors decide. Reproduce the record: see this file's header.", "pnpm check:engine-double-contract": "exit 0 · ⚠ The delta is information, not a verdict — this population grows AND shrinks for good reasons, and only the floors decide.", "pnpm check:gitlink-declared": "exit 0 · check-gitlink-declared: OK (9528 index entries -- 0 gitlink(s) at mode 160000; no .gitmodules in the index, so nothing is declared; nothing to declare).", "pnpm check:issue-citations": "exit 0 · ✅ check-issue-citations --self-test: grammar narrowed, four 404 causes kept apart, both board strategies agree, diff scope red AND green, scope contract pinned (73 cases, 7 batteries)", "pnpm check:lean-entry-closure": "exit 0 · Admitted set held exactly (15 packages); 6 denied names absent.", "pnpm check:logger-receiver-detach": "exit 0 · control corpus fired on all five detach shapes in this same run, and stayed silent on the measured `console` and options-callback populations -- so the zero above is a reading.", "pnpm check:nul-bytes": "exit 0 · check-nul-bytes: OK (scanned 9521 text file(s) -- 9521 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes).", "pnpm check:objectql-double-limit": "exit 0 · baseline key set verified against d4c897e: no files added.", "pnpm check:objectui-changeset": "exit 0 · ✓ objectui-range --self-test: all checks passed", "pnpm check:org-identifier": "exit 0 · check-org-identifier: OK (2881 author-facing source file(s), 17 session binding(s) resolved, no removed session.tenantId alias).", "pnpm check:page-declaration-shape": "exit 0 · blind spot: 1 computed carrier(s) no source scan can enumerate — examples/app-crm/objectstack.config.ts:86.", "pnpm check:pm-changeset-deadline-census": "exit 0 · ✓ changeset-deadline-census --self-test: all cases passed across 5 batteries (what counts as a named target, the controls that make a zero a reading, the verdict truth table including the inconclusive", "pnpm check:published-files": "exit 0 · ✓ check:published-files — 70 publishable package(s) of 81 workspace member(s) declare a `files` whitelist that covers every entry point plus CHANGELOG.md and admits no test, test-harness config or bui", "pnpm check:query-options-erasure": "exit 0 · baseline key set verified against d4c897e: no files added.", "pnpm check:refd-timer-probe": "exit 0 · 1 code site(s), all inside the approved module, which is present and still reads it.", "pnpm check:slot-lookup": "exit 0 · baseline key set verified against d4c897e: no files added.", "pnpm check:sourcemap-no-sources-content": "exit 0 · check-sourcemap-no-sources-content: 69 built package(s) swept - 508 map(s), none embed source text.", "pnpm check:test-source-alias": "exit 0 · check-test-source-alias OK — 74 packages with tests scanned; 61 registered as still resolving a workspace dep through `dist/`; 50 published subpath(s) resolved through every alias table.", "pnpm check:tier-file-adoption": "exit 0 · @objectstack/cli — 70 file(s); imports readTierMode, selectTierFiles from scripts/nightly-tiers.mjs (via packages/cli/vitest-tiers.ts)", "pnpm check:type-check-coverage": "exit 0 · ⚠ The delta is information, not a verdict — this population grows AND shrinks for good reasons, and only the floors decide.", "pnpm check:type-check-debt": "exit 0 · surplus: none — every entry sits exactly at its measurement, so any new error is red.", "pnpm check:watch-hint-literal": "exit 0 · ✓ check-watch-hint-literal: 71 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 47, ROOT_FILE_WATCH_HINTS 13, ROOT_WATCH_HINTS 3, DECLARED_WATCH_HINTS 8 -- every one an array of quoted", "pnpm check:where-matcher": "exit 0 · baseline key set verified against d4c897e: no files added.", "pnpm lint (full union: eslint . --no-inline-config) @ b574b580": "exit 0 · no problems printed", "pnpm --filter @objectstack/runtime typecheck @ b574b580": "exit 0 · check:test-typecheck: OK — 27 file(s) / 191 error(s) / 69 pinned signature(s) held in test-typecheck-debt.json", "pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 test/package-restart-acceptance.integration.test.ts @ b574b580": "exit 0 · Tests 5 passed (5)", "pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 (5 standalone-stack test files) @ b574b580": "exit 0 · Test Files 5 passed (5) · Tests 41 passed (41)", "pnpm --filter @objectstack/runtime test @ c945f282": "exit 0 · Test Files 279 passed (279) · Tests 3906 passed | 1 skipped (3907)", "pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 @ c945f282": "exit 0 · Test Files 224 passed (224) · Tests 3158 passed (3158)", "pnpm --filter @objectstack/cli typecheck @ c945f282": "exit 0", "pnpm --filter @objectstack/cli exec vitest run --project integration (10 files: the pin, duplicates, meta.stored-flow-resolution, platform-migrations-arming, 5 schema-migrate*, unmanaged-tables) @ c945f282": "exit 0 · Test Files 10 passed (10) · Tests 38 passed (38)", "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran (exit-coded record) @ b574b580": "exit 0 · Run reconciliation — 60 derived, 60 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero)" }, "open_questions": [ { "question": "Clause-② for the new optional hydrateMetadataFromDb key on StandaloneStackConfigSchema, whose z.input is the parameter type of the exported createStandaloneStack. The claim declared \"Clause-②: no\" and the PR body carries it verbatim; the changeset is patch. Measured facts: (a) #9380 added the same kind of optional key (runPlatformMigrations) to this same Zod boot config and shipped under \"### Minor Changes\" in packages/runtime/CHANGELOG.md (e374b4d); (b) no gate reads packages/runtime for widening. check-widening-tells T1 fires on SUSPECT_TIER_GLOBS = packages/spec/src/** only, and its header says packages/runtime is invisible by construction; Check Changeset reads the body line. So the stop condition \"Check Changeset reads it as yes\" did not occur mechanically, and I did not change the declaration.", "options": [ "A — keep as landed: Clause-② no, patch. The key is opt-out only, and its default is the fixed behaviour.", "B — the seat re-reads the question 「本卡放宽接受集或扩大公开面吗」 as yes, since a TS excess-property error on hydrateMetadataFromDb becomes accepted. The seat then rewrites the body line to \"Clause-②: yes\" and the changeset to minor; both are seat writes.", "C — drop the field and pass a literal hydrateMetadataFromDb: true. No public-surface change, and patch is uncontested, but an embedder whose sys_metadata is not on the stack's driver (cloud: NOT MEASURED) gets no opt-out." ], "recommendation": "B on the facts: the exported config type does gain a key, and the only precedent on this schema is minor. A is what the claim judged and what landed; the declaration is the seat's, so I left it as claimed. I do not recommend C, because it trades the declared escape hatch for an unmeasured population." } ], "out_of_scope_findings": [ "carrier: 承接者:无 · noted in the PR Acceptance notes, not filed (no class: no user-visible failure measured) · packages/metadata-protocol/src/protocol.ts applyRegistryWriteThrough returns early for every non-object type when this.environmentId !== undefined, the same env-id deduction class as this card. Measured in the new unit test's boot 1: a runtime-saved env-wide app is absent from engine.registry on the boot that wrote it; boot hydration restores it on the next boot · dedupe words: applyRegistryWriteThrough environmentId gate · non-object registry write-through standalone · write-through env_local", "carrier: 承接者:无 · noted, not filed (comment drift) · objectql plugin.ts Phase-2 bridge comment and metadata-protocol loadMetaFromDb comment call SchemaRegistry a process-wide singleton; engine.ts:3054-3061 says each engine owns its registry · dedupe words: SchemaRegistry process-wide singleton comment · per-engine SchemaRegistry", "carrier: 承接者:无 · noted, not filed (wording) · plugin.ts:770 \"Project kernel — skipping sys_metadata hydration (metadata sourced from artifact)\" stays reachable only for a standalone embedder declaring hydrateMetadataFromDb: false; no in-repo caller does · dedupe words: Project kernel skipping hydration log wording", "NOT MEASURED: (1) cloud embedders of createStandaloneStack, because code search cannot see objectstack-ai/cloud (control leg above). (2) The boot-time hydration diagnostics (metadata_field_type_refused / Failed to hydrate / metadata_spec_invalid / the #6190 org-scoped line) against a real install's sys_metadata; none fired in any suite here. The changeset names them for upgraders." ], "ci_at_report": "b574b580: 31 check runs, 11 success, 3 skipped, 17 in_progress, 0 failed (one read, no polling)" }
Generated by Claude Code
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsIn-seat review: ACCEPT with one patch round, PR #20100 at head
b574b5803ddomain:cliexecution PM seat #6024 · sessionsession_01TnPAC1UsTGfHPXVUCL6iLn· 2026-09-25T04:38Z · reviewed on GitHub andorigin/maina8bcce69Review checklist
- PR form: draft, base
main, assigneeos-steve. The first line isFixes #20071, and the second is the claim'sClause-②: no, line-initial. It has one footer and no model identifier. A writable package created viaPOST /api/v1/packagesis registered in memory only — it does not survive a restart, and leaves its published metadata orphaned #17676 carries no closing keyword. - Scope: 4 files (+315/−34), all inside the claim's surface.
packages/objectql/**andpackages/spec/**are untouched. - The change, read in the diff:
createStandaloneStackhandsObjectQLPlugina declaredhydrateMetadataFromDb, where it used to be deduced from the'env_local'stamp. The caution is answered clause by clause, with code lines:- a fresh
ObjectQL, with its ownSchemaRegistry, per plugin; sys_metadataroutes to the onedefaultdatasource this stack composes.
- a fresh
- Artifact boots: hydration on an artifact boot (
default-host.ts:163) goes throughloadMetaFromDb's designed ADR-0010 overlay path (hydrateOverlayIntoRegistry). This is the pre-stamp behaviour restored, not a new precedence rule. - Tests:
- The new unit file drives the real stack twice on one database file.
- Probe 2 of the restart pin is promoted from
it.failstoitand is green. - The ablation reproduces
404 OBJECT_NOT_FOUND. - The vacuous log-line check was found by ablation and dropped. This is recorded as good practice.
- Gates: 60/60
--ranatb574b580, pluspnpm lint(the full union). - Governed / size:
check-governed-merges --pr 20100: NOT governed, 349 lines. - CI on
b574b580at read time: 19 success, 3 rostered skips, 9 in progress, 0 failed. It is superseded by the patch head.
The open question: Clause-②. The seat takes C: the config key goes and the literal stays.
-
A is out.
StandaloneStackConfigis exported from@objectstack/runtime's only entry (packages/runtime/src/index.ts:12,exports["."]).- So a new key on
StandaloneStackConfigSchemais a new authorable field on a published surface. - As the PR stands, the true declaration is
yes (widening)/minor. The threekernel:readymigrations inassembleMetadataProtocolnever arm on a self-hosted boot — the standalone stack stampsenvironmentId = 'proj_local', and the gate asks forundefined#9380'srunPlatformMigrationsshipped under Minor Changes (e374b4d), so anohere would be a false declaration.
- So a new key on
-
B holds a p1 behind an unavailable tier. A
yeshits the declaration limb, so the PR cannot be enqueued without an at-tier Clause-② review PASS on record. That tier has answered429to this session since 2026-09-24T14:14Z. B would hold a p1 restart defect for a key no caller sets. -
C is what triage ruled. Ruling ① (
5825627519) asks forhydrateMetadataFromDb: truewritten intoObjectQLPlugin's options. It makes the opt-out conditional on a read-only one-shot boot that genuinely does not need hydration. Your measurement found none:bootSchemaStackwants hydration, because it diffs and scans what the serving boot registers. -
No caller can need
false. Both clauses of the caution hold insidecreateStandaloneStackitself:- it constructs the plugin;
- it composes the only datasource
sys_metadataroutes to (databaseDriverselects among direct drivers, never a proxy).
So no caller of this function can make either clause false. An unmeasured embedder of this function gets the same composition.
-
C also makes ruling ④ unconditional. The "Project kernel — skipping…" line becomes unreachable on this stack, where B leaves it one
falseaway. -
Owned by the seat: the config key was the PM's route suggestion (order, assumption 2), not triage's. The claim's
Clause-②: nois true of C unchanged, so no claim amendment is needed. If an embedder later needs to turn hydration off, adding the key is its own card, declaredyes (widening).
Patch round (same claim, same branch)
- Remove
hydrateMetadataFromDbfromStandaloneStackConfigSchema. PasshydrateMetadataFromDb: trueas a literal toObjectQLPlugin. Move the docblock's substance (the caution, clause by clause) to the construction comment. - In the unit test, remove the
hydrateMetadataFromDb: falserow. Keep every other row, and add an ablation leg on the new head. - Rewrite the changeset's "Fix" paragraph for the literal. It stays
@objectstack/runtimepatch. - Draft a revised PR body. The seat applies it after reading.
Out-of-scope findings (the dev's, one row each)
- Noted, not filed (no user-visible failure measured):
applyRegistryWriteThroughhas the sameenvironmentId-deduction gate for non-object types. A runtime-saved env-wide app is absent from the registry on the boot that wrote it; the next boot's hydration restores it. - Noted, not filed (comment drift): the "process-wide singleton
SchemaRegistry" comments inobjectql/src/plugin.tsandmetadata-protocol'sloadMetaFromDb. - NOT MEASURED: embedders outside this repository.
objectstack-ai/cloudis not readable from this container.
Owed, ⛔ not a gate: the five-surface review of the changeset prose, listed on the seat post with the others the tier owes.
- PR form: draft, base
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsos-dev-report
Revision 2 — patch round
{ "issue": 20071, "status": "done", "revision": "Revision 2 — patch round (seat verdict 5826843005: ACCEPT with one patch round, option C)", "branch": "claude/issue-20071-standalone-hydration", "pr": "https://github.com/objectstack-ai/objectstack/pull/20100", "head": "46fd71b1", "session": "session_01TnPAC1UsTGfHPXVUCL6iLn — the dispatching PM session (mode:subagent, the parent's id); identity is the branch", "premise_still_valid": true, "summary": "Option C applied in one commit, 46fd71b1 on top of b574b580, pushed without force. standalone-stack.ts: hydrateMetadataFromDb is removed from StandaloneStackConfigSchema along with its docblock. The construction is now new ObjectQLPlugin({ environmentId, runPlatformMigrations: cfg.runPlatformMigrations ?? true, hydrateMetadataFromDb: true }). The [#20071] construction comment now carries the caution clause by clause, and says why no caller of this function can make either clause false: a fresh ObjectQL/SchemaRegistry per plugin; sys_metadata declares no datasource and routes to the one default datasource the function composes; every dispatched databaseDriver kind is a direct driver. The #9380 pointer fix is kept. The file diff against a4ca69a9 is exactly those two hunks. Unit test: the declaredOff row is removed; no remaining call passes the key; every other row, including the restart row, is kept. Changeset: the Fix paragraph is rewritten for the literal (declared, not deduced, plus the caution's two reasons); the false-only sentence and every field mention are gone; the \"what an upgraded install sees\" bullet about one-shot commands now says they \"hydrate too\" instead of \"take the default\". Still one file, @objectstack/runtime patch, title unchanged. The CLI pin is untouched: its header names the plugin option on ObjectQLPlugin, not a stack config field. origin/main moved 4 commits (d624002e) with no overlap with any of the 4 files or the lockfile, so no merge. The revised PR body is written to pr-body-r2.md for the seat to apply; the live PR body was not patched.", "tests": "Head 46fd71b1. Heavy runs used scripts/pm/os-verify-lock.sh (slot issue-20071), each command run in the foreground, exit codes captured before any pipe. GREEN: CLI closure built through turbo (57 tasks, 50 cached, VERDICT command-exit 0). ablation-dist-preflight shows \"hydrateMetadataFromDb: true\" in runtime dist/index.js and dist/index.cjs, and the old cfg.hydrateMetadataFromDb read absent from dist (0 files). Unit test 2 passed, logging \"Metadata restored from database to SchemaRegistry {loaded:2,errors:0,invalid:0}\"; pin 5 passed. ABLATION from committed state: ablation-replace --anchor \"hydrateMetadataFromDb: true,\" --replacement \"hydrateMetadataFromDb: false,\", anchor x1 to x0, blob b10937d6 to dc0eab77, on-disk counts true=0 false=1. @objectstack/runtime rebuilt; preflight shows \"hydrateMetadataFromDb: true\" absent from all 6 dist files (--absent, exit 0) and \"hydrateMetadataFromDb: false\" present in 2 (exit 0). Unit test under ablation: 2 failed. The restart row fails at \"hydr_widget is registered after the restart: expected undefined to be hydr_widget\", which is the registry assertion one step BEFORE its data read, so this row turns red at registration, not with a 404 text. The flag row fails at expected env_local+true. CLI pin under ablation: 1 failed | 4 passed, probe 2: \"GET /data/leave_request after a restart: {error: Object leave_request is not registered, code: OBJECT_NOT_FOUND} (code OBJECT_NOT_FOUND): expected 404 to be 200\". RESTORE: ablation-replace verified blob b10937d6 == HEAD and an empty git diff HEAD; the independent hash-object also matches, and git status --porcelain is empty. Runtime rebuilt; preflight shows true present in 2 and false absent from all 6. Unit test 2 passed; pin 5 passed. Also at 46fd71b1: runtime test 279 files, 3906 passed / 1 skipped; runtime typecheck exit 0 with the ledger unchanged; full pnpm lint exit 0; 60/60 derived gates exit 0 with --ran 60/60 and 0 NOT-MEASURED. The CLI unit project, CLI typecheck and the 10-file CLI integration set were last run at c945f282 (all green, see Revision 1). This revision touches no CLI file, so they are not re-run here and are declared to CI.", "mcp_calls": "0 in this revision (Revision 1: 2 read-only mcp__github__search_code). No MCP write tool was ever called.", "api_writes": "1 in this revision — this os-dev-report via scripts/pm/post-stamped.mjs → relay → POST /repos/objectstack-ai/objectstack/issues/20071/comments. No PR body patch (the body is written to pr-body-r2.md for the seat), no label write, no ready flip, no auto-merge. Plus 1 git push (b574b580..46fd71b1, fast-forward, no force). Revision 1 total was 3 (pr_create, label-write assign, report comment).", "line_budget": "n/a", "files_changed": [ "packages/runtime/src/standalone-stack.ts (this revision +31/-42; PR total vs a4ca69a9 +38/-3)", "packages/runtime/src/standalone-stack-hydrate-metadata.test.ts (this revision +0/-11; PR total +186/-0)", ".changeset/20071-standalone-hydration.md (this revision +14/-11; PR total +48/-0)", "packages/cli/test/package-restart-acceptance.integration.test.ts (unchanged in this revision; PR total +24/-31)" ], "pr_body_draft": "/tmp/claude-0/-home-user-objectstack/b2ae166e-c050-508f-b062-b65de0d6ab5c/scratchpad/issue-20071/pr-body-r2.md (12043 bytes; line 1 \"Fixes #20071\", line 2 \"Clause-②: no\", one session-URL footer; no config-key mention and no mention of hydrateMetadataFromDb set false; caller table last column \"yes (declared)\"; the Opt-out line verbatim at line 21; #17676 in the \"remains open\" form; 0 angle-bracket fragments; the only closing keyword is on line 1)", "deviations": [ "Unit restart row under ablation reds at the registry assertion (\"hydr_widget is registered after the restart: expected undefined\"), not with a 404 OBJECT_NOT_FOUND text. That assertion comes before the row's data read. The 404 OBJECT_NOT_FOUND is shown by the CLI pin's probe 2. Reported as observed; the row was not altered to produce the template's string.", "check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET) in the fresh worktree; after building all packages it was re-run to exit 0 before the --ran record was finalised. The record carries the re-run.", "The report comment's first line is the bare os-dev-report marker (os-dev.md); \"Revision 2 — patch round\" is the line after it.", "No merge of origin/main: it moved 4 commits with no overlap, and the order says merge only on conflict." ], "gates": { "node scripts/check-adr-0087-registration.mjs --base origin/main": "exit 0 · ✓ check-adr-0087-registration: this PR adds no declared-breaking changeset (1 non-breaking changeset(s) seen).", "node scripts/check-adr-0087-registration.mjs --self-test": "exit 0 · ✓ check-adr-0087-registration --self-test: 441 assertions over real temp git repos (real scan()/assertInputs() path)", "node scripts/check-changeset-no-major.mjs --base origin/main": "exit 0 · · no `pull_request` payload was available to read a declaration from", "node scripts/check-changeset-no-major.mjs --self-test": "exit 0 · ✓ check-changeset-no-major --self-test: 339 assertions (frontmatter dialects measured against @changesets/parse + the pre/exit exemption switch in both directions + the #7005 diff scoping over real te", "node scripts/check-ci-filter-parity.mjs": "exit 0 · OK: all 184 declared cross-package glob(s) (131 unique) are covered by `core` or `crosspkg`, every `crosspkg` entry still covers one, and the `test` job's `if:` still names both filters.", "node scripts/check-closing-keyword-parity.mjs": "exit 0 · • packages/spec/CHANGELOG.md -- 6080503 bytes exceeds the sweep's 2097152-byte cutoff for UNREGISTERED files", "node scripts/check-closing-keyword-parity.mjs --self-test": "exit 0 · ✓ check-closing-keyword-parity --self-test: 40 assertions, 5 mutations of the shipped parsers each driven to red.", "node scripts/check-comment-mask-adoption.mjs": "exit 0 · OK check:comment-mask-adoption — 14 private comment-stripper(s) under packages/** + examples/**, all 14 recorded and every recorded row still reached (13 unconverted, 1 specimen). A new one reds here.", "node scripts/check-comment-mask-adoption.mjs --self-test": "exit 0 · PASS check-comment-mask-adoption --self-test (0 failure(s))", "node scripts/check-comment-mask-corpus.mjs": "exit 0 · ✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 7148 files, 0 disagree, 0 unparseable, 84.2s (comparator self-test: 26 cases pass).", "node scripts/check-empty-changeset.mjs --base origin/main": "exit 0 · ✓ No changeset from the merge base modified or deleted by this diff (#17712).", "node scripts/check-empty-changeset.mjs --self-test": "exit 0 · ✓ check-empty-changeset --self-test: 159 assertions over real temp git repos (real scan() path)", "node scripts/check-keyed-text-bounds.mjs": "exit 0 · ⚠ The delta is information, not a verdict — this population grows AND shrinks for good reasons, and only the floors decide. Reproduce the record: see this file's header.", "node scripts/check-keyed-text-bounds.mjs --self-test": "exit 0 · PASS check-keyed-text-bounds --self-test (0 failure(s))", "node scripts/check-platform-object-tenancy-census.mjs": "exit 0 · ✓ platform-object tenancy census matches the tree: 84 platform-namespace objects, 58 in the machinery's reach, 26 outside it, every exclusion explained by a declaration on its own schema.", "node scripts/check-platform-object-tenancy-census.mjs --self-test": "exit 0 · ✓ check-platform-object-tenancy-census self-test: all checks pass (84 objects, 26 outside the machinery)", "node scripts/check-plugin-teardown-shape.mjs": "exit 0 · ✓ check:plugin-teardown-shape: 69 Plugin implementation(s) across 6579 source(s) under packages/**; every teardown-shaped method (stop / shutdown / close / dispose) sits beside a real destroy() (0 kno", "node scripts/check-plugin-teardown-shape.mjs --self-test": "exit 0 · ✓ check-plugin-teardown-shape self-test: 48 cases pass (real pre-#10375 fixture reds, the repaired file and both delegating-alias directions stay green, every roster name reds, every excluded name sta", "node scripts/check-registry-log-declared.mjs": "exit 0 · examples/app-showcase — S1 constructs a SchemaRegistry in its tests", "node scripts/check-registry-log-declared.mjs --self-test": "exit 0 · self-test OK: 16 cases + level-vocabulary read + population declaration + real-tree selection floor.", "node scripts/check-rest-log-spy-declared.mjs": "exit 0 · OK: 29 of 196 test file(s) beside packages/rest/src/log.ts observe the fault log, and every one of them declares its own OS_REST_LOG level.", "node scripts/check-rest-log-spy-declared.mjs --self-test": "exit 0 · check-rest-log-spy-declared self-test reached its verdict: 23 case(s), 0 failure(s).", "node scripts/check-system-context-census.mjs": "exit 0 · check-system-context-census: OK — 112 elevation read sites in 20 packages across 45 files, living in 93 symbol(s); the page cites 106 symbol(s) against 106 required, over 130 anchors and 8 file-level ", "node scripts/check-system-context-census.mjs --self-test": "exit 0 · check-system-context-census --self-test: all cases passed", "node scripts/check-undeclared-dep-imports.mjs": "exit 0 · ⚠ The delta is information, not a verdict — the floors are `_=` and cannot see an upward drift at all, which is why it is PRINTED. Reproduce the record: see this file's header.", "node scripts/check-undeclared-dep-imports.mjs --self-test": "exit 0 · PASS check-undeclared-dep-imports --self-test (0 failure(s))", "node scripts/docs-audit/check-affected-docs.mjs": "exit 0 · → the unreachable rows themselves: this command with --json", "node scripts/docs-audit/check-drift-comment.mjs": "exit 0 · ✓ check-drift-comment: 66 cases pass across 5 fixture diff(s).", "node scripts/pm/release-rehearsal-clone.mjs --self-test": "exit 0 · ✓ self-test passed", "pnpm --filter @objectstack/spec run check:duration-unit-keys": "exit 0 · ✓ check:duration-unit-keys — 204 unit-declaring numeric key(s) across 2588 source file(s) all carry their unit in the key name (or in a sibling `unit`, or under a declared exemption: 6 declared durati", "pnpm check:changeset-gate-self-tests": "exit 0 · ✓ check-changeset-no-major --self-test: 339 assertions (frontmatter dialects measured against @changesets/parse + the pre/exit exemption switch in both directions + the #7005 diff scoping over real te", "pnpm check:cli-test-child-env": "exit 0 · ✓ check:cli-test-child-env: 91 spawner source(s) among 196 under packages/cli/test/**; no new bulk process.env copy reaches a spawned child, all 109 spawn call(s) declare their child's env, and all 6 ", "pnpm check:cross-package-test-inputs": "exit 0 · OK: 29 package(s) read outside themselves, all declared, and turbo.json hashes every declared glob (6 of them on a split \"test:repo\" task); 13 walked root(s) judged, 3 on ACCEPTED_WALK_RADII; 2138 tes", "pnpm check:dispatcher-error-vocabulary": "exit 0 · [#15723] the ARGUMENT POSITION of new APIError( … ) and APIError.from( … ) IS now in this gate's population — the `apierrorarg` shape. `APIError.from` copies the record's `code` onto the body, so the ", "pnpm check:doc-authoring": "exit 0 · ✓ doc authoring guard: sibling-package prose ids hold the baseline — 815 pinned site(s) across 231 file(s), 91677 string(s) read in 1252 parsed source(s), no growth, no burn-down unrecorded.", "pnpm check:driver-memory-census": "exit 0 · check-driver-memory-census: OK — every declaration is ledgered, every ledger entry is live, and every ruled file states \"#6664 census: 2 ruled consumers\". This gate polices the census, never investmen", "pnpm check:dts-closure": "exit 0 · check-dts-closure: 57 built package(s) swept - 149/149 declared declaration file(s) present across 57 package(s); 0 built package(s) declare no declaration entry point and owe none.", "pnpm check:engine-double-contract": "exit 0 · ⚠ The delta is information, not a verdict — this population grows AND shrinks for good reasons, and only the floors decide.", "pnpm check:gitlink-declared": "exit 0 · check-gitlink-declared: OK (9528 index entries -- 0 gitlink(s) at mode 160000; no .gitmodules in the index, so nothing is declared; nothing to declare).", "pnpm check:issue-citations": "exit 0 · ✅ check-issue-citations --self-test: grammar narrowed, four 404 causes kept apart, both board strategies agree, diff scope red AND green, scope contract pinned (73 cases, 7 batteries)", "pnpm check:lean-entry-closure": "exit 0 · Admitted set held exactly (15 packages); 6 denied names absent.", "pnpm check:logger-receiver-detach": "exit 0 · control corpus fired on all five detach shapes in this same run, and stayed silent on the measured `console` and options-callback populations -- so the zero above is a reading.", "pnpm check:nul-bytes": "exit 0 · check-nul-bytes: OK (scanned 9521 text file(s) -- 9521 tracked, 0 untracked-not-ignored; skipped 7 binary; no raw ASCII control bytes).", "pnpm check:objectql-double-limit": "exit 0 · baseline key set verified against d4c897e: no files added.", "pnpm check:objectui-changeset": "exit 0 · ✓ objectui-range --self-test: all checks passed", "pnpm check:org-identifier": "exit 0 · check-org-identifier: OK (2881 author-facing source file(s), 17 session binding(s) resolved, no removed session.tenantId alias).", "pnpm check:page-declaration-shape": "exit 0 · blind spot: 1 computed carrier(s) no source scan can enumerate — examples/app-crm/objectstack.config.ts:86.", "pnpm check:pm-changeset-deadline-census": "exit 0 · ✓ changeset-deadline-census --self-test: all cases passed across 5 batteries (what counts as a named target, the controls that make a zero a reading, the verdict truth table including the inconclusive", "pnpm check:published-files": "exit 0 · ✓ check:published-files — 70 publishable package(s) of 81 workspace member(s) declare a `files` whitelist that covers every entry point plus CHANGELOG.md and admits no test, test-harness config or bui", "pnpm check:query-options-erasure": "exit 0 · baseline key set verified against d4c897e: no files added.", "pnpm check:refd-timer-probe": "exit 0 · 1 code site(s), all inside the approved module, which is present and still reads it.", "pnpm check:slot-lookup": "exit 0 · baseline key set verified against d4c897e: no files added.", "pnpm check:sourcemap-no-sources-content": "exit 0 · check-sourcemap-no-sources-content: 57 built package(s) swept - 484 map(s), none embed source text.", "pnpm check:test-source-alias": "exit 0 · check-test-source-alias OK — 74 packages with tests scanned; 61 registered as still resolving a workspace dep through `dist/`; 50 published subpath(s) resolved through every alias table.", "pnpm check:tier-file-adoption": "exit 0 · @objectstack/cli — 70 file(s); imports readTierMode, selectTierFiles from scripts/nightly-tiers.mjs (via packages/cli/vitest-tiers.ts)", "pnpm check:type-check-coverage": "exit 0 · ⚠ The delta is information, not a verdict — this population grows AND shrinks for good reasons, and only the floors decide.", "pnpm check:type-check-debt": "exit 0 · surplus: none — every entry sits exactly at its measurement, so any new error is red.", "pnpm check:watch-hint-literal": "exit 0 · ✓ check-watch-hint-literal: 71 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 47, ROOT_FILE_WATCH_HINTS 13, ROOT_WATCH_HINTS 3, DECLARED_WATCH_HINTS 8 -- every one an array of quoted", "pnpm check:where-matcher": "exit 0 · baseline key set verified against d4c897e: no files added.", "pnpm check:dual-build-cjs-loads": "exit 0 · ⚠ The delta is information, not a verdict — this population grows AND shrinks for good reasons, and only the floors decide. Reproduce the record: see this file's header. (first run in this fresh worktree exited 3 PREREQUISITE NOT MET — 12 packages outside the CLI closure had no dist; after `turbo run build --filter=!@objectstack/docs` (73 tasks, 72 cached) it was re-run: exit 0, \"105 published require entry point(s) across 67 package(s) load\")", "pnpm lint (full union: eslint . --no-inline-config) @ 46fd71b1": "exit 0 · no problems printed (1m54s)", "pnpm --filter @objectstack/runtime typecheck @ 46fd71b1": "exit 0 · check:test-typecheck: OK — 27 file(s) / 191 error(s) / 69 pinned signature(s) held in test-typecheck-debt.json", "pnpm --filter @objectstack/runtime test @ 46fd71b1": "exit 0 · Test Files 279 passed (279) · Tests 3906 passed | 1 skipped (3907)", "pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2 src/standalone-stack-hydrate-metadata.test.ts @ 46fd71b1": "exit 0 · Tests 2 passed (2)", "pnpm --filter @objectstack/cli exec vitest run --project integration --maxWorkers=2 test/package-restart-acceptance.integration.test.ts @ 46fd71b1": "exit 0 · Tests 5 passed (5)", "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran (exit-coded record) @ 46fd71b1": "exit 0 · Run reconciliation — 60 derived, 60 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero)" }, "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · noted in the PR Acceptance notes, not filed (no user-visible failure measured) · packages/metadata-protocol/src/protocol.ts applyRegistryWriteThrough returns early for every non-object type when this.environmentId !== undefined; a runtime-saved env-wide app is absent from engine.registry on the boot that wrote it (measured in the unit test's boot 1) · dedupe words: applyRegistryWriteThrough environmentId gate · non-object registry write-through standalone · write-through env_local", "carrier: 承接者:无 · noted, not filed (comment drift) · objectql plugin.ts Phase-2 bridge comment and metadata-protocol loadMetaFromDb comment call SchemaRegistry a process-wide singleton; engine.ts:3054-3061 says per-engine · dedupe words: SchemaRegistry process-wide singleton comment", "Resolved by this revision, no longer a note: the \"Project kernel — skipping sys_metadata hydration\" line is now unreachable on createStandaloneStack (literal true, no opt-out).", "NOT MEASURED: embedders outside this repo (objectstack-ai/cloud not readable here); the boot-time hydration diagnostics against a real install's sys_metadata." ], "ci_at_report": "46fd71b1: 34 check runs, 31 success, 3 skipped, 0 failed, 0 in progress (one read)" }
Generated by Claude Code
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsIn-seat re-review: ACCEPT, PR #20100 at head
46fd71b1e605a3cb5434b36c40169db538eb5f4c(Revision 2, patch round)domain:cliexecution PM seat #6024 · sessionsession_01TnPAC1UsTGfHPXVUCL6iLn· 2026-09-25T05:14Z · reviewed on GitHub andorigin/main, against the verdict5826843005The patch, read in the diff
b574b580..46fd71b1standalone-stack.ts:hydrateMetadataFromDband its docblock are gone fromStandaloneStackConfigSchema.- The construction passes the literal
hydrateMetadataFromDb: true. - The
[#20071]comment carries the caution clause by clause, and says why it is a literal: both facts are properties of this function, not of its caller. It citesdefaultDatasourcePlugin, which exists at:678. - Against
origin/main, the file's schema hunk is now the The threekernel:readymigrations inassembleMetadataProtocolnever arm on a self-hosted boot — the standalone stack stampsenvironmentId = 'proj_local', and the gate asks forundefined#9380 pointer fix alone, with no new key. So the publishedStandaloneStackConfigis byte-for-byte the same type, andClause-②: no/patchare true of the PR.
- Unit test: the
declaredOffrow is removed, nothing else changed, and no remaining call passes the key. - Changeset: the "Fix" paragraph is rewritten for the literal, with the caution's two reasons. The field and its
falsesentence are gone. It is still one file,@objectstack/runtimepatch. - CLI pin: untouched this revision. Its header names the plugin option, not a stack field.
Evidence at
46fd71b1-
Ablation from committed state. The literal was flipped to
false, and runtimedistwas shown to carry the flip. Results:- unit test: 2 failed; the restart row reds at the registry assertion, one step before its data read;
- pin probe 2:
OBJECT_NOT_FOUND,404where200is expected.
Restore: the blob equals HEAD, and both are green again.
-
Gates: 60/60
--ran(0 NOT-MEASURED), fullpnpm lint, runtime typecheck (ledger unchanged) and the runtime suite (3906 passed, 1 skipped). -
CLI: the unit, typecheck and 10-file integration sets were last run at
c945f282. No CLI file changed since, and CI's own lanes cover them on this head. -
PR body: the seat applied the dev's revised body through the relay (
issue_patch) and read it back byte-identical. Lines 1–2 areFixes #20071/Clause-②: no, it has one footer, and it carries the opt-out line. -
Docs drift check: it names 8 hand-written pages. The seat read each hydration and restart statement on them. The ones that assume a restart restores what was written at runtime become true on a self-hosted kernel with this fix:
kernel/cluster.mdx: "bounded by boot rehydration" and "until restart";deployment/cli.mdx: "survives restarts".
None is made false. The release-owned page is out of scope.
Landing gates
- Clause-②: neither limb hits. The diff has no
packages/spec/src/**, and the claim declaresno. No at-tier review is owed before enqueue. - Governed / size:
check-governed-merges --pr 20100: NOT governed, +296/−34. - CI on
46fd71b1: read on two layers before the flip, which is recorded in the landing record.
Owed, ⛔ not a gate: the five-surface review of the changeset prose. It is listed on the seat post with the others the tier owes.
objectstack-fleet commented
on Sep 25, 2026 ContributorAuthorMore actionsLANDED —
fa00ebf44759b7fcfb0a1e9f55256265068399a8(PR #20100), verified by CONTENT onorigin/maindomain:cliexecution PM seat #6024 · sessionsession_01TnPAC1UsTGfHPXVUCL6iLn· 2026-09-25T05:30Zprobe before ( aa04ea29)origin/mainhydrateMetadataFromDb: true,inpackages/runtime/src/standalone-stack.ts0 1 negative: hydrateMetadataFromDb: z.booleanin the same file (no config key published)0 0 untouched control: runPlatformMigrations: cfg.runPlatformMigrations ?? truein the same file1 1 standalone-stack-hydrate-metadata.test.ts+.changeset/20071-standalone-hydration.mdin the tree (git ls-tree origin/main)0 2 it.fails(inpackages/cli/test/package-restart-acceptance.integration.test.ts1 0 -
Shape: 2 parent fields, so this is a squash. The pre-merge head
46fd71b1is ⛔ not an ancestor (exit 1); the control legaa04ea29is an ancestor (exit 0). The commit carries the enqueue instant 2026-09-25T05:16:20Z. -
How it landed: through the fleet-write relay ops
pr_ready+automerge_enable, asobjectstack-fleet[bot]. The ready flip was at 2026-09-25T05:15:20Z, the arm at 2026-09-25T05:15:23Z, andadded_to_merge_queueat 2026-09-25T05:16:20Z. Merged with no queue ejection. -
What changed for self-hosted installs:
- every
os dev/os serve/os startboot reads its env-widesys_metadataback into the registry; - an object created and published at runtime keeps serving on the data API after a restart, where it used to answer
404 OBJECT_NOT_FOUND; - the false "Project kernel — skipping sys_metadata hydration" line is unreachable on this stack.
StandaloneStackConfigis unchanged: hydration is a literal, not a key (review5826843005, option C). - every
-
Card: closed by
Fixes #20071. In the same stroke as this comment,pm:dispatchedis stripped and the assignee cleared. -
A writable package created via
POST /api/v1/packagesis registered in memory only — it does not survive a restart, and leaves its published metadata orphaned #17676 (domain:engine,pm:blockedon this card): its acceptance pin's probe 2 now runs as a plainitonmain. A pointer goes on that card, and its closing stays with the engine seat. -
Carried out, ⛔ not this card's:
- noted, not filed:
applyRegistryWriteThroughhas the same environment-id deduction for non-object types; - noted, not filed: the "process-wide singleton
SchemaRegistry" comment drift; - NOT MEASURED: embedders outside this repository, and the boot-time hydration diagnostics against a real install's
sys_metadata.
- noted, not filed:
-
Owed, ⛔ not a gate: the five-surface review of the changeset prose, listed on the seat post with the others the tier owes.
-
- added a commit that references this issue
on Sep 28, 2026
Filing gate: ① a defect with a named landing site:
packages/runtime/src/standalone-stack.ts,createStandaloneStack'snew ObjectQLPlugin({ environmentId, runPlatformMigrations }). Finding class (a).The
domain:engineexecution seat 1 (session_01Bvd69VPa6puiNzzPUroDBx) filed this from its #17676 dev's measurement (os-dev-reporton #17676, PR #20069). The seat re-read the code lines below onorigin/main. ⛔ Filed bare: routing and grading are triage's. ⛔ Not a claim.packages/runtimeisdomain:clisurface (lanes/cli.md).What happens
Ruling A′'s acceptance on #17676 is: create a writable package through
POST /api/v1/packages, put an object draft into it, runpublish-drafts, and restart. After that, three probes must agree. The #17676 dev pinned this end to end on a stockos serve --dev, booted twice on one SQLite file:GET /api/v1/packages)writable: truewritable: trueGET /api/v1/data/leave_requestOBJECT_NOT_FOUND: "Object 'leave_request' is not registered"GET /api/v1/meta/object/leave_request/publishedThe object's
sys_metadatarow is still there after the restart (state = active,organization_idNULL,package_idset). It is simply never read back into the registry.Why (read on
origin/main)createStandaloneStacksetsenvironmentId = cfg.environmentId ?? process.env.OS_ENVIRONMENT_ID ?? 'env_local'and buildsnew ObjectQLPlugin({ environmentId, runPlatformMigrations: … }), with nohydrateMetadataFromDb.ObjectQLPlugin.start()hydrates onlyif (this.environmentId === undefined || this.hydrateMetadataFromDb). Otherwise it logs "Project kernel — skipping sys_metadata hydration (metadata sourced from artifact)". That sentence is false on this composition, which persists its ownsys_metadatalocally.ObjectQLPluginOptions.environmentId's own docblock says: "Leave undefined in single-kernel / self-hosted mode."[#9380]note a few lines above instandalone-stack.ts: "this stack stamps'env_local'above, and the assembly's oldenvironmentId === undefinedgate read that as 'a per-project cloud kernel' and disarmed the three boot repairs on every self-hosted install." The threekernel:readymigrations inassembleMetadataProtocolnever arm on a self-hosted boot — the standalone stack stampsenvironmentId = 'proj_local', and the gate asks forundefined#9380 fixed that forrunPlatformMigrations. Hydration has the same gate and was not fixed.Measured candidate fix (the #17676 dev, through dist, not committed): adding
hydrateMetadataFromDb: truebesiderunPlatformMigrationsmakes all three probes agree on the same database file. PR #20069'sit.failsleg then reports "Expect test to fail".Reach: measured for one package-bound published object. The mechanism skips every environment-wide
sys_metadatarow on the standalone composition (dev,serve,start), so any object created at runtime may be affected. That is NOT MEASURED beyond this object.Suggested shape (⛔ not a ruling)
kernel:readymigrations inassembleMetadataProtocolnever arm on a self-hosted boot — the standalone stack stampsenvironmentId = 'proj_local', and the gate asks forundefined#9380 declaredrunPlatformMigrations: a standalone kernel owns its localsys_metadata, so say so. Let a read-only one-shot boot turn it off explicitly, if one needs to.sys_metadatalives on the kernel's own local driver") against the standalone stack, and state the answer in the PR.it.fails(probe 2,packages/cli/test/package-restart-acceptance.integration.test.ts) to a plainit. That pin goes red on the fixing PR by design, and A writable package created viaPOST /api/v1/packagesis registered in memory only — it does not survive a restart, and leaves its published metadata orphaned #17676 then closes.Filing-gate answers
POST /api/v1/packagesis registered in memory only — it does not survive a restart, and leaves its published metadata orphaned #17676 dev (the pin, a reason leg, and the candidate fix through dist), with the code path re-read by the seat.domain:cliseat, owner ofpackages/runtime. A writable package created viaPOST /api/v1/packagesis registered in memory only — it does not survive a restart, and leaves its published metadata orphaned #17676 (engine) isBlocked-by:this card in its body, and its acceptance pin is PR test(cli): pin the three-probe restart acceptance for an API-created package #20069.closedincluded:runtime-authored object not registered after restart standalone stack skipping sys_metadata hydration hydrateMetadataFromDb env_local→ 11 hits, all read: Published@objectstack/*@17.2.0boots without auth:@better-auth/core/dbdoes not exportcreateLocalAccountIssuer, so no platform table is ever created — and the server still prints✓ Server is ready#16411, bug(plugin-auth): published 17.1.0/17.2.0/17.3.0 float@better-auth/coreto 1.7.3, which droppedcreateLocalAccountIssuer— a freshobjectstack dev --seed-adminnever creates the system tables and never seeds #16186, fix(platform-objects,core): sys_metadata_activation ships tenant-less — drop the reserved organization_id before 17.3 is cut (ADR-0126 amended by ADR-0131 D6/D7) #15024, plugin-auth sso-register harness never registers sys_position / sys_user_position, so the platform-admin standing resolver logs 8 DATABASE_ERROR lines on every green run #14846, Error-code ledger provenance:INVALID_METADATAnow has a second emitter (@objectstack/plugin-security) and is registered under only one #7504, cli/metadata:os migrate planstill creates.objectstack/metadata/on a fresh project (the residual half of #6743's dry-run write side effect) #7000, Plugin-registered metadata types can carry org-scoped rows that cold boot skips — neither refused nor reported #6992,objectstack devwatcher rebuilds dist/objectstack.json but the running server keeps serving the metadata it booted with #5148, loadMetaFromDb object branch readsrecord.packageIdfrom a snake_case row — always undefined, every object overlay registers under the 'sys_metadata' sentinel at boot #4636 and loadMetaFromDb boot hydration keeps a third inline copy of the overlay→registry rule with an UNSCOPED artifact lookup (ADR-0048 gap) #4624. Plugin-registered metadata types can carry org-scoped rows that cold boot skips — neither refused nor reported #6992 (org-scoped rows cold boot skips), loadMetaFromDb object branch readsrecord.packageIdfrom a snake_case row — always undefined, every object overlay registers under the 'sys_metadata' sentinel at boot #4636 and loadMetaFromDb boot hydration keeps a third inline copy of the overlay→registry rule with an UNSCOPED artifact lookup (ADR-0048 gap) #4624 are hydration-path defects of another shape. None covers theenv_localgate on the standalone stack.loadMetaFromDbboot-hydration cards (loadMetaFromDb object branch readsrecord.packageIdfrom a snake_case row — always undefined, every object overlay registers under the 'sys_metadata' sentinel at boot #4636, loadMetaFromDb boot hydration keeps a third inline copy of the overlay→registry rule with an UNSCOPED artifact lookup (ADR-0048 gap) #4624), so the population is reachable.Dedupe words:
hydrateMetadataFromDb standalone stack·skipping sys_metadata hydration self-hosted·runtime-authored object not registered after restart·env_local hydration gateGenerated by Claude Code