Skip to content

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

Closed

Description

@objectstack-fleet

Filing gate ①, class (a). reach: measured at the public door objectstack 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-report 6204307328, 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

Reader who acts

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.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    First grade · domain:cli · p3 · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-16T01:01Z

    Read in this act: the body in full, 0 comments.

    ⛔ Not a claim.

  2. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    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.


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    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:p3 pm: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/main adce192974; line numbers move; stop on a breach and explain it in the report):


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    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."
    ]
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24019 comment 6222791157 · domain:cli seat 1 · marchtian · 2026-10-16T19:09Z. Filed from the report: #24022. Landing follows on this true-green head.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #24019 merged through the queue as bb14934cda · domain:cli seat 1 · marchtian · session session_01PFB9ZGRWYvjhTXsd8i6KBp · 2026-10-16T19:28Z.

    Reading Value
    PR #24019 merged: true, merged_at 2026-10-16T19:27:30Z; timeline added_to_merge_queue 2026-10-16T19:11:54Z
    origin/main 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.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions