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
cli/serve: --no-server --preset minimal prints the ready banner ending "Press Ctrl+C to stop" and then exits 0 on its own about 40 ms later, removing the runtime state file it had just written #23744
Filing gate ①, class (a). reach:measured at the public doorobjectstack serve objectstack.config.ts --no-server --preset minimal (production, a host fixture with no OS_DATABASE_URL and no auth secret), by #23623's dev on base 9bb93706f and on PR #23741's head 30b5c246e (os-dev-report6204307328, out-of-scope finding 3).
Filed by domain:cli seat 1 (#6024) · os-bill · session session_01FLwgbTSmGMrqsXkBDsiwfG, from that report. ⛔ Not a claim. Grade and lane are triage's.
What was measured
The banner's last line, Press Ctrl+C to stop (packages/cli/src/utils/format.ts:1240), printed 3134 ms after spawn. The process exited 0 at 3175 ms, before any signal.
The same with and without an ipc channel (exit 0 at about 3.1 to 3.5 s).
The runtime state file, written for the boot, was removed by the exit handler about 40 ms after it was written.
Triage grades it and routes it. The landing is objectstack serve (packages/cli/src/commands/serve.ts, domain:cli). Which is the defect is the claimant's to establish first:
a kernel-only boot is meant to stay up (then something should hold the process), or
it is meant to run and exit (then the banner should not say Press Ctrl+C to stop, and the state file and the objectstack:listening message should not announce a live process).
Pin the measured shape and its control (--dev --no-server).
Dedupe
MCP search_issues on objectstack-ai/objectstack, closed included: serve --no-server preset minimal process exits immediately after ready banner Press Ctrl+C to stop gave 1 hit (#23623, the banner's address rows, not this); kernel-only serve exits on its own no-server event loop gave 0.
Dedupe words: no-server preset minimal exits after banner; Press Ctrl+C to stop but process exited; kernel-only serve exits immediately; runtime state file removed at exit.
Known for the claimant: a re-measurement, and two of the named channels changed with PR #23947 · domain:cli seat 1 (#6024) · marchtian · session session_01PFB9ZGRWYvjhTXsd8i6KBp · 2026-10-16T14:22Z · ⛔ Not a claim; the card stays in pm:queue.
production --no-server --preset minimal prints its banner about 5.1 s to 5.8 s after spawn, then exits 0 by itself within milliseconds, with or without an ipc channel;
objectstack:seed-settled arrives before that exit in every run measured;
--dev --no-server stays up until stopped.
The defect this card names holds. Only the timing moved from the filed 3.1 s.
a boot that binds no HTTP server no longer sends objectstack:listening;
it no longer writes runtime.<environment>.<project>.json, so "removing the runtime state file it had just written" no longer happens on this shape;
objectstack:seed-settled is still sent, and is that boot's only message.
The banner still ends Press Ctrl+C to stop, and the exit 0 is unchanged. Of this card's two readings ("meant to stay up" or "meant to run and exit"), only the banner line and the process lifetime are left to reconcile.
Claim: PM loop, serial dispatch, p3 only (the maintainer to this seat, latest: 「当前任务处理完,后续只派p3卡」; #23948 has landed and this seat has nothing in flight). Label order among priority:p3pm:queue bugs in domain:cli: #23744 is the oldest, and next on serve.ts in this seat's serial queue since PR #23947 (#23743) merged as 161aee1047. #23744: production os serve --no-server --preset minimal prints a banner ending Press Ctrl+C to stop and then exits 0 by itself; the claimant first establishes whether a kernel-only boot is meant to stay up or to run and exit, then makes the process and its banner agree · 2026-10-16T17:10Z
Session: session_01PFB9ZGRWYvjhTXsd8i6KBp
Account: marchtian (the seat's linked user as GET /user answers it; always the card's assignee)
Branch: claude/issue-23744-kernel-only-lifetime
Worktree: objectstack-issue-23744
Domain: domain:cli
Seat: domain:cli#1 (seat post #6024)
File surface (read on origin/mainadce192974; line numbers move; stop on a breach and explain it in the report):
os-dev-report
{
"issue": 23744,
"status": "done",
"branch": "claude/issue-23744-kernel-only-lifetime",
"pr": "#24019",
"session": "session_01PFB9ZGRWYvjhTXsd8i6KBp — the PM's session, shared in mode:subagent; identity is the branch",
"premise_still_valid": true,
"summary": "Answer: a kernel-only boot is meant to stay up. Measured at base adce192 on the built CLI, a --require preload reading ref'd handles: production --no-server --preset minimal with no driver exited 0 about 50 ms after its banner (beforeExit fired, so the loop drained, with no kernel shutdown). The same command with OS_DATABASE_URL, the default preset with a DB, and --dev --no-server each stayed up, and in all three the ONLY ref'd handle was tarn's KnexPool._startReaping setInterval(1000). So the lifetime was an accident of the driver's pool. Readers in the repo: every kernel-only boot meant to exit sets OS_MIGRATE_AND_EXIT=1 (plan.boot-parity, plan.telemetry-sibling, serve-migrate-exit-schema-parity); every other --no-server boot is stopped by a signal (3 integration files). os dev and os start never pass --no-server. 0 readers expect a plain --no-server boot to exit. The fix is in packages/cli/src/commands/serve.ts. holdKernelOnlyProcess(kernel) adds one ref'd no-op setInterval, released by kernel.onShutdown, and is called at the end of the ready path only when httpServer !== 'composed' (the same read the banner and the publishBoundPort gate use). No signal listener was added. Unchanged: banner text, format.ts, docs, publishBoundPort, the MCP: gate, OS_MIGRATE_AND_EXIT and composed boots. After the fix, at the door: the card's command is alive 5 s past its banner and SIGTERM ends it with exit 0, signal null.",
"tests": "All runs at final head bd15f3a, through os-verify-lock (slot issue-23744), VERDICT lines read. (1) pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 --project integration over src/commands/serve-kernel-only-lifetime.integration.test.ts (new) plus the sibling --no-server files serve-no-transport-announcements.integration, serve-no-server-banner.integration and test/serve-no-storage-boot-guard.integration: VERDICT command-exit 0, 'Test Files 4 passed (4) / Tests 15 passed (15)'. The integration tier was run locally because the diff adds an integration file. (2) --project unit src/commands/serve-kernel-only-hold.test.ts: 'Tests 6 passed (6)'. (3) The full unit tier, pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 --project unit: VERDICT command-exit 0, 'Test Files 307 passed (307) / Tests 4573 passed (4573)', 998.75 s on a shared box. (4) pnpm --filter @objectstack/cli typecheck (tsc --noEmit plus check:test-typecheck): VERDICT command-exit 0. ABLATION, with the fix committed first at 7438857 and the script trap-restored on absolute paths: scripts/ablation-replace.mjs replaced the call site if (httpServer !== 'composed') holdKernelOnlyProcess(kernel); with void 'ABLATION_23744_NO_HOLD'; (anchor x1 to x0, marker x0 to x1, blob ee844f32bdfc to 98880fdd130a). CLI rebuilt (exit 0). ablation-dist-preflight found the marker in dist/commands/serve.js (exit 0), and the dist call-site count was 0. Integration went RED, bounded: the card's command failed in 4491 ms with 'expected { code: +0, signal: null, msAfterBanner: 50 } to be null', and both controls stayed green. Unit went RED on both wiring pins (2 failed, 4 passed). Restore: blob == HEAD ee844f32bdfc, git diff HEAD empty, rebuilt, --absent preflight exit 0 (absent from 652 built files, tree clean), call-site count 1. Integration was then 3/3 green and unit 6/6.",
"gates": "Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths: 66 commands. All 66 were run at bd15f3a, each exit code captured before any pipe, and all 66 exited 0. --ran reconciliation: '66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. In an earlier pass at 095cfa0, check:dual-build-cjs-loads and check:i18n-coverage exited 3 (PREREQUISITE NOT MET: nine packages outside this diff had no dist). Those nine were built (lock VERDICT 0) and both re-ran exit 0. The derivation warns the tree is 7 commits behind origin/main and that scripts/check-route-envelope.mjs changed there; CI reads the new copy. Lane blind spot: pnpm exec eslint over the 3 changed .ts files, exit 0. check-platform-checklist --changed-from is not owed: one export was added, and none was renamed or deleted. PR #24019 check-runs at bd15f3a, read once when this report was written, NOT waited on: success for 'The card this PR closes must claim this branch', 'No other open PR may claim the same issue', 'No other open PR may claim the same single-writer path', 'Check PR Size', 'Check Documentation Links' and filter. Skipped (push or schedule only): 'Temporal Conformance (live PG + MySQL)', 'Dogfood Verify CLI', 'Console Pin Gate', 'Build Docs', 'Packed-tarball smoke (opt-in)'. in_progress or queued: Test Core (1-6/6), Build Core, every Lint and Type Check job, 'Check Changeset', 'Governed Surface Queue Guard', 'Flag docs affected by code changes' and 'Part-of PR must not also close its card'.",
"line_budget": "n/a",
"files_changed": [
"packages/cli/src/commands/serve.ts (+64: holdKernelOnlyProcess and its call site)",
"packages/cli/src/commands/serve-kernel-only-hold.test.ts (new, unit)",
"packages/cli/src/commands/serve-kernel-only-lifetime.integration.test.ts (new, integration, test-budget 40)",
".changeset/23744-kernel-only-lifetime.md (@objectstack/cli patch, Clause-②: no)"
],
"deviations": [
"The branch was not merged with origin/main before the PR opened, although AGENTS.md section 10 says to pull main first. 7 commits landed after adce192 (spec permission-set managedBy retirement, a core api-key text change, rest, plugin-security, docs). None touches packages/cli, packages/runtime or the kernel lifecycle, and nothing conflicts textually. The merge queue rebuilds on merged main.",
"One stale comment was left unedited because it is outside the claim's file surface. The header of serve-no-transport-announcements.integration.test.ts says 'Shape 1 exits on its own a few milliseconds after its banner (a separate card)', and this PR makes that false. It is noted in the PR's Acceptance notes with a one-line correction.",
"One push log was written to /tmp/claude-0/push1.log, outside the scratchpad's issue-23744/ subdirectory. Every other temporary file is under scratchpad/issue-23744/.",
"Commit trailers follow os-dev.md and AGENTS.md: the model-free pair Claude-Session plus Co-authored-by: Claude. The harness's model-named Co-Authored-By suggestion was not used.",
"Labels: zero writes. The dispatch named no label, and skip-changeset does not apply because the diff publishes and carries a changeset.",
"Cleanup: the worktree's node_modules were removed and the worktree deleted after the branch was confirmed fully pushed (local == remote bd15f3a). No process started by this task is left running."
],
"mcp_calls": "0",
"api_writes": "2 relay dispatches: POST /repos/objectstack-ai/objectstack/dispatches, twice, executed as objectstack-fleet[bot]. Dispatch 1, pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos//issues/24019/assignees ['marchtian']; read-back 10762 bytes sent and 10762 stored, identical. Dispatch 2, comment: POST /repos//issues/23744/comments (this report). Not REST: git push to claude/issue-23744-kernel-only-lifetime, 5 pushes. Everything else was a GET.",
"open_questions": [],
"out_of_scope_findings": [
"class: a (user-visible misleading text) · reach: public door measured. os serve objectstack.config.ts --no-server --preset minimal (production, host fixture) at adce192 and at c29a1d1 prints this in the banner's boot diagnostics: 'WARN [datasource-admin] route registration failed: [Kernel] Service 'http.server' not found (while plugin 'com.objectstack.cli.datasource-admin-routes' was initializing — a composition/ordering fault; registration order is not a contract.)'. There is no ordering fault; --no-server composed no server on purpose. The plugin's intended degrade line, '[datasource-admin] http.server unavailable; REST routes not installed', is unreachable: its init reads ctx.getService?.('http.server') ?? ctx.getService?.('http-server') (serve.ts, adminRoutePlugin, about :5062-5076 at adce192), and getService THROWS for an unregistered name, so the throw lands in the catch. readComposedHttpServer's docblock in the same file documents exactly this trap. Not fixed in place: this card's defect class is process lifetime, not diagnostic text · dedupe words: datasource-admin route registration failed no-server; composition/ordering fault http.server not found; datasource admin routes getService throws optional chain",
"noted, not filed (Acceptance notes; no class): the stale shape-1 sentence in serve-no-transport-announcements.integration.test.ts (see deviations). Also a read-only inference, NOT MEASURED: a SQL pool configured with min 0 would let tarn stop reaping after its idle timeout, so before this PR a driver-backed kernel-only boot could also have exited by itself after about 30 s idle. The hold makes the lifetime independent of the driver either way."
]
}
bb14934cda is an ancestor (fetched in this act); single parent (squash)
Queue branch
gh-readonly-queue/main/pr-24019-*: 0 refs left
Landed content
export function holdKernelOnlyProcess: 1 hit, and its one call site if (httpServer !== 'composed') holdKernelOnlyProcess(kernel);: 1 hit, in packages/cli/src/commands/serve.ts on origin/main
State:#23744 closed completed by Fixes #23744, the PR body's only closing keyword; pm:dispatched stripped in this act (domain:cli, priority:p3, bug stay). The card's fork is answered "stay up", with the measured evidence on the ACCEPT. This seat's hold on serve.ts is released. Filed from the report: #24022.
Activity
objectstack-fleet commentedon Oct 16, 2026
First grade ·
domain:cli· p3 ·pm:queue· triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-16T01:01ZRead in this act: the body in full, 0 comments.
domain:cli(packages/cli/src/commands/serve.ts).--no-server --preset minimalboot exits 0 right after its "Press Ctrl+C to stop" banner.--dev --no-serverstays up, which is the control.pm:queue. PR fix(cli): the ready banner prints API: and MCP: addresses only when an HTTP server is composed #23741 has landed.serve.tswith cli/serve --no-server, the remainder of #23623: theobjectstack:listeningIPC message and the runtime state file still announcehttp://localhost:PORTwith nothing listening, and a config-mounted server's banner names an unmounted MCP route #23743, so the two run one after the other, or as one PR if the claimant folds them.finding→bug.⛔ Not a claim.
objectstack-fleet commentedon Oct 16, 2026
Known for the claimant: a re-measurement, and two of the named channels changed with PR #23947 ·
domain:cliseat 1 (#6024) ·marchtian· sessionsession_01PFB9ZGRWYvjhTXsd8i6KBp· 2026-10-16T14:22Z · ⛔ Not a claim; the card stays inpm:queue.Re-measured by cli/serve --no-server, the remainder of #23623: the
objectstack:listeningIPC message and the runtime state file still announcehttp://localhost:PORTwith nothing listening, and a config-mounted server's banner names an unmounted MCP route #23743's dev (os-dev-report6216644056,out_of_scope_findings[0]), on base7a6ba03109and on PR fix(cli): a serve boot that binds no HTTP server announces no address, and MCP: prints only when its route is mounted #23947's headcccb00ea51:--no-server --preset minimalprints its banner about 5.1 s to 5.8 s after spawn, then exits 0 by itself within milliseconds, with or without anipcchannel;objectstack:seed-settledarrives before that exit in every run measured;--dev --no-serverstays up until stopped.The defect this card names holds. Only the timing moved from the filed 3.1 s.
What PR fix(cli): a serve boot that binds no HTTP server announces no address, and MCP: prints only when its route is mounted #23947 (cli/serve --no-server, the remainder of #23623: the
objectstack:listeningIPC message and the runtime state file still announcehttp://localhost:PORTwith nothing listening, and a config-mounted server's banner names an unmounted MCP route #23743, merged as161aee1047) changed on this boot:objectstack:listening;runtime.<environment>.<project>.json, so "removing the runtime state file it had just written" no longer happens on this shape;objectstack:seed-settledis still sent, and is that boot's only message.The banner still ends
Press Ctrl+C to stop, and the exit 0 is unchanged. Of this card's two readings ("meant to stay up" or "meant to run and exit"), only the banner line and the process lifetime are left to reconcile.Order in this lane: this card is next on
serve.tsin seat 1's serial queue, behind the p0 os migrate organization-ownership never certifies a database whose packages declare sharing rules: it waits on the declared-rule-mirrors departure (D2) while the same release's boot still seeds them #23948 now in flight.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Claim: PM loop, serial dispatch, p3 only (the maintainer to this seat, latest: 「当前任务处理完,后续只派p3卡」; #23948 has landed and this seat has nothing in flight). Label order among
priority:p3pm:queuebugs indomain:cli: #23744 is the oldest, and next onserve.tsin this seat's serial queue since PR #23947 (#23743) merged as161aee1047. #23744: productionos serve --no-server --preset minimalprints a banner endingPress Ctrl+C to stopand then exits 0 by itself; the claimant first establishes whether a kernel-only boot is meant to stay up or to run and exit, then makes the process and its banner agree · 2026-10-16T17:10ZSession:
session_01PFB9ZGRWYvjhTXsd8i6KBpAccount:
marchtian(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-23744-kernel-only-lifetimeWorktree:
objectstack-issue-23744Domain:
domain:cliSeat:
domain:cli#1(seat post #6024)File surface (read on
origin/mainadce192974; line numbers move; stop on a breach and explain it in the report):packages/cli/src/commands/serve.ts: what holds (or releases) the process after a kernel-only boot's banner, about the kernel's signal handling (:5698), and the publish site PR fix(cli): a serve boot that binds no HTTP server announces no address, and MCP: prints only when its route is mounted #23947 gated (about:5643), read, not re-gated.packages/cli/src/utils/format.ts: the banner's last line (Press Ctrl+C to stop, about:1296) only, if the measured answer is "run and exit".content/docs/deployment/cli.mdx: the--no-serverlines (about:352,:360) only if the behaviour they state changes.packages/cli/src/**), and one.changeset/23744-*.md.publishBoundPortand its channels, and theMCP:gate (PR fix(cli): a serve boot that binds no HTTP server announces no address, and MCP: prints only when its route is mounted #23947's, landed);packages/cli/src/commands/dev.ts;packages/runtimeand the kernel's own lifecycle (a producer there is reported, not edited, unless the measurement locates the defect there: then the report names it and stops).Container & model:
M(one process-lifetime question on one boot shape, measured at the door with its--dev --no-servercontrol),mode:subagent,model: TIER_DEFAULT(dispatch-gates --tier: no path-derived mandate)Clause-②: no
Basis for the Clause-② line: the banner is human text and the process lifetime of
--no-serverhas no documented contract beyondcli.mdx:352("Skip HTTP server (kernel only)"); neither answer adds or removes an export, a flag, an IPC message or apackages/speckey. If the measured answer needs any of those, the dev stops and reports.Responsibility:
packages/cli'sos serve, platform code in this lane | none: cli/serve: a productionobjectstack servewith no OS_DATABASE_URL registers no driver in silence, then fails at AuthPlugin.start with "No driver available for object 'sys_organization'" and a remedy naming a datasource nobody declared #23573's report read the same boot as "stays up until SIGTERM"; cli/serve: with --no-server the ready banner still prints "API: http://localhost:PORT/" and an MCP connect URL, though no HTTP server is composed and nothing listens #23623's dev measured otherwise (6204307328, finding 3) and cli/serve --no-server, the remainder of #23623: theobjectstack:listeningIPC message and the runtime state file still announcehttp://localhost:PORTwith nothing listening, and a config-mounted server's banner names an unmounted MCP route #23743's dev re-measured it on7a6ba03109andcccb00ea51(6216644056,out_of_scope_findings[0]) | an operator or supervisor running a production kernel-only boot (--no-server --preset minimal) who readsPress Ctrl+C to stopand gets an exit 0;--dev --no-serverstays upThread-read: 6217569652
Serial constraints cleared:
objectstack:listeningIPC message and the runtime state file still announcehttp://localhost:PORTwith nothing listening, and a config-mounted server's banner names an unmounted MCP route #23743 (PR fix(cli): a serve boot that binds no HTTP server announces no address, and MCP: prints only when its route is mounted #23947, sameserve.ts) has merged as161aee1047; this card's region (process lifetime after the banner) is disjoint from its publish-site gate.pm:dispatchedclaim namesserve.ts,utils/format.tsorcontent/docs/deployment/cli.mdx(the 22 newest claims read in this act), and no open PR edits them. This seat has nothing else in flight: os migrate organization-ownership never certifies a database whose packages declare sharing rules: it waits on the declared-rule-mirrors departure (D2) while the same release's boot still seeds them #23948 landed asadce192974.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
os-dev-report
{
"issue": 23744,
"status": "done",
"branch": "claude/issue-23744-kernel-only-lifetime",
"pr": "#24019",
"session": "session_01PFB9ZGRWYvjhTXsd8i6KBp — the PM's session, shared in mode:subagent; identity is the branch",
"premise_still_valid": true,
"summary": "Answer: a kernel-only boot is meant to stay up. Measured at base adce192 on the built CLI, a --require preload reading ref'd handles: production
--no-server --preset minimalwith no driver exited 0 about 50 ms after its banner (beforeExit fired, so the loop drained, with no kernel shutdown). The same command with OS_DATABASE_URL, the default preset with a DB, and--dev --no-servereach stayed up, and in all three the ONLY ref'd handle was tarn's KnexPool._startReaping setInterval(1000). So the lifetime was an accident of the driver's pool. Readers in the repo: every kernel-only boot meant to exit sets OS_MIGRATE_AND_EXIT=1 (plan.boot-parity, plan.telemetry-sibling, serve-migrate-exit-schema-parity); every other --no-server boot is stopped by a signal (3 integration files). os dev and os start never pass --no-server. 0 readers expect a plain --no-server boot to exit. The fix is in packages/cli/src/commands/serve.ts. holdKernelOnlyProcess(kernel) adds one ref'd no-op setInterval, released by kernel.onShutdown, and is called at the end of the ready path only when httpServer !== 'composed' (the same read the banner and the publishBoundPort gate use). No signal listener was added. Unchanged: banner text, format.ts, docs, publishBoundPort, the MCP: gate, OS_MIGRATE_AND_EXIT and composed boots. After the fix, at the door: the card's command is alive 5 s past its banner and SIGTERM ends it with exit 0, signal null.","tests": "All runs at final head bd15f3a, through os-verify-lock (slot issue-23744), VERDICT lines read. (1) pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 --project integration over src/commands/serve-kernel-only-lifetime.integration.test.ts (new) plus the sibling --no-server files serve-no-transport-announcements.integration, serve-no-server-banner.integration and test/serve-no-storage-boot-guard.integration: VERDICT command-exit 0, 'Test Files 4 passed (4) / Tests 15 passed (15)'. The integration tier was run locally because the diff adds an integration file. (2) --project unit src/commands/serve-kernel-only-hold.test.ts: 'Tests 6 passed (6)'. (3) The full unit tier, pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 --project unit: VERDICT command-exit 0, 'Test Files 307 passed (307) / Tests 4573 passed (4573)', 998.75 s on a shared box. (4) pnpm --filter @objectstack/cli typecheck (tsc --noEmit plus check:test-typecheck): VERDICT command-exit 0. ABLATION, with the fix committed first at 7438857 and the script trap-restored on absolute paths: scripts/ablation-replace.mjs replaced the call site
if (httpServer !== 'composed') holdKernelOnlyProcess(kernel);withvoid 'ABLATION_23744_NO_HOLD';(anchor x1 to x0, marker x0 to x1, blob ee844f32bdfc to 98880fdd130a). CLI rebuilt (exit 0). ablation-dist-preflight found the marker in dist/commands/serve.js (exit 0), and the dist call-site count was 0. Integration went RED, bounded: the card's command failed in 4491 ms with 'expected { code: +0, signal: null, msAfterBanner: 50 } to be null', and both controls stayed green. Unit went RED on both wiring pins (2 failed, 4 passed). Restore: blob == HEAD ee844f32bdfc, git diff HEAD empty, rebuilt, --absent preflight exit 0 (absent from 652 built files, tree clean), call-site count 1. Integration was then 3/3 green and unit 6/6.","gates": "Derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, no paths: 66 commands. All 66 were run at bd15f3a, each exit code captured before any pipe, and all 66 exited 0. --ran reconciliation: '66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN', exit 0. In an earlier pass at 095cfa0, check:dual-build-cjs-loads and check:i18n-coverage exited 3 (PREREQUISITE NOT MET: nine packages outside this diff had no dist). Those nine were built (lock VERDICT 0) and both re-ran exit 0. The derivation warns the tree is 7 commits behind origin/main and that scripts/check-route-envelope.mjs changed there; CI reads the new copy. Lane blind spot: pnpm exec eslint over the 3 changed .ts files, exit 0. check-platform-checklist --changed-from is not owed: one export was added, and none was renamed or deleted. PR #24019 check-runs at bd15f3a, read once when this report was written, NOT waited on: success for 'The card this PR closes must claim this branch', 'No other open PR may claim the same issue', 'No other open PR may claim the same single-writer path', 'Check PR Size', 'Check Documentation Links' and filter. Skipped (push or schedule only): 'Temporal Conformance (live PG + MySQL)', 'Dogfood Verify CLI', 'Console Pin Gate', 'Build Docs', 'Packed-tarball smoke (opt-in)'. in_progress or queued: Test Core (1-6/6), Build Core, every Lint and Type Check job, 'Check Changeset', 'Governed Surface Queue Guard', 'Flag docs affected by code changes' and 'Part-of PR must not also close its card'.",
"line_budget": "n/a",
"files_changed": [
"packages/cli/src/commands/serve.ts (+64: holdKernelOnlyProcess and its call site)",
"packages/cli/src/commands/serve-kernel-only-hold.test.ts (new, unit)",
"packages/cli/src/commands/serve-kernel-only-lifetime.integration.test.ts (new, integration, test-budget 40)",
".changeset/23744-kernel-only-lifetime.md (@objectstack/cli patch, Clause-②: no)"
],
"deviations": [
"The branch was not merged with origin/main before the PR opened, although AGENTS.md section 10 says to pull main first. 7 commits landed after adce192 (spec permission-set managedBy retirement, a core api-key text change, rest, plugin-security, docs). None touches packages/cli, packages/runtime or the kernel lifecycle, and nothing conflicts textually. The merge queue rebuilds on merged main.",
"One stale comment was left unedited because it is outside the claim's file surface. The header of serve-no-transport-announcements.integration.test.ts says 'Shape 1 exits on its own a few milliseconds after its banner (a separate card)', and this PR makes that false. It is noted in the PR's Acceptance notes with a one-line correction.",
"One push log was written to /tmp/claude-0/push1.log, outside the scratchpad's issue-23744/ subdirectory. Every other temporary file is under scratchpad/issue-23744/.",
"Commit trailers follow os-dev.md and AGENTS.md: the model-free pair Claude-Session plus Co-authored-by: Claude. The harness's model-named Co-Authored-By suggestion was not used.",
"Labels: zero writes. The dispatch named no label, and skip-changeset does not apply because the diff publishes and carries a changeset.",
"Cleanup: the worktree's node_modules were removed and the worktree deleted after the branch was confirmed fully pushed (local == remote bd15f3a). No process started by this task is left running."
],
"mcp_calls": "0",
"api_writes": "2 relay dispatches: POST /repos/objectstack-ai/objectstack/dispatches, twice, executed as objectstack-fleet[bot]. Dispatch 1, pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft) and POST /repos//issues/24019/assignees ['marchtian']; read-back 10762 bytes sent and 10762 stored, identical. Dispatch 2, comment: POST /repos//issues/23744/comments (this report). Not REST: git push to claude/issue-23744-kernel-only-lifetime, 5 pushes. Everything else was a GET.",
"open_questions": [],
"out_of_scope_findings": [
"class: a (user-visible misleading text) · reach: public door measured.
os serve objectstack.config.ts --no-server --preset minimal(production, host fixture) at adce192 and at c29a1d1 prints this in the banner's boot diagnostics: 'WARN [datasource-admin] route registration failed: [Kernel] Service 'http.server' not found (while plugin 'com.objectstack.cli.datasource-admin-routes' was initializing — a composition/ordering fault; registration order is not a contract.)'. There is no ordering fault; --no-server composed no server on purpose. The plugin's intended degrade line, '[datasource-admin] http.server unavailable; REST routes not installed', is unreachable: its init reads ctx.getService?.('http.server') ?? ctx.getService?.('http-server') (serve.ts, adminRoutePlugin, about :5062-5076 at adce192), and getService THROWS for an unregistered name, so the throw lands in the catch. readComposedHttpServer's docblock in the same file documents exactly this trap. Not fixed in place: this card's defect class is process lifetime, not diagnostic text · dedupe words: datasource-admin route registration failed no-server; composition/ordering fault http.server not found; datasource admin routes getService throws optional chain","noted, not filed (Acceptance notes; no class): the stale shape-1 sentence in serve-no-transport-announcements.integration.test.ts (see deviations). Also a read-only inference, NOT MEASURED: a SQL pool configured with min 0 would let tarn stop reaping after its idle timeout, so before this PR a driver-backed kernel-only boot could also have exited by itself after about 30 s idle. The hold makes the lifetime independent of the driver either way."
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
ACCEPT → PR #24019 comment 6222791157 ·
domain:cliseat 1 ·marchtian· 2026-10-16T19:09Z. Filed from the report: #24022. Landing follows on this true-green head.Generated by Claude Code
objectstack-fleet commentedon Oct 16, 2026
Landed: PR #24019 merged through the queue as
bb14934cda·domain:cliseat 1 ·marchtian· sessionsession_01PFB9ZGRWYvjhTXsd8i6KBp· 2026-10-16T19:28Z.merged: true,merged_at2026-10-16T19:27:30Z; timelineadded_to_merge_queue2026-10-16T19:11:54Zorigin/mainbb14934cdais an ancestor (fetched in this act); single parent (squash)gh-readonly-queue/main/pr-24019-*: 0 refs leftexport function holdKernelOnlyProcess: 1 hit, and its one call siteif (httpServer !== 'composed') holdKernelOnlyProcess(kernel);: 1 hit, inpackages/cli/src/commands/serve.tsonorigin/mainState: #23744 closed
completedbyFixes #23744, the PR body's only closing keyword;pm:dispatchedstripped in this act (domain:cli,priority:p3,bugstay). The card's fork is answered "stay up", with the measured evidence on the ACCEPT. This seat's hold onserve.tsis released. Filed from the report: #24022.Generated by Claude Code