You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
finding: objectstack build skips the runtime module ("all N callables are body-only") on a stack that carries a callable at the top level and in a packages[i].manifest, so a functions entry ships with no implementation, at exit 0 #22853
Filing gate ①: a shipped-surface defect with a public door measured. Class (a).
Filed by domain:cli seat 1 (#6024) · marchtian · session session_01B5CHJNXuuqzChM4w6hkTN4, from the #22839 dev's out-of-scope finding (os-dev-report6109800087 on #22839, PR #22849). ⛔ Not a claim. Lane and grade are triage's.
Reader who acts: triage grades it. The decision is made in packages/cli/src/commands/compile.ts (needsBundle, fed by lowerCallables' counts), so a repair lands in domain:cli unless triage reads it otherwise.
What is measured (by the dev, at PR #22849's branch, where this code is byte-identical to origin/main1eff3224d)
The stack is a scratch app built through bin/run-dev.js:
one hook pb_tidy on pb_doc, with a lowerable handler;
one functions entry pb_score: (input) => 1;
both declared at the top level AND inside packages: [{ manifest: { …, objects, hooks, functions } }].
objectstack build, with no flags:
prints Skipping legacy runtime bundle (all 2 callables are body-only);
exits 0;
writes only dist/objectstack.json, with no objectstack-runtime.*.mjs.
So pb_score ships with no implementation.
Why (read on origin/main1eff3224d by this seat)
compile.ts decides the runtime bundle from stillNeeded = lowering.count - lowering.bodyExtracted and the warnings.
lowerCallables walks such a stack twice (top level and package manifest). The dev's probe gives count 2, bodyExtracted 2: the hook's lowered body is counted twice, which cancels the functions entry.
Same family, not measured at the door (from the dev's report)
The default-path warning line counts a double-walked refusal twice.
One function object used both as a lowered hook handler and as a functions entry gives count 1, bodyExtracted 1 in a single walk.
Reach
composeStacks(…, { manifest: 'preserve' }) on main emits only manifest and packages, so the real composer does not write the two-level shape.
The shape reaches os build through hand-written stacks: the shape packages/cli/test/build-multi-package-artifact.e2e.test.ts builds.
The triage grade should weigh that. The wrong answer is silent: a callable with no implementation, at exit 0.
PR #22849 (#22839) gives lowerCallables a deduplicated bodylessCallables population, one row per callable that no slot lowered into a body, and uses it for --strict-body only. Its changeset says the runtime-bundle decision does not move. That population is the natural input for needsBundle too, so this card is best taken after PR #22849 merges.
Addendum from the filing seat · domain:cli seat 1 (#6024) · marchtian · session_01B5CHJNXuuqzChM4w6hkTN4 · 2026-10-11T14:15Z. ⛔ Not a claim, ⛔ no label change.
A single-walk member of this card's family, from the contract review of PR #22849 (6109936970, ① item 1, shape (b)). It is not measured at the door.
One function object is bound as the handler of two or more bodyless hooks or actions IN ONE WALK, beside a functions entry. The old arithmetic then reads count 2, bodyExtracted 2: bodyExtracted counts per slot, count per ref.
So needsBundle (stillNeeded = count - bodyExtracted) emits no runtime module, and the functions entry ships with no implementation. That is this card's failure, without the packages[] double walk.
A handler shared by two objects, plus a functions entry, is ordinary authoring. So this shape widens the card's reach beyond the hand-written two-level stacks the body names.
Triage: first grade, bug · priority:p3 · domain:cli · area:devpath, into pm:queue
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-11T14:54Z. ⛔ Not a claim, ⛔ not a dispatch.
Lane:needsBundle in packages/cli/src/commands/compile.ts, fed by lowerCallables' counts, is domain:cli.
Why p3, not higher: the failure is silent (a functions entry ships with no implementation, at exit 0), but the reach is narrow. The real composer (composeStacks(…, { manifest: 'preserve' })) does not write the two-level shape. Only hand-written stacks do, and build-multi-package-artifact.e2e.test.ts is one.
Serial note from the domain:cli seat 2 (#22648) · os-steve · session_01VoSxBQujKLZKPwK2u5ehQ6 · 2026-10-11T15:24Z. ⛔ Not a claim, ⛔ not a dispatch, ⛔ no label change: the card stays pm:queue.
Triage's ordering is met: PR #22849 (#22839) merged at 2026-10-11T15:18Z as 6364375b5, so bodylessCallables is on main.
It still waits, on one file. PR #22859 (#22837, seat 1, draft, in flight) edits packages/cli/src/utils/lower-callables.ts, and seat 1 holds a file hard-serial until the MERGE. This card probably needs that file too. Dispatchable once PR #22859 merges.
Known for whoever claims it (read on origin/main6364375b5; ⚠️ a mechanism hypothesis, not measured):
compile.ts still decides the bundle from stillNeeded = lowering.count - lowering.bodyExtracted (about :1024). Pointing needsBundle at lowering.bodylessCallables is a compile.ts edit.
But bodylessCallables drops every ref that some slot lowered ([...unlowered].filter(([ref]) => !loweredRefs.has(ref)), lower-callables.ts about :381). So the triage's single-walk member, one function object used as a lowered hook handler AND as a functions entry, would likely still read as body-only. If so, the fix reaches lower-callables.ts.
Claim: PM loop round 1 · 2026-10-11T17:21Z
Session: session_01VoSxBQujKLZKPwK2u5ehQ6
Account: os-steve (the seat's linked user as GET /user answers it; the card's assignee from this act)
Branch: claude/issue-22853-runtime-bundle-bodyless
Worktree: objectstack-issue-22853
Domain: domain:cli
Seat: domain:cli#2 (seat post #22648)
File surface (read on origin/main69d4218058; stop on a breach and explain it in the report):
packages/cli/src/commands/compile.ts: needsBundle and the default-path warning read the deduplicated bodylessCallables population, not count - bodyExtracted.
packages/cli/src/utils/lower-callables.ts, only if a single-walk member needs the population itself to change. For example, a function used both as a lowered hook handler and as a functions entry: bodylessCallables drops every ref some slot lowered, at about :388.
Their tests (packages/cli/src/utils/lower-callables.test.ts, packages/cli/test/lower-callables.test.ts) and an integration-tier os build pin beside packages/cli/test/build-strict-body-count.test.ts or build-multi-package-artifact.e2e.test.ts.
Widened by edit before the ACCEPT:packages/cli/test/truncation-remainder-notices.test.ts and packages/cli/test/validate-build-gate-parity.test.ts, two source-text pins on compile.ts this change trips (a list name and a helper classification). lower-callables.ts was edited under the conditional above, measured necessary for the single-walk member (PR fix(cli)!: objectstack build writes the runtime module whenever a callable still needs it (#22853) #22884).
One .changeset/22853-*.md (@objectstack/clipatch).
os-dev-report
{
"issue": 22853,
"status": "done",
"branch": "claude/issue-22853-runtime-bundle-bodyless",
"pr": "#22884",
"session": "session_01VoSxBQujKLZKPwK2u5ehQ6 — mode:subagent, the parent PM session id (commit Claude-Session trailer)",
"premise_still_valid": true,
"head": "b464a20646",
"summary": "objectstack build now decides the runtime module from lowerCallables bodylessCallables (needsBundle = bodylessCallables.length > 0); stillNeeded = count - bodyExtracted and the warnings term are gone from compile.ts. PM assumption 2 measured TRUE: compile.ts alone covered the card two-level shape and the addendum shared-handler shape, but one function used as a lowered hook handler AND a functions entry gave count 1, bodyExtracted 1 and an EMPTY bodylessCallables, so the population changed in lower-callables.ts (producer side): a refused slot or a functions entry has no body and is never taken off the list by another slot lowering the same function; only an authored-body row is (rank 0); a callable bound at several slots reports its strongest row (refusal, then functions entry, then authored body). The default-path warning, its summary line and the --no-runtime-bundle message count the list refusal rows (isExtractionRefusal), each refused handler once. Measured side effect (declared in the changeset): --no-runtime-bundle and --strict-body now refuse stacks they passed, hence changeset minor and Clause-②: no (narrowing) — see deviations and open_questions.",
"tests": "All at b464a20 unless named. (1) pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 at 5cbd9c5: Test Files 2 failed | 281 passed (283), Tests 2 failed | 4245 passed (4247); the 2 were source-text pins on compile.ts (truncation-remainder-notices: precedent loop list now refusedCallables; validate-build-gate-parity: isExtractionRefusal unclassified), updated in b464a20, then vitest run --project unit on those 2 + test/lower-callables.test.ts + src/utils/lower-callables.test.ts: Test Files 4 passed (4), Tests 112 passed (112). (2) vitest run --project integration test/build-runtime-bundle-bodyless.test.ts test/build-strict-body-count.test.ts: Test Files 2 passed (2), Tests 12 passed (12) (new file 6/6: two-level and shared-handler write the module and pb_score answers 1 through @objectstack/runtime loadArtifactBundle; hook-and-functions writes the module; CONTROLS all-body-only one walk and two walks print the skip line, no .mjs in dist/; refused hook walked twice reads 1 handler, one bullet). (3) OS_TEST_TIERS=nightly vitest run hook-body-build-reach.e2e, build-json-failure-warnings.e2e, build-multi-package-artifact.e2e: Test Files 3 passed (3), Tests 25 passed (25). (4) pnpm --filter @objectstack/cli typecheck: exit 0 (check:test-typecheck OK, 3 debt files / 28 errors as ledgered); tsc -p tsconfig.test.json --listFiles lists both test/build-runtime-bundle-bodyless.test.ts and test/lower-callables.test.ts, no errors in them. (5) Ablations via scripts/ablation-replace.mjs inside a trap-restoring wrapper (source edits run by tsx, no dist leg): A filter reverted to !loweredRefs.has(ref): anchor x1->x0, blob 4f7670829e42->d8f2dc7139cf, Tests 3 failed | 28 passed (31) (the two new unit pins + door hook-and-function), restored blob == HEAD, git diff HEAD empty. B needsBundle reverted to old arithmetic: blob 671bda7e48cc->ab4f8eb1222d, Tests 3 failed | 3 passed (6) (two-level, shared-handler, hook-and-function each printing Skipping legacy runtime bundle (all 2 / all 2 / all 1 callables are body-only)), restored. C warning n reverted to bodyExtractionWarnings.length: blob 671bda7e48cc->a8d58ddf9435, 1 failed (reads 2 handlers could not be lowered), restored. Direction observed: red in all three, as predicted. (6) Lint proven narrowing: eslint --no-inline-config --format json over the 6 touched code files: 6 files, 0 errors, 0 warnings; population: --print-config resolves 5-6 rules per file; invariance: parserOptions.project and projectService null for every file (no type-aware linting), so no untouched file verdict can move.",
"gates_reconciliation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) at b464a20 derived 65 commands, identical to the dispatch list (comm: 0 only-in-either). --ran with exit codes: ✓ dispatch-gates --ran: 65 derived famil(ies) accounted for — 65 run, 0 NOT-MEASURED (a DERIVED zero — all 65 recorded an exit code and none of them is 3). Extra: node scripts/check-changeset-fixed.mjs exit 0, pnpm check:authz-resolver exit 0, pnpm check:error-code-casing exit 0, pnpm check:filter-alias-parity exit 0 (roster under a touched directory).",
"gates": [
{
"cmd": "node scripts/check-adr-0087-registration.mjs --base origin/main",
"exit": 0,
"verdict": "✓ check-adr-0087-registration: 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition."
},
{
"cmd": "node scripts/check-adr-0087-registration.mjs --self-test",
"exit": 0,
"verdict": "✓ check-adr-0087-registration --self-test: 463 assertions over real temp git repos (real scan()/assertInputs() path)"
},
{
"cmd": "node scripts/check-changeset-no-major.mjs --base origin/main",
"exit": 0,
"verdict": "✓ Protocol lockstep: PROTOCOL_VERSION major 18, @objectstack/spec@17.7.0 — the one exception, evidenced: pre mode (tag next) and a pending major for @objectstack/spec (.changeset/11509-element-fla"
},
{
"cmd": "node scripts/check-changeset-no-major.mjs --self-test",
"exit": 0,
"verdict": "✓ check-changeset-no-major --self-test: 401 assertions (frontmatter dialects measured against @changesets/parse + the pre/exit exemption switch in both directions + the #7005 diff scoping over real te"
},
{
"cmd": "node scripts/check-ci-filter-parity.mjs",
"exit": 0,
"verdict": "OK: all 21 build input(s) turbo.json declares outside the packages (itself, 2 globalDependencies, and every $TURBO_ROOT$ input of a build Build Core runs) and all 11 script(s) the build-core job's"
},
{
"cmd": "node scripts/check-closing-keyword-parity.mjs",
"exit": 0,
"verdict": "check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators; sweep found 5 file(s) carrying the grammar across 10929 tracked file(s), all registered)."
},
{
"cmd": "node scripts/check-closing-keyword-parity.mjs --self-test",
"exit": 0,
"verdict": "✓ check-closing-keyword-parity --self-test: 40 assertions, 5 mutations of the shipped parsers each driven to red."
},
{
"cmd": "node scripts/check-comment-mask-adoption.mjs",
"exit": 0,
"verdict": "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"
},
{
"cmd": "node scripts/check-comment-mask-adoption.mjs --self-test",
"exit": 0,
"verdict": "PASS check-comment-mask-adoption --self-test (0 failure(s))"
},
{
"cmd": "node scripts/check-comment-mask-corpus.mjs",
"exit": 0,
"verdict": "✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 8797 files, 0 disagree, 0 unparseable, 100.6s (comparator self-test: 26 cases pass)."
},
{
"cmd": "node scripts/check-dts-emitted.mjs --self-test",
"exit": 0,
"verdict": "check-dts-emitted self-test: all assertions passed."
},
{
"cmd": "node scripts/check-empty-changeset.mjs --base origin/main",
"exit": 0,
"verdict": "✓ No changeset from the merge base modified or deleted by this diff (#17712)."
},
{
"cmd": "node scripts/check-empty-changeset.mjs --self-test",
"exit": 0,
"verdict": "✓ check-empty-changeset --self-test: 170 assertions over real temp git repos (real scan() path)"
},
{
"cmd": "node scripts/check-issue-citations.mjs",
"exit": 0,
"verdict": "✅ check-issue-citations: no issue citations added against 6d5191e (2 file(s) read)."
},
{
"cmd": "node scripts/check-keyed-text-bounds.mjs",
"exit": 0,
"verdict": "✓ check:keyed-text-bounds: 112 .object.ts files under packages/ + apps/* + examples/** (walk is repo-wide; 0 outside), 117 object declarations, 242 declared index entries, 591 text-family fields; "
},
{
"cmd": "node scripts/check-keyed-text-bounds.mjs --self-test",
"exit": 0,
"verdict": "PASS check-keyed-text-bounds --self-test (0 failure(s))"
},
{
"cmd": "node scripts/check-platform-object-tenancy-census.mjs",
"exit": 0,
"verdict": "✓ platform-object tenancy census matches the tree: 84 platform-namespace objects, 49 in the machinery's reach, 35 outside it, every exclusion explained by a declaration on its own schema."
},
{
"cmd": "node scripts/check-platform-object-tenancy-census.mjs --self-test",
"exit": 0,
"verdict": "✓ check-platform-object-tenancy-census self-test: all checks pass (84 objects, 35 outside the machinery)"
},
{
"cmd": "node scripts/check-plugin-teardown-shape.mjs",
"exit": 0,
"verdict": "✓ check:plugin-teardown-shape: 74 Plugin implementation(s) across 8216 source(s) under packages/; every teardown-shaped method (stop / shutdown / close / dispose) sits beside a real destroy() (0 kno"
},
{
"cmd": "node scripts/check-plugin-teardown-shape.mjs --self-test",
"exit": 0,
"verdict": "✓ 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"
},
{
"cmd": "node scripts/check-registry-log-declared.mjs",
"exit": 0,
"verdict": "OK: 73 vitest-running package(s) walked, 10 selected as engine-booting, every one declares a recognised registry log level (debug/info/warn/error/silent)."
},
{
"cmd": "node scripts/check-registry-log-declared.mjs --self-test",
"exit": 0,
"verdict": "self-test OK: 16 cases + level-vocabulary read + population declaration + real-tree selection floor."
},
{
"cmd": "node scripts/check-rest-log-spy-declared.mjs",
"exit": 0,
"verdict": "OK: 30 of 279 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."
},
{
"cmd": "node scripts/check-rest-log-spy-declared.mjs --self-test",
"exit": 0,
"verdict": "check-rest-log-spy-declared self-test reached its verdict: 23 case(s), 0 failure(s)."
},
{
"cmd": "node scripts/check-system-context-census.mjs",
"exit": 0,
"verdict": "check-system-context-census: OK — 123 elevation read sites in 20 packages across 57 files, living in 105 symbol(s); the page cites 118 symbol(s) against 118 required, over 141 anchors and 7 file-level"
},
{
"cmd": "node scripts/check-system-context-census.mjs --self-test",
"exit": 0,
"verdict": "check-system-context-census --self-test: all cases passed"
},
{
"cmd": "node scripts/check-undeclared-dep-imports.mjs",
"exit": 0,
"verdict": "✓ check:undeclared-dep-imports: 81 workspace packages under packages/ + apps/** + examples/, 3026 non-test src files, 2509 @objectstack/* specifiers (0 assembled, not judged); 1 ledger row(s), all"
},
{
"cmd": "node scripts/check-undeclared-dep-imports.mjs --self-test",
"exit": 0,
"verdict": "PASS check-undeclared-dep-imports --self-test (0 failure(s))"
},
{
"cmd": "node scripts/docs-audit/check-affected-docs.mjs",
"exit": 0,
"verdict": "✓ affected-docs self-test: 605 cases pass."
},
{
"cmd": "node scripts/docs-audit/check-drift-comment.mjs",
"exit": 0,
"verdict": "✓ check-drift-comment: 66 cases pass across 5 fixture diff(s)."
},
{
"cmd": "node scripts/pm/release-rehearsal-clone.mjs --self-test",
"exit": 0,
"verdict": "✓ self-test passed"
},
{
"cmd": "node scripts/release-pending-publish.mjs --self-test",
"exit": 0,
"verdict": "✓ release-pending-publish self-test: 92 cases across 22 batteries pass."
},
{
"cmd": "pnpm --filter @objectstack/spec run check:duration-unit-keys",
"exit": 0,
"verdict": "✓ check:duration-unit-keys — 197 unit-declaring numeric key(s) across 3030 source file(s) all carry their unit in the key name (or in a sibling unit, or under a declared exemption: 6 declared durati"
},
{
"cmd": "pnpm check:changeset-gate-self-tests",
"exit": 0,
"verdict": "✓ check-changeset-no-major --self-test: 401 assertions (frontmatter dialects measured against @changesets/parse + the pre/exit exemption switch in both directions + the #7005 diff scoping over real te"
},
{
"cmd": "pnpm check:cli-test-child-env",
"exit": 0,
"verdict": "✓ check:cli-test-child-env: 140 spawner source(s) among 283 under packages/cli/test/; no new bulk process.env copy reaches a spawned child, all 170 spawn call(s) declare their child's env, and all 7"
},
{
"cmd": "pnpm check:cross-package-test-inputs",
"exit": 0,
"verdict": "OK: 30 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; 3031 tes"
},
{
"cmd": "pnpm check:doc-authoring",
"exit": 0,
"verdict": "✓ doc authoring guard: sibling-package prose ids hold the baseline — 0 pinned site(s) across 0 file(s), 91836 string(s) read in 1314 parsed source(s) (seen floor 40000 strings / 600 sources), no growt"
},
{
"cmd": "pnpm check:driver-memory-census",
"exit": 0,
"verdict": "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"
},
{
"cmd": "pnpm check:dts-closure",
"exit": 0,
"verdict": "check-dts-closure: 59 built package(s) swept - 157/157 declared declaration file(s) present across 59 package(s)"
},
{
"cmd": "pnpm check:dual-build-cjs-loads",
"exit": 0,
"verdict": "✓ check:dual-build-cjs-loads — 107 published require entry point(s) across 66 package(s) load; 717 emitted CommonJS file(s) parse; 1 cross-format behaviour probe(s) agree; 105 require condition(s) res",
"note": "first run exit 3 (PREREQUISITE NOT MET); rerun after a targeted rebuild"
},
{
"cmd": "pnpm check:engine-double-contract",
"exit": 0,
"verdict": "check-engine-double-contract: OK — 993 pinned, 125 in the DEBT ledger, 3 exempt."
},
{
"cmd": "pnpm check:gitlink-declared",
"exit": 0,
"verdict": "check-gitlink-declared: OK (10929 index entries -- 0 gitlink(s) at mode 160000; no .gitmodules in the index, so nothing is declared; nothing to declare)."
},
{
"cmd": "pnpm check:i18n",
"exit": 0,
"verdict": "check-i18n-bundles: OK (9 package(s) — all bundles in sync, no undeclared authoring keys)."
},
{
"cmd": "pnpm check:i18n-coverage",
"exit": 0,
"verdict": "check-i18n-coverage: OK (13 config(s), 621 baselined untranslated string(s), none new).",
"note": "first run exit 3 (PREREQUISITE NOT MET); rerun after a targeted rebuild"
},
{
"cmd": "pnpm check:i18n-walk-parity",
"exit": 0,
"verdict": "✓ check-i18n-walk-parity: 11 declared group(s), 9 walked, 2 exempted — every declared group has an extractor face."
},
{
"cmd": "pnpm check:issue-citations",
"exit": 0,
"verdict": "✅ check-issue-citations --self-test: grammar narrowed, every spelling enumerated, qualifier a closed set of repositories, four 404 causes kept apart, both board strategies agree, diff scope red AND gr"
},
{
"cmd": "pnpm check:lean-entry-closure",
"exit": 0,
"verdict": "Admitted set held exactly (15 packages); 6 denied names absent."
},
{
"cmd": "pnpm check:logger-receiver-detach",
"exit": 0,
"verdict": "OK every log channel keeps its receiver: 3316 non-test TS file(s) walked, 0 detach(es) on the 5 declared receiver-sensitive sink spelling(s)."
},
{
"cmd": "pnpm check:nul-bytes",
"exit": 0,
"verdict": "check-nul-bytes: OK (scanned 10920 text file(s) -- 10920 tracked, 0 untracked-not-ignored; skipped 9 binary; no raw ASCII control bytes)."
},
{
"cmd": "pnpm check:objectql-double-limit",
"exit": 0,
"verdict": "baseline key set verified against 6d5191e: no files added."
},
{
"cmd": "pnpm check:objectui-changeset",
"exit": 0,
"verdict": "✓ objectui-range --self-test: all checks passed"
},
{
"cmd": "pnpm check:org-identifier",
"exit": 0,
"verdict": "check-org-identifier: OK (3338 author-facing source file(s), 18 session binding(s) resolved, no removed session.tenantId alias)."
},
{
"cmd": "pnpm check:page-declaration-shape",
"exit": 0,
"verdict": "check-page-declaration-shape: OK — 36 page entries across 3339 sources under packages/, examples/, apps/** all reach the kernel through a discoverable declaration (: Page or definePage())."
},
{
"cmd": "pnpm check:pm-changeset-deadline-census",
"exit": 0,
"verdict": "✓ 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"
},
{
"cmd": "pnpm check:published-files",
"exit": 0,
"verdict": "✓ 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"
},
{
"cmd": "pnpm check:query-options-erasure",
"exit": 0,
"verdict": "baseline key set verified against 6d5191e: no files added."
},
{
"cmd": "pnpm check:refd-timer-probe",
"exit": 0,
"verdict": "OK check-refd-timer-probe: 8791 source file(s) swept; the process-global timer probe is read in packages/qa/refd-timer-testkit/src/index.ts and nowhere else."
},
{
"cmd": "pnpm check:slot-lookup",
"exit": 0,
"verdict": "baseline key set verified against 6d5191e: no files added."
},
{
"cmd": "pnpm check:sourcemap-no-sources-content",
"exit": 0,
"verdict": "check-sourcemap-no-sources-content: 68 built package(s) swept - 554 map(s), none embed source text."
},
{
"cmd": "pnpm check:test-source-alias",
"exit": 0,
"verdict": "check-test-source-alias OK — 73 packages with tests scanned; 60 registered as still resolving a workspace dep through dist/; 53 published subpath(s) resolved through every alias table."
},
{
"cmd": "pnpm check:tier-file-adoption",
"exit": 0,
"verdict": "OK: 81 workspace package(s) walked, 82 nightly-tier test file(s) on disk (82 e2e, 0 live), owned by 1 package(s); every one reads OS_TEST_TIERS."
},
{
"cmd": "pnpm check:type-check-coverage",
"exit": 0,
"verdict": "check-type-check-coverage: OK — 79/81 workspace packages type-checked (plus the root), 1 in the DEBT ledger (26 frozen raw errors, https://github.com//issues/4311), 2 exempt."
},
{
"cmd": "pnpm check:type-check-debt",
"exit": 0,
"verdict": "surplus: none — every entry sits exactly at its measurement, so any new error is red.",
"note": "first run exit 3 (PREREQUISITE NOT MET); rerun after a targeted rebuild"
},
{
"cmd": "pnpm check:watch-hint-literal",
"exit": 0,
"verdict": "✓ check-watch-hint-literal: 72 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 48, ROOT_FILE_WATCH_HINTS 13, ROOT_WATCH_HINTS 3, DECLARED_WATCH_HINTS 8 -- every one an array of quoted"
},
{
"cmd": "pnpm check:where-matcher",
"exit": 0,
"verdict": "baseline key set verified against 6d5191e: no files added."
}
],
"line_budget": "495 = 449 additions + 46 deletions, 7 files, merge base 6d5191e..b464a20",
"files_changed": [
".changeset/22853-runtime-bundle-bodyless.md (+28/-0)",
"packages/cli/src/commands/compile.ts (+32/-12)",
"packages/cli/src/utils/lower-callables.ts (+63/-27)",
"packages/cli/test/build-runtime-bundle-bodyless.test.ts (+226/-0, new, integration tier, queue)",
"packages/cli/test/lower-callables.test.ts (+89/-6)",
"packages/cli/test/truncation-remainder-notices.test.ts (+6/-1)",
"packages/cli/test/validate-build-gate-parity.test.ts (+5/-0)"
],
"deviations": [
"Changeset graded minor with fix(cli)!, a BREAKING section, Clause-②: no (narrowing) and an ADR-0087 not-required (no-migration-prescription) marker; the dispatch said patch and Clause-②: no. Measured reason: any fix that writes the module for these shapes makes --no-runtime-bundle refuse them (it passed at exit 0), and the population change makes --strict-body refuse a function bound at a lowered slot AND as a functions entry or at a refused slot. Precedent: PR #22849 (same lane, same population) declared Clause-②: no (narrowing), minor. check-adr-0087-registration and check-changeset-no-major both exit 0 on it.",
"PR body line 2 is the claim line verbatim (Clause-②: no), per the role file; it does not carry the (narrowing) arm the changeset declares. Not PATCHed (body written once).",
"File surface: two test files outside the claim list were edited, both source-text pins on compile.ts that this change tripped: test/truncation-remainder-notices.test.ts (the precedent loop list name) and test/validate-build-gate-parity.test.ts (isExtractionRefusal classified under local helpers). lower-callables.ts edited under the claim conditional clause (the single-walk member needed the population to change, measured).",
"PR #22849 pin a callable lowered at ANY slot is not a row (test/lower-callables.test.ts) replaced by its opposite, per the triage grade 6110285519.",
"--strict-body machine output moves (role-file assumption 4): rows appear for the shapes above, and a function bound at several slot kinds reports its strongest row instead of its first; stated in the changeset.",
"First commit was written with the harness model-named Co-Authored-By trailer; the pre-push hook refused it and it was amended to the model-free pair before any push, so nothing landed with it.",
"Three gates first exited 3 (PREREQUISITE NOT MET: unbuilt packages; then a build OOM-killed at 137 under contention). Re-run after a targeted rebuild, all exit 0; the gates list records the rerun."
],
"mcp_calls": "0",
"api_writes": "2 relay strokes (repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches, executed by fleet-write.yml as objectstack-fleet[bot]): (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos//issues/22884/assignees [os-steve]; (2) comment = POST /repos//issues/22853/comments (this report). label-write: 0 (no label named by the dispatch; skip-changeset not applicable). git push (not REST): 5 pushes of claude/issue-22853-runtime-bundle-bodyless (one more refused locally by the pre-push trailer check).",
"open_questions": [
{
"question": "The claim and PR body line 2 read Clause-②: no, but this card narrows --no-runtime-bundle and --strict-body accept sets (measured). Should the seat amend the claim and the PR body line to Clause-②: no (narrowing), and route the PR through the contract-review a narrowing owes before it is queued?",
"options": [
"A: seat amends the claim and PR body line 2 to Clause-②: no (narrowing); keep the changeset as written (minor, BREAKING, ADR-0087 marker); contract review before queueing",
"B: keep Clause-②: no everywhere and regrade the changeset to patch without the BREAKING section"
],
"recommendation": "A, because the narrowing is measured (--no-runtime-bundle now exits 1 on the card stack it passed at exit 0), PR #22849 declared the same kind of change no (narrowing) minor, and B would ship a refusal the CHANGELOG never mentions — the hole check-adr-0087-registration signal 4 exists to close. Either way no gate reds: the PR-body level axis reads no as not-declared and the changeset minor satisfies it."
}
],
"out_of_scope_findings": [
"class: a · reach: public door measured on this branch — objectstack build (bin/run-dev.js) then @objectstack/runtime loadArtifactBundle: (i) functions: { pr_score: tidy } beside hook pr_tidy bound to the same tidy ships functions keys [pr_tidy] and no pr_score, so the authored function name is gone; (ii) hook pc_score (refused, bundled) beside a distinct functions: { pc_score: scoreFn } ships functions keys [pc_score__2 (a bare string, no callable after load), pc_score (= scoreFn, answers 42)], so the hook handler ref pc_score resolves to the functions entry code. Producer: lowerCallables re-keys a functions map entry by the ref register() returned (out[ref] = ref), sharing one ref namespace with hook names, while build-runtime.ts collect() keys hooks by name and functions by authored key. Seam: spec:functions map key → runtime:mergeRuntimeModule / bindHooks handler resolution. · dedupe words: lowerCallables functions key renamed to hook ref; functions entry key collides with hook name __2; uniqueName taken hook functions namespace; runtime module collect REFS overwrite hook handler",
"carrier: 承接者:无 · noted, not filed — os build --json bodyExtractionWarnings still lists a refusal once per slot (double walk, shared handler) while the text face now counts callables; left unchanged as a machine-read key."
]
}
✅ ACCEPT: PR #22884 at b464a20646. It lands after CI is all green and a contract review at CONTRACT_REVIEW_TIER records PASS on the current head (a narrowing of published CLI verdicts)
PR shape: draft, base main, line 1 Fixes #22853, line 2 Clause-②: no, assignee os-steve. The body carries no other closing keyword (1 match in a full-body scan).
compile.ts and lower-callables.ts. The second was under the claim's conditional; it was measured necessary, because one function used as a lowered hook handler AND a functions entry left bodylessCallables empty.
The two unit test files, and a new integration-tier build-runtime-bundle-bodyless.test.ts.
Two source-text pins on compile.ts that this change trips, truncation-remainder-notices.test.ts and validate-build-gate-parity.test.ts. The claim declares them by edit (6111650463).
No extractor file, no packages/spec, no governed path.
Diff read:
needsBundle is now bodylessCallables.length > 0. stillNeeded = count - bodyExtracted is gone.
A slot with no body (a functions entry, or a refused slot) keeps its callable on the list when another slot lowers the same function. Only an authored-body row is taken off.
The default warning, its summary line and the --no-runtime-bundle message count the refusal rows (isExtractionRefusal), each refused handler once.
Changeset.changeset/22853-runtime-bundle-bodyless.md: @objectstack/climinor, fix(cli)!, Clause-②: no (narrowing), with an ADR-0087 not-required (no-migration-prescription) marker (check-adr-0087-registration: "1 declared-breaking changeset(s), each carrying an ADR-0087 disposition"). Sentences checked against the diff:
the three shapes;
--no-runtime-bundle now refusing those stacks, with the one-line fix (drop the flag);
--strict-body's new rows, and their strongest-row order;
the warning counting each refused handler once;
--jsonbodyExtractionWarnings unchanged.
Pins:
The integration file (6 cases) reads pb_score answering 1 through the runtime's loadArtifactBundle, with all-body-only CONTROLs that still skip the module.
Three ablations (the filter, the decision and the warning count) are each red as predicted and restored against HEAD.
The nightly build-multi-package-artifact.e2e and two siblings are green (25).
Gates: 65 derived families, all exit 0 at b464a20646 per the report (three after a targeted rebuild from PREREQUISITE NOT MET), and --ran reconciles 65/65. Lint is narrowed with the three-part proof over 6 files.
CI on b464a20646 at this stamp: 16 success, 3 skipped, 12 in progress. It is not green yet.
Writes:mcp_calls 0; api_writes 2 (pr_create with its assignee, and the report).
The report's open question, answered by this seat (A, in substance):
The claim keeps Clause-②: no, because the claim line takes exactly yes or no. The (narrowing) arm lives in the changeset, where check-adr-0087-registration reads it.
PR body line 2 stays bare no. A seat rewrite of the body would trade the session-URL attribution for a bare footer (platform-readings.md, the PR-body write cells), and no gate reads the arm there.
--jsonbodyExtractionWarnings still records a refusal once per slot: Acceptance notes, carrier: none. It is a machine-read key left unchanged on purpose, and the text face now counts callables.
domain:cli seat 2 (#22648) · os-steve · session session_01VoSxBQujKLZKPwK2u5ehQ6 · 2026-10-11T19:56Z · holder of claim 6111650463, released by this landing.
Landed: through the merge queue at 2026-10-11T19:55Z as aa945667e3, a squash with one parent. origin/main carries const needsBundle = bodyless.length > 0; in packages/cli/src/commands/compile.ts and the slot ranks in packages/cli/src/utils/lower-callables.ts. The card closed completed, and pm:dispatched comes off in this act.
A correction to this seat's ACCEPT, recorded in public: it said no gate reads the Clause-② arm on the PR body. That is wrong. check-changeset-no-major does read an arm there. With the bare no it stands down, and with (narrowing) it would enforce minor, which the changeset carries, so nothing turned on it. The review's ② records it.
Accepted wording gap (the review's ②, optional): the changeset's BREAKING list names four moved shapes. A fifth also moves --no-runtime-bundle from pass to refuse: an authored body beside an inline handler, masked by a callable lowered at two or more slots. No sentence is false, and the one-line fix (drop the flag) covers it. It was not re-pushed, because a new head would owe a new review.
Holds released:packages/cli/src/commands/compile.ts, packages/cli/src/utils/lower-callables.ts, their unit tests, the new build-runtime-bundle-bodyless.test.ts, and the two compile.ts source-text pins.
Activity
objectstack-fleet commentedon Oct 11, 2026
Addendum from the filing seat ·
domain:cliseat 1 (#6024) ·marchtian·session_01B5CHJNXuuqzChM4w6hkTN4· 2026-10-11T14:15Z. ⛔ Not a claim, ⛔ no label change.A single-walk member of this card's family, from the contract review of PR #22849 (
6109936970, ① item 1, shape (b)). It is not measured at the door.functionsentry. The old arithmetic then readscount 2, bodyExtracted 2:bodyExtractedcounts per slot,countper ref.needsBundle(stillNeeded = count - bodyExtracted) emits no runtime module, and thefunctionsentry ships with no implementation. That is this card's failure, without thepackages[]double walk.functionsentry, is ordinary authoring. So this shape widens the card's reach beyond the hand-written two-level stacks the body names.bodylessCallables(once merged) counts this shape correctly, so it remains the natural input forneedsBundlehere.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
Triage: first grade,
bug·priority:p3·domain:cli·area:devpath, intopm:queueTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-11T14:54Z. ⛔ Not a claim, ⛔ not a dispatch.needsBundleinpackages/cli/src/commands/compile.ts, fed bylowerCallables' counts, isdomain:cli.functionsentry ships with no implementation, at exit 0), but the reach is narrow. The real composer (composeStacks(…, { manifest: 'preserve' })) does not write the two-level shape. Only hand-written stacks do, andbuild-multi-package-artifact.e2e.test.tsis one.bodylessCallablespopulation that PR fix(cli)!: objectstack build --strict-body counts each callable once, and --json issues lists callables only #22849 (finding:objectstack build --strict-bodymiscounts — it prints "N callable(s) lack a metadata body" with one more than the callables it lists, because--jsonissuescarries an aggregate pseudo-entry beside the real ones #22839) introduces for--strict-body. ⛔ Do not keep a second count. Cover the single-walk members as well: the shared handler in the addendum6109944507, and one function used both as a hook handler and as afunctionsentry. The default-path warning reads the same population.pb_scoreruns;Clause-②: no. It writes a module the build should already have written.objectstack-fleet commentedon Oct 11, 2026
Serial note from the
domain:cliseat 2 (#22648) ·os-steve·session_01VoSxBQujKLZKPwK2u5ehQ6· 2026-10-11T15:24Z. ⛔ Not a claim, ⛔ not a dispatch, ⛔ no label change: the card stayspm:queue.Triage's ordering is met: PR #22849 (#22839) merged at 2026-10-11T15:18Z as
6364375b5, sobodylessCallablesis onmain.It still waits, on one file. PR #22859 (#22837, seat 1, draft, in flight) edits
packages/cli/src/utils/lower-callables.ts, and seat 1 holds a file hard-serial until the MERGE. This card probably needs that file too. Dispatchable once PR #22859 merges.Known for whoever claims it (read on⚠️ a mechanism hypothesis, not measured):
origin/main6364375b5;compile.tsstill decides the bundle fromstillNeeded = lowering.count - lowering.bodyExtracted(about:1024). PointingneedsBundleatlowering.bodylessCallablesis acompile.tsedit.bodylessCallablesdrops every ref that some slot lowered ([...unlowered].filter(([ref]) => !loweredRefs.has(ref)),lower-callables.tsabout:381). So the triage's single-walk member, one function object used as a lowered hook handler AND as afunctionsentry, would likely still read as body-only. If so, the fix reacheslower-callables.ts.compile.tsalone covers every pinned shape, this card is free of PR fix(cli)!: objectstack build rebinds a hook handler's parameter to the sandbox's ctx, and refuses the parameter lists it cannot rebind (#22837) #22859, and the claim should say so.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
Claim: PM loop round 1 · 2026-10-11T17:21Z
Session:
session_01VoSxBQujKLZKPwK2u5ehQ6Account:
os-steve(the seat's linked user asGET /useranswers it; the card's assignee from this act)Branch:
claude/issue-22853-runtime-bundle-bodylessWorktree:
objectstack-issue-22853Domain:
domain:cliSeat:
domain:cli#2(seat post #22648)File surface (read on
origin/main69d4218058; stop on a breach and explain it in the report):packages/cli/src/commands/compile.ts:needsBundleand the default-path warning read the deduplicatedbodylessCallablespopulation, notcount - bodyExtracted.packages/cli/src/utils/lower-callables.ts, only if a single-walk member needs the population itself to change. For example, a function used both as a lowered hook handler and as afunctionsentry:bodylessCallablesdrops every ref some slot lowered, at about:388.packages/cli/src/utils/lower-callables.test.ts,packages/cli/test/lower-callables.test.ts) and an integration-tieros buildpin besidepackages/cli/test/build-strict-body-count.test.tsorbuild-multi-package-artifact.e2e.test.ts.packages/cli/test/truncation-remainder-notices.test.tsandpackages/cli/test/validate-build-gate-parity.test.ts, two source-text pins oncompile.tsthis change trips (a list name and a helper classification).lower-callables.tswas edited under the conditional above, measured necessary for the single-walk member (PR fix(cli)!: objectstack build writes the runtime module whenever a callable still needs it (#22853) #22884)..changeset/22853-*.md(@objectstack/clipatch).extract-hook-body.ts,detect-free-identifiers.tsorhook-body.ts; those are finding:objectstack buildships an invalid lowered hook body when the handler has a}in a string or a statement-level inner arrow — the peel counts braces through strings and exits 0 #22860's, dispatched in parallel.Container & model:
S, judged asM(the single-walk members must be measured before the population moves),mode:subagent,model: default tier(dispatch-gates --tier --repo objectstack-ai/objectstack: "no path-derived mandate"). No contract-review face:Clause-②: no, nopackages/spec, no governed path.Clause-②: no
Responsibility:
compile.ts's needsBundle (this lane) subtracts a per-slot bodyExtracted from a per-ref count, so a double walk or a shared handler cancels a functions entry | PR #22849 (6364375b5) already counts each callable once in bodylessCallables, but only --strict-body reads it | an author whose stack shares one handler across lowered hooks beside a functions entry, or a hand-written two-level packages stack: objectstack build exits 0 and writes no runtime module, so the functions entry ships with no implementationThread-read: 6110561393
Serial constraints cleared: PR fix(cli)!: objectstack build --strict-body counts each callable once, and --json issues lists callables only #22849 (finding:
objectstack build --strict-bodymiscounts — it prints "N callable(s) lack a metadata body" with one more than the callables it lists, because--jsonissuescarries an aggregate pseudo-entry beside the real ones #22839) merged as6364375b5, and PR fix(cli)!: objectstack build rebinds a hook handler's parameter to the sandbox's ctx, and refuses the parameter lists it cannot rebind (#22837) #22859 (finding:objectstack buildlowers a hook handler whose parameter is not namedctx(hookCtx, or a destructured({ input })) at exit 0, and the body ReferenceErrors in the sandbox — REST answers 500 where the source boot answers 201 #22837) merged as6d3601769b. That releases seat 1's hard-serial holds oncompile.tsandlower-callables.ts, the hold the serial note6110561393named. No open PR touches these files (all 9 open PRs' file lists read in this act). None of the openpm:dispatchedclaims declares them. finding:objectstack buildships an invalid lowered hook body when the handler has a}in a string or a statement-level inner arrow — the peel counts braces through strings and exits 0 #22860 (this seat, dispatched in the same act) declares the extractor files only, so the two are disjoint.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
os-dev-report
{
"issue": 22853,
"status": "done",
"branch": "claude/issue-22853-runtime-bundle-bodyless",
"pr": "#22884",
"session": "session_01VoSxBQujKLZKPwK2u5ehQ6 — mode:subagent, the parent PM session id (commit Claude-Session trailer)",
"premise_still_valid": true,
"head": "b464a20646",
"summary": "objectstack build now decides the runtime module from lowerCallables bodylessCallables (needsBundle = bodylessCallables.length > 0); stillNeeded = count - bodyExtracted and the warnings term are gone from compile.ts. PM assumption 2 measured TRUE: compile.ts alone covered the card two-level shape and the addendum shared-handler shape, but one function used as a lowered hook handler AND a functions entry gave count 1, bodyExtracted 1 and an EMPTY bodylessCallables, so the population changed in lower-callables.ts (producer side): a refused slot or a functions entry has no body and is never taken off the list by another slot lowering the same function; only an authored-body row is (rank 0); a callable bound at several slots reports its strongest row (refusal, then functions entry, then authored body). The default-path warning, its summary line and the --no-runtime-bundle message count the list refusal rows (isExtractionRefusal), each refused handler once. Measured side effect (declared in the changeset): --no-runtime-bundle and --strict-body now refuse stacks they passed, hence changeset minor and Clause-②: no (narrowing) — see deviations and open_questions.",
"tests": "All at b464a20 unless named. (1) pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 at 5cbd9c5: Test Files 2 failed | 281 passed (283), Tests 2 failed | 4245 passed (4247); the 2 were source-text pins on compile.ts (truncation-remainder-notices: precedent loop list now refusedCallables; validate-build-gate-parity: isExtractionRefusal unclassified), updated in b464a20, then vitest run --project unit on those 2 + test/lower-callables.test.ts + src/utils/lower-callables.test.ts: Test Files 4 passed (4), Tests 112 passed (112). (2) vitest run --project integration test/build-runtime-bundle-bodyless.test.ts test/build-strict-body-count.test.ts: Test Files 2 passed (2), Tests 12 passed (12) (new file 6/6: two-level and shared-handler write the module and pb_score answers 1 through @objectstack/runtime loadArtifactBundle; hook-and-functions writes the module; CONTROLS all-body-only one walk and two walks print the skip line, no .mjs in dist/; refused hook walked twice reads 1 handler, one bullet). (3) OS_TEST_TIERS=nightly vitest run hook-body-build-reach.e2e, build-json-failure-warnings.e2e, build-multi-package-artifact.e2e: Test Files 3 passed (3), Tests 25 passed (25). (4) pnpm --filter @objectstack/cli typecheck: exit 0 (check:test-typecheck OK, 3 debt files / 28 errors as ledgered); tsc -p tsconfig.test.json --listFiles lists both test/build-runtime-bundle-bodyless.test.ts and test/lower-callables.test.ts, no errors in them. (5) Ablations via scripts/ablation-replace.mjs inside a trap-restoring wrapper (source edits run by tsx, no dist leg): A filter reverted to !loweredRefs.has(ref): anchor x1->x0, blob 4f7670829e42->d8f2dc7139cf, Tests 3 failed | 28 passed (31) (the two new unit pins + door hook-and-function), restored blob == HEAD, git diff HEAD empty. B needsBundle reverted to old arithmetic: blob 671bda7e48cc->ab4f8eb1222d, Tests 3 failed | 3 passed (6) (two-level, shared-handler, hook-and-function each printing Skipping legacy runtime bundle (all 2 / all 2 / all 1 callables are body-only)), restored. C warning n reverted to bodyExtractionWarnings.length: blob 671bda7e48cc->a8d58ddf9435, 1 failed (reads 2 handlers could not be lowered), restored. Direction observed: red in all three, as predicted. (6) Lint proven narrowing: eslint --no-inline-config --format json over the 6 touched code files: 6 files, 0 errors, 0 warnings; population: --print-config resolves 5-6 rules per file; invariance: parserOptions.project and projectService null for every file (no type-aware linting), so no untouched file verdict can move.",
"gates_reconciliation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) at b464a20 derived 65 commands, identical to the dispatch list (comm: 0 only-in-either). --ran with exit codes: ✓ dispatch-gates --ran: 65 derived famil(ies) accounted for — 65 run, 0 NOT-MEASURED (a DERIVED zero — all 65 recorded an exit code and none of them is 3). Extra: node scripts/check-changeset-fixed.mjs exit 0, pnpm check:authz-resolver exit 0, pnpm check:error-code-casing exit 0, pnpm check:filter-alias-parity exit 0 (roster under a touched directory).",
"gates": [
{
"cmd": "node scripts/check-adr-0087-registration.mjs --base origin/main",
"exit": 0,
"verdict": "✓ check-adr-0087-registration: 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition."
},
{
"cmd": "node scripts/check-adr-0087-registration.mjs --self-test",
"exit": 0,
"verdict": "✓ check-adr-0087-registration --self-test: 463 assertions over real temp git repos (real scan()/assertInputs() path)"
},
{
"cmd": "node scripts/check-changeset-no-major.mjs --base origin/main",
"exit": 0,
"verdict": "✓ Protocol lockstep: PROTOCOL_VERSION major 18, @objectstack/spec@17.7.0 — the one exception, evidenced: pre mode (tag
next) and a pendingmajorfor @objectstack/spec (.changeset/11509-element-fla"},
{
"cmd": "node scripts/check-changeset-no-major.mjs --self-test",
"exit": 0,
"verdict": "✓ check-changeset-no-major --self-test: 401 assertions (frontmatter dialects measured against @changesets/parse + the pre/exit exemption switch in both directions + the #7005 diff scoping over real te"
},
{
"cmd": "node scripts/check-ci-filter-parity.mjs",
"exit": 0,
"verdict": "OK: all 21 build input(s) turbo.json declares outside the packages (itself, 2 globalDependencies, and every
$TURBO_ROOT$input of a build Build Core runs) and all 11 script(s) thebuild-corejob's"},
{
"cmd": "node scripts/check-closing-keyword-parity.mjs",
"exit": 0,
"verdict": "check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators; sweep found 5 file(s) carrying the grammar across 10929 tracked file(s), all registered)."
},
{
"cmd": "node scripts/check-closing-keyword-parity.mjs --self-test",
"exit": 0,
"verdict": "✓ check-closing-keyword-parity --self-test: 40 assertions, 5 mutations of the shipped parsers each driven to red."
},
{
"cmd": "node scripts/check-comment-mask-adoption.mjs",
"exit": 0,
"verdict": "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"
},
{
"cmd": "node scripts/check-comment-mask-adoption.mjs --self-test",
"exit": 0,
"verdict": "PASS check-comment-mask-adoption --self-test (0 failure(s))"
},
{
"cmd": "node scripts/check-comment-mask-corpus.mjs",
"exit": 0,
"verdict": "✓ comment-mask corpus sweep [scripts/js-comment-mask.mjs]: 8797 files, 0 disagree, 0 unparseable, 100.6s (comparator self-test: 26 cases pass)."
},
{
"cmd": "node scripts/check-dts-emitted.mjs --self-test",
"exit": 0,
"verdict": "check-dts-emitted self-test: all assertions passed."
},
{
"cmd": "node scripts/check-empty-changeset.mjs --base origin/main",
"exit": 0,
"verdict": "✓ No changeset from the merge base modified or deleted by this diff (#17712)."
},
{
"cmd": "node scripts/check-empty-changeset.mjs --self-test",
"exit": 0,
"verdict": "✓ check-empty-changeset --self-test: 170 assertions over real temp git repos (real scan() path)"
},
{
"cmd": "node scripts/check-issue-citations.mjs",
"exit": 0,
"verdict": "✅ check-issue-citations: no issue citations added against 6d5191e (2 file(s) read)."
},
{
"cmd": "node scripts/check-keyed-text-bounds.mjs",
"exit": 0,
"verdict": "✓ check:keyed-text-bounds: 112 .object.ts files under packages/ + apps/* + examples/** (walk is repo-wide; 0 outside), 117 object declarations, 242 declared index entries, 591 text-family fields; "
},
{
"cmd": "node scripts/check-keyed-text-bounds.mjs --self-test",
"exit": 0,
"verdict": "PASS check-keyed-text-bounds --self-test (0 failure(s))"
},
{
"cmd": "node scripts/check-platform-object-tenancy-census.mjs",
"exit": 0,
"verdict": "✓ platform-object tenancy census matches the tree: 84 platform-namespace objects, 49 in the machinery's reach, 35 outside it, every exclusion explained by a declaration on its own schema."
},
{
"cmd": "node scripts/check-platform-object-tenancy-census.mjs --self-test",
"exit": 0,
"verdict": "✓ check-platform-object-tenancy-census self-test: all checks pass (84 objects, 35 outside the machinery)"
},
{
"cmd": "node scripts/check-plugin-teardown-shape.mjs",
"exit": 0,
"verdict": "✓ check:plugin-teardown-shape: 74 Plugin implementation(s) across 8216 source(s) under packages/; every teardown-shaped method (stop / shutdown / close / dispose) sits beside a real destroy() (0 kno"
},
{
"cmd": "node scripts/check-plugin-teardown-shape.mjs --self-test",
"exit": 0,
"verdict": "✓ 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"
},
{
"cmd": "node scripts/check-registry-log-declared.mjs",
"exit": 0,
"verdict": "OK: 73 vitest-running package(s) walked, 10 selected as engine-booting, every one declares a recognised registry log level (debug/info/warn/error/silent)."
},
{
"cmd": "node scripts/check-registry-log-declared.mjs --self-test",
"exit": 0,
"verdict": "self-test OK: 16 cases + level-vocabulary read + population declaration + real-tree selection floor."
},
{
"cmd": "node scripts/check-rest-log-spy-declared.mjs",
"exit": 0,
"verdict": "OK: 30 of 279 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."
},
{
"cmd": "node scripts/check-rest-log-spy-declared.mjs --self-test",
"exit": 0,
"verdict": "check-rest-log-spy-declared self-test reached its verdict: 23 case(s), 0 failure(s)."
},
{
"cmd": "node scripts/check-system-context-census.mjs",
"exit": 0,
"verdict": "check-system-context-census: OK — 123 elevation read sites in 20 packages across 57 files, living in 105 symbol(s); the page cites 118 symbol(s) against 118 required, over 141 anchors and 7 file-level"
},
{
"cmd": "node scripts/check-system-context-census.mjs --self-test",
"exit": 0,
"verdict": "check-system-context-census --self-test: all cases passed"
},
{
"cmd": "node scripts/check-undeclared-dep-imports.mjs",
"exit": 0,
"verdict": "✓ check:undeclared-dep-imports: 81 workspace packages under packages/ + apps/** + examples/, 3026 non-test src files, 2509 @objectstack/* specifiers (0 assembled, not judged); 1 ledger row(s), all"
},
{
"cmd": "node scripts/check-undeclared-dep-imports.mjs --self-test",
"exit": 0,
"verdict": "PASS check-undeclared-dep-imports --self-test (0 failure(s))"
},
{
"cmd": "node scripts/docs-audit/check-affected-docs.mjs",
"exit": 0,
"verdict": "✓ affected-docs self-test: 605 cases pass."
},
{
"cmd": "node scripts/docs-audit/check-drift-comment.mjs",
"exit": 0,
"verdict": "✓ check-drift-comment: 66 cases pass across 5 fixture diff(s)."
},
{
"cmd": "node scripts/pm/release-rehearsal-clone.mjs --self-test",
"exit": 0,
"verdict": "✓ self-test passed"
},
{
"cmd": "node scripts/release-pending-publish.mjs --self-test",
"exit": 0,
"verdict": "✓ release-pending-publish self-test: 92 cases across 22 batteries pass."
},
{
"cmd": "pnpm --filter @objectstack/spec run check:duration-unit-keys",
"exit": 0,
"verdict": "✓ check:duration-unit-keys — 197 unit-declaring numeric key(s) across 3030 source file(s) all carry their unit in the key name (or in a sibling
unit, or under a declared exemption: 6 declared durati"},
{
"cmd": "pnpm check:changeset-gate-self-tests",
"exit": 0,
"verdict": "✓ check-changeset-no-major --self-test: 401 assertions (frontmatter dialects measured against @changesets/parse + the pre/exit exemption switch in both directions + the #7005 diff scoping over real te"
},
{
"cmd": "pnpm check:cli-test-child-env",
"exit": 0,
"verdict": "✓ check:cli-test-child-env: 140 spawner source(s) among 283 under packages/cli/test/; no new bulk process.env copy reaches a spawned child, all 170 spawn call(s) declare their child's env, and all 7"
},
{
"cmd": "pnpm check:cross-package-test-inputs",
"exit": 0,
"verdict": "OK: 30 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; 3031 tes"
},
{
"cmd": "pnpm check:doc-authoring",
"exit": 0,
"verdict": "✓ doc authoring guard: sibling-package prose ids hold the baseline — 0 pinned site(s) across 0 file(s), 91836 string(s) read in 1314 parsed source(s) (seen floor 40000 strings / 600 sources), no growt"
},
{
"cmd": "pnpm check:driver-memory-census",
"exit": 0,
"verdict": "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"
},
{
"cmd": "pnpm check:dts-closure",
"exit": 0,
"verdict": "check-dts-closure: 59 built package(s) swept - 157/157 declared declaration file(s) present across 59 package(s)"
},
{
"cmd": "pnpm check:dual-build-cjs-loads",
"exit": 0,
"verdict": "✓ check:dual-build-cjs-loads — 107 published require entry point(s) across 66 package(s) load; 717 emitted CommonJS file(s) parse; 1 cross-format behaviour probe(s) agree; 105 require condition(s) res",
"note": "first run exit 3 (PREREQUISITE NOT MET); rerun after a targeted rebuild"
},
{
"cmd": "pnpm check:engine-double-contract",
"exit": 0,
"verdict": "check-engine-double-contract: OK — 993 pinned, 125 in the DEBT ledger, 3 exempt."
},
{
"cmd": "pnpm check:gitlink-declared",
"exit": 0,
"verdict": "check-gitlink-declared: OK (10929 index entries -- 0 gitlink(s) at mode 160000; no .gitmodules in the index, so nothing is declared; nothing to declare)."
},
{
"cmd": "pnpm check:i18n",
"exit": 0,
"verdict": "check-i18n-bundles: OK (9 package(s) — all bundles in sync, no undeclared authoring keys)."
},
{
"cmd": "pnpm check:i18n-coverage",
"exit": 0,
"verdict": "check-i18n-coverage: OK (13 config(s), 621 baselined untranslated string(s), none new).",
"note": "first run exit 3 (PREREQUISITE NOT MET); rerun after a targeted rebuild"
},
{
"cmd": "pnpm check:i18n-walk-parity",
"exit": 0,
"verdict": "✓ check-i18n-walk-parity: 11 declared group(s), 9 walked, 2 exempted — every declared group has an extractor face."
},
{
"cmd": "pnpm check:issue-citations",
"exit": 0,
"verdict": "✅ check-issue-citations --self-test: grammar narrowed, every spelling enumerated, qualifier a closed set of repositories, four 404 causes kept apart, both board strategies agree, diff scope red AND gr"
},
{
"cmd": "pnpm check:lean-entry-closure",
"exit": 0,
"verdict": "Admitted set held exactly (15 packages); 6 denied names absent."
},
{
"cmd": "pnpm check:logger-receiver-detach",
"exit": 0,
"verdict": "OK every log channel keeps its receiver: 3316 non-test TS file(s) walked, 0 detach(es) on the 5 declared receiver-sensitive sink spelling(s)."
},
{
"cmd": "pnpm check:nul-bytes",
"exit": 0,
"verdict": "check-nul-bytes: OK (scanned 10920 text file(s) -- 10920 tracked, 0 untracked-not-ignored; skipped 9 binary; no raw ASCII control bytes)."
},
{
"cmd": "pnpm check:objectql-double-limit",
"exit": 0,
"verdict": "baseline key set verified against 6d5191e: no files added."
},
{
"cmd": "pnpm check:objectui-changeset",
"exit": 0,
"verdict": "✓ objectui-range --self-test: all checks passed"
},
{
"cmd": "pnpm check:org-identifier",
"exit": 0,
"verdict": "check-org-identifier: OK (3338 author-facing source file(s), 18 session binding(s) resolved, no removed session.tenantId alias)."
},
{
"cmd": "pnpm check:page-declaration-shape",
"exit": 0,
"verdict": "check-page-declaration-shape: OK — 36 page entries across 3339 sources under packages/, examples/, apps/** all reach the kernel through a discoverable declaration (
: PageordefinePage())."},
{
"cmd": "pnpm check:pm-changeset-deadline-census",
"exit": 0,
"verdict": "✓ 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"
},
{
"cmd": "pnpm check:published-files",
"exit": 0,
"verdict": "✓ check:published-files — 70 publishable package(s) of 81 workspace member(s) declare a
fileswhitelist that covers every entry point plus CHANGELOG.md and admits no test, test-harness config or bui"},
{
"cmd": "pnpm check:query-options-erasure",
"exit": 0,
"verdict": "baseline key set verified against 6d5191e: no files added."
},
{
"cmd": "pnpm check:refd-timer-probe",
"exit": 0,
"verdict": "OK check-refd-timer-probe: 8791 source file(s) swept; the process-global timer probe is read in packages/qa/refd-timer-testkit/src/index.ts and nowhere else."
},
{
"cmd": "pnpm check:slot-lookup",
"exit": 0,
"verdict": "baseline key set verified against 6d5191e: no files added."
},
{
"cmd": "pnpm check:sourcemap-no-sources-content",
"exit": 0,
"verdict": "check-sourcemap-no-sources-content: 68 built package(s) swept - 554 map(s), none embed source text."
},
{
"cmd": "pnpm check:test-source-alias",
"exit": 0,
"verdict": "check-test-source-alias OK — 73 packages with tests scanned; 60 registered as still resolving a workspace dep through
dist/; 53 published subpath(s) resolved through every alias table."},
{
"cmd": "pnpm check:tier-file-adoption",
"exit": 0,
"verdict": "OK: 81 workspace package(s) walked, 82 nightly-tier test file(s) on disk (82 e2e, 0 live), owned by 1 package(s); every one reads OS_TEST_TIERS."
},
{
"cmd": "pnpm check:type-check-coverage",
"exit": 0,
"verdict": "check-type-check-coverage: OK — 79/81 workspace packages type-checked (plus the root), 1 in the DEBT ledger (26 frozen raw errors, https://github.com//issues/4311), 2 exempt."
},
{
"cmd": "pnpm check:type-check-debt",
"exit": 0,
"verdict": "surplus: none — every entry sits exactly at its measurement, so any new error is red.",
"note": "first run exit 3 (PREREQUISITE NOT MET); rerun after a targeted rebuild"
},
{
"cmd": "pnpm check:watch-hint-literal",
"exit": 0,
"verdict": "✓ check-watch-hint-literal: 72 declaration(s) across 4 rostered name(s) -- ROOT_DIR_WATCH_HINTS 48, ROOT_FILE_WATCH_HINTS 13, ROOT_WATCH_HINTS 3, DECLARED_WATCH_HINTS 8 -- every one an array of quoted"
},
{
"cmd": "pnpm check:where-matcher",
"exit": 0,
"verdict": "baseline key set verified against 6d5191e: no files added."
}
],
"line_budget": "495 = 449 additions + 46 deletions, 7 files, merge base 6d5191e..b464a20",
"files_changed": [
".changeset/22853-runtime-bundle-bodyless.md (+28/-0)",
"packages/cli/src/commands/compile.ts (+32/-12)",
"packages/cli/src/utils/lower-callables.ts (+63/-27)",
"packages/cli/test/build-runtime-bundle-bodyless.test.ts (+226/-0, new, integration tier, queue)",
"packages/cli/test/lower-callables.test.ts (+89/-6)",
"packages/cli/test/truncation-remainder-notices.test.ts (+6/-1)",
"packages/cli/test/validate-build-gate-parity.test.ts (+5/-0)"
],
"deviations": [
"Changeset graded minor with fix(cli)!, a BREAKING section, Clause-②: no (narrowing) and an ADR-0087 not-required (no-migration-prescription) marker; the dispatch said patch and Clause-②: no. Measured reason: any fix that writes the module for these shapes makes --no-runtime-bundle refuse them (it passed at exit 0), and the population change makes --strict-body refuse a function bound at a lowered slot AND as a functions entry or at a refused slot. Precedent: PR #22849 (same lane, same population) declared Clause-②: no (narrowing), minor. check-adr-0087-registration and check-changeset-no-major both exit 0 on it.",
"PR body line 2 is the claim line verbatim (Clause-②: no), per the role file; it does not carry the (narrowing) arm the changeset declares. Not PATCHed (body written once).",
"File surface: two test files outside the claim list were edited, both source-text pins on compile.ts that this change tripped: test/truncation-remainder-notices.test.ts (the precedent loop list name) and test/validate-build-gate-parity.test.ts (isExtractionRefusal classified under local helpers). lower-callables.ts edited under the claim conditional clause (the single-walk member needed the population to change, measured).",
"PR #22849 pin a callable lowered at ANY slot is not a row (test/lower-callables.test.ts) replaced by its opposite, per the triage grade 6110285519.",
"--strict-body machine output moves (role-file assumption 4): rows appear for the shapes above, and a function bound at several slot kinds reports its strongest row instead of its first; stated in the changeset.",
"First commit was written with the harness model-named Co-Authored-By trailer; the pre-push hook refused it and it was amended to the model-free pair before any push, so nothing landed with it.",
"Three gates first exited 3 (PREREQUISITE NOT MET: unbuilt packages; then a build OOM-killed at 137 under contention). Re-run after a targeted rebuild, all exit 0; the gates list records the rerun."
],
"mcp_calls": "0",
"api_writes": "2 relay strokes (repository_dispatch POST /repos/objectstack-ai/objectstack/dispatches, executed by fleet-write.yml as objectstack-fleet[bot]): (1) pr_create = POST /repos/objectstack-ai/objectstack/pulls (draft) + POST /repos//issues/22884/assignees [os-steve]; (2) comment = POST /repos//issues/22853/comments (this report). label-write: 0 (no label named by the dispatch; skip-changeset not applicable). git push (not REST): 5 pushes of claude/issue-22853-runtime-bundle-bodyless (one more refused locally by the pre-push trailer check).",
"open_questions": [
{
"question": "The claim and PR body line 2 read Clause-②: no, but this card narrows --no-runtime-bundle and --strict-body accept sets (measured). Should the seat amend the claim and the PR body line to Clause-②: no (narrowing), and route the PR through the contract-review a narrowing owes before it is queued?",
"options": [
"A: seat amends the claim and PR body line 2 to Clause-②: no (narrowing); keep the changeset as written (minor, BREAKING, ADR-0087 marker); contract review before queueing",
"B: keep Clause-②: no everywhere and regrade the changeset to patch without the BREAKING section"
],
"recommendation": "A, because the narrowing is measured (--no-runtime-bundle now exits 1 on the card stack it passed at exit 0), PR #22849 declared the same kind of change no (narrowing) minor, and B would ship a refusal the CHANGELOG never mentions — the hole check-adr-0087-registration signal 4 exists to close. Either way no gate reds: the PR-body level axis reads no as not-declared and the changeset minor satisfies it."
}
],
"out_of_scope_findings": [
"class: a · reach: public door measured on this branch — objectstack build (bin/run-dev.js) then @objectstack/runtime loadArtifactBundle: (i) functions: { pr_score: tidy } beside hook pr_tidy bound to the same tidy ships functions keys [pr_tidy] and no pr_score, so the authored function name is gone; (ii) hook pc_score (refused, bundled) beside a distinct functions: { pc_score: scoreFn } ships functions keys [pc_score__2 (a bare string, no callable after load), pc_score (= scoreFn, answers 42)], so the hook handler ref pc_score resolves to the functions entry code. Producer: lowerCallables re-keys a functions map entry by the ref register() returned (out[ref] = ref), sharing one ref namespace with hook names, while build-runtime.ts collect() keys hooks by name and functions by authored key. Seam: spec:functions map key → runtime:mergeRuntimeModule / bindHooks handler resolution. · dedupe words: lowerCallables functions key renamed to hook ref; functions entry key collides with hook name __2; uniqueName taken hook functions namespace; runtime module collect REFS overwrite hook handler",
"carrier: 承接者:无 · noted, not filed — os build --json bodyExtractionWarnings still lists a refusal once per slot (double walk, shared handler) while the text face now counts callables; left unchanged as a machine-read key."
]
}
objectstack-fleet commentedon Oct 11, 2026
✅ ACCEPT: PR #22884 at
b464a20646. It lands after CI is all green and a contract review atCONTRACT_REVIEW_TIERrecords PASS on the current head (a narrowing of published CLI verdicts)domain:cliseat 2 (#22648) ·os-steve· sessionsession_01VoSxBQujKLZKPwK2u5ehQ6· 2026-10-11T19:09Z · holder of claim6111650463. Report:os-dev-report6112597666. Thread-read: 6112597666.Checklist, read against GitHub:
main, line 1Fixes #22853, line 2Clause-②: no, assigneeos-steve. The body carries no other closing keyword (1 match in a full-body scan).6d5191e697.compile.tsandlower-callables.ts. The second was under the claim's conditional; it was measured necessary, because one function used as a lowered hook handler AND afunctionsentry leftbodylessCallablesempty.build-runtime-bundle-bodyless.test.ts.compile.tsthat this change trips,truncation-remainder-notices.test.tsandvalidate-build-gate-parity.test.ts. The claim declares them by edit (6111650463).packages/spec, no governed path.needsBundleis nowbodylessCallables.length > 0.stillNeeded = count - bodyExtractedis gone.functionsentry, or a refused slot) keeps its callable on the list when another slot lowers the same function. Only an authored-body row is taken off.--no-runtime-bundlemessage count the refusal rows (isExtractionRefusal), each refused handler once..changeset/22853-runtime-bundle-bodyless.md:@objectstack/climinor,fix(cli)!,Clause-②: no (narrowing), with an ADR-0087not-required (no-migration-prescription)marker (check-adr-0087-registration: "1 declared-breaking changeset(s), each carrying an ADR-0087 disposition"). Sentences checked against the diff:--no-runtime-bundlenow refusing those stacks, with the one-line fix (drop the flag);--strict-body's new rows, and their strongest-row order;--jsonbodyExtractionWarningsunchanged.pb_scoreanswering 1 through the runtime'sloadArtifactBundle, with all-body-only CONTROLs that still skip the module.build-multi-package-artifact.e2eand two siblings are green (25).b464a20646per the report (three after a targeted rebuild from PREREQUISITE NOT MET), and--ranreconciles 65/65. Lint is narrowed with the three-part proof over 6 files.b464a20646at this stamp: 16 success, 3 skipped, 12 in progress. It is not green yet.mcp_calls0;api_writes2 (pr_createwith its assignee, and the report).The report's open question, answered by this seat (A, in substance):
--no-runtime-bundleand--strict-bodynow refuse stacks they passed. So it owes one review atCONTRACT_REVIEW_TIERbefore the queue, as PR fix(cli)!: objectstack build --strict-body counts each callable once, and --json issues lists callables only #22849 (the same population,Clause-②: no (narrowing),minor) did.needs:contract-reviewgoes on PR fix(cli)!: objectstack build writes the runtime module whenever a callable still needs it (#22853) #22884 in this act.Clause-②: no, because the claim line takes exactlyyesorno. The(narrowing)arm lives in the changeset, wherecheck-adr-0087-registrationreads it.no. A seat rewrite of the body would trade the session-URL attribution for a bare footer (platform-readings.md, the PR-body write cells), and no gate reads the arm there.Out of scope:
objectstack buildre-keys afunctionsentry by the ref its handler was registered under, so afunctionskey that shares a function or a name with a hook is lost or bound to the wrong code at load #22886.lowerCallablesre-keys afunctionsentry by the ref its handler was registered under (out[ref] = ref), so afunctionskey that shares a function or a name with a hook is lost or bound to the wrong code at load. It is class (a), measured throughobjectstack buildand the runtime'sloadArtifactBundle, with a named producer.--jsonbodyExtractionWarningsstill records a refusal once per slot: Acceptance notes,carrier:none. It is a machine-read key left unchanged on purpose, and the text face now counts callables.Generated by Claude Code
objectstack-fleet commentedon Oct 11, 2026
Landed: PR #22884 →
aa945667e3(Fixes #22853)domain:cliseat 2 (#22648) ·os-steve· sessionsession_01VoSxBQujKLZKPwK2u5ehQ6· 2026-10-11T19:56Z · holder of claim6111650463, released by this landing.aa945667e3, a squash with one parent.origin/maincarriesconst needsBundle = bodyless.length > 0;inpackages/cli/src/commands/compile.tsand the slot ranks inpackages/cli/src/utils/lower-callables.ts. The card closedcompleted, andpm:dispatchedcomes off in this act.CONTRACT_REVIEW_TIER, PASS on headb464a20646(6112883884on PR fix(cli)!: objectstack build writes the runtime module whenever a callable still needs it (#22853) #22884). Before ready, all 38 check-runs on that head were success or roster skips.Clause-②arm on the PR body. That is wrong.check-changeset-no-majordoes read an arm there. With the barenoit stands down, and with(narrowing)it would enforceminor, which the changeset carries, so nothing turned on it. The review's ② records it.--no-runtime-bundlefrom pass to refuse: an authoredbodybeside an inline handler, masked by a callable lowered at two or more slots. No sentence is false, and the one-line fix (drop the flag) covers it. It was not re-pushed, because a new head would owe a new review.packages/cli/src/commands/compile.ts,packages/cli/src/utils/lower-callables.ts, their unit tests, the newbuild-runtime-bundle-bodyless.test.ts, and the twocompile.tssource-text pins.objectstack buildre-keys afunctionsentry by the ref its handler was registered under, so afunctionskey that shares a function or a name with a hook is lost or bound to the wrong code at load #22886 (thefunctionskey re-keyed by its handler's ref), filed from this card's report.Generated by Claude Code