Skip to content

cli/serve --no-server, the remainder of #23623: the objectstack:listening IPC message and the runtime state file still announce http://localhost:PORT with nothing listening, and a config-mounted server's banner names an unmounted MCP route #23743

Closed

Description

@objectstack-fleet

Filing gate ①. This is the remainder of #23623: the address announcements PR #23741 left as they are, because the seat's dispatch fenced them out. Both are measured at the public door by #23623's dev, on base 9bb93706f and on PR #23741's head 30b5c246e (os-dev-report 6204307328, out-of-scope findings 1 and 2, and open_questions 1).

Filed by domain:cli seat 1 (#6024) · os-bill · session session_01FLwgbTSmGMrqsXkBDsiwfG, in the same act as the seat's review of PR #23741. ⛔ Not a claim. Grade and lane are triage's.

1. The machine channels, class (b)

objectstack serve objectstack.config.ts --no-server --preset minimal (production, a host fixture, spawned with an ipc channel) received { type: 'objectstack:listening', port: 35809, url: 'http://localhost:35809' }. A GET to that port answered ECONNREFUSED. --dev --no-server did the same.

  • The contract it breaks: content/docs/deployment/cli.mdx:269: "objectstack:listening | os serve | The HTTP server is bound. Carries { port, url } — the port actually bound".
  • runtime.<environment>.<project>.json is written with the same port and url on every --no-server boot measured. No docs page states a contract for that file; serve.ts calls it a best-effort supervision file.
  • Why: publishBoundPort (packages/cli/src/commands/serve.ts) publishes resolveBoundPort(kernel, port) on all three channels. With no transport registered, resolveBoundPort falls back to the requested port by design. PR fix(cli): the ready banner prints API: and MCP: addresses only when an HTTP server is composed #23741 makes only the banner read whether a transport is composed (readComposedHttpServer).
  • Reach: the message's only in-repo consumer is the os dev parent (dev.ts:707), and it never spawns a --no-server child (os dev declares no server flag). So no in-repo consumer is reached; an external supervisor that spawns os serve --no-server with an ipc channel is.

2. The banner's MCP: row under a config-mounted server, class (a)

objectstack serve objectstack.config.ts --no-server --preset minimal, with a config that mounts its own new HonoServerPlugin({ port }): the banner prints MCP: http://localhost:PORT/api/v1/mcp and its connect hint. GET /api/v1/mcp answers 404 (/api/v1/health 404 too), while /api/v1/data/fx_task answers 401, so the transport listens.

Reader who acts

Triage grades it and routes it. Both halves land in packages/cli/src/commands/serve.ts (domain:cli), after PR #23741.

  • Half 1: whether objectstack:listening and the state file are sent or written at all on a boot with no transport, or carry a field saying none is bound, is a consumer-contract question. The docs row is the contract.
  • Half 2: gate the MCP: row on the route's owner being composed, read off the kernel the way PR fix(cli): the ready banner prints API: and MCP: addresses only when an HTTP server is composed #23741 reads http.server. The dev's recommendation was to leave it until a producer of the shape appears (zero today).

Dedupe

MCP search_issues on objectstack-ai/objectstack, closed included: serve --no-server objectstack:listening IPC message runtime state file announces port url nothing listening gave 0 hits; objectstack:listening no-server gave 0; banner MCP row route not mounted dispatcher not composed 404 gave 2 (#9823 and #4886, both closed, neither this).

Dedupe words: objectstack:listening no-server; IPC listening message without HTTP server; runtime state file url no-server; config HonoServerPlugin MCP 404; banner MCP row unmounted route.


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:00Z

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

    ⛔ Not a claim.

  2. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1, the third slot of the maintainer's temporary concurrency (「临时并发可以加到3」; for this slot 「换一个卡派」, in place of #23863, which waits on PR #23862). Label order: the open pm:queue bugs left in domain:cli are p3; this is the oldest. #23743: on a --no-server boot, objectstack:listening and the runtime state file stop announcing an HTTP address nothing listens on, and the banner's MCP: row prints only when the route's owner is composed · 2026-10-16T10:37Z
    Session: session_01PFB9ZGRWYvjhTXsd8i6KBp
    Account: marchtian (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-23743-no-server-announcements
    Worktree: objectstack-issue-23743
    Domain: domain:cli
    Seat: domain:cli#1 (seat post #6024)
    File surface (read on origin/main 6422da58e8; line numbers move; stop on a breach and explain it in the report):


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 23743,
    "status": "done",
    "branch": "claude/issue-23743-no-server-announcements",
    "pr": "#23947",
    "session": "session_01PFB9ZGRWYvjhTXsd8i6KBp — the PM session's id, which this subagent shares (Claude-Session line on every commit); identity is the branch named in claim 6213641477",
    "premise_still_valid": true,
    "summary": "Both halves reproduced at the door on base 7a6ba03 before any edit. Half 1: production --no-server --preset minimal (ipc channel) received {type:'objectstack:listening', port:38393, url:'http://localhost:38393'} and found runtime.env_local.PROJECT.json with that url, and every probe answered ECONNREFUSED; --dev --no-server did the same. Half 2: a config-mounted HonoServerPlugin under --no-server printed MCP: plus its connect hint, while /api/v1/mcp answered 404 and /api/v1/data/fx_task answered 401. Fix, all in packages/cli/src/commands/serve.ts: the publish site runs publishBoundPort(...) only when httpServer === 'composed' and otherwise prints the banner alone. httpServer is the same resolveHttpServerComposition value the banner's address rows read, so one predicate decides all three channels. objectstack:seed-settled is still sent on such a boot and is its only message. The state file is not written on such a boot; its payload shape is unchanged. The banner's MCP: row now gets isMcpServerEnabled() && mcpRouteMounted, where mcpRouteMounted = httpServer === 'composed' && readComposedMcpRouteOwner(kernel), a new kernel read: kernel.hasPlugin('com.objectstack.runtime.dispatcher'), the plugin that mounts /api/v1/mcp. Both docs rows (cli.mdx :269-:270) were updated together. Zone 2 measured: (1) holds as stated. (2) The seed-settled consumers are the os dev relay (dev.ts:769, never spawns --no-server) and the docs example, which waits for seed-settled alone; SeedSettledMessage's no-hang rule decides that it is still sent, alone. (3) The state-file readers in this repo are scripts/publish-smoke.sh (spawns objectstack dev, reads .port, curls health) and CLI tests only; no docs contract exists; choice: not written. (4) No live route table exists on IHttpServer; the narrowest sound read is the kernel's plugin registry, which HonoServerPlugin already uses for the dispatcher name. Draft PR #23947 is open with assignee marchtian; CI is in_progress.",
    "tests": "New unit file src/commands/serve-no-transport-announcements.test.ts (10 cases): readComposedMcpRouteOwner against a real ObjectKernel (createDispatcherPlugin registered gives true; transport-only gives false); MCP_ROUTE_OWNER_PLUGIN read off createDispatcherPlugin().name; it asks for that name only; false when the kernel cannot answer; run() wiring source pins with comments masked. New integration file src/commands/serve-no-transport-announcements.integration.test.ts: 3 boots of bin/run.js with an ipc channel and a watched OS_HOME. (1) Production --no-server: no listening message, messages exactly ['objectstack:seed-settled'], no runtime.*.json ever created (expect.soft, 3 legs). (2) Control default boot: [listening, seed-settled], the message equals the API: row's {port,url}, the state file carries the same, MCP: row, health 200, /mcp not 404. (3) Hono --no-server: no MCP: row or hint, /mcp 404, IPC and state file carry the API: address. test-budget 30 from local runs of 19.4 / 18.9 / 20.9 s. Unit tier as 4 shards, pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 --shard=K/4, on 23b3033. Shard 1: 76 files, 1418 passed. Shard 2: 1099 passed, 3 failed, all 'Test timed out in 5000ms' while my own unlocked gate battery shared the cores; the 2 files re-run alone gave 'Test Files 2 passed (2) · Tests 41 passed (41)'. Shard 3: 918 passed. Shard 4: 1071 passed, 1 failed, a real one: serve-observability-registration.test.ts locates the transport by the first raw-source 'new HonoServerPlugin(' and my docblock spelled it; fixed in cccb00e. On final head cccb00e after rebuilding the CLI: 6 touched unit files 'Test Files 6 passed (6) · Tests 82 passed (82)'; integration, scoped (new file, serve-no-server-banner, test/serve-no-storage-boot-guard, test/dev-boot-output-order) 'Test Files 4 passed (4) · Tests 15 passed (15)'; OS_TEST_TIERS=nightly test/serve-publishes-bound-port.e2e.test.ts 'Tests 6 passed (6)'; the rest of the integration tier is declared to CI. Ablation (fix committed first; ablation-replace.mjs wrap mode plus a trap restoring from HEAD; CLI rebuilt; ablation-dist-preflight). Gate leg: anchor x1 to x0, blob 8de5619d0a58 to f04d083f4255, marker in 1 built file. Result 'Tests 3 failed | 10 passed (13)': all three no-transport soft legs red (listening sent, not the only message, state file written), both wiring pins red, both controls green; direction: turned red, as predicted. Restore: blob == HEAD, git diff HEAD empty, status clean, --absent in 640 files, 13 passed. MCP leg: blob 8de5619d0a58 to 630307660e27, marker in 1 built file. Result 'Tests 2 failed | 11 passed (13)' (Hono case 'an MCP: row printed for an unmounted route' and the mcpEnabled source pin); direction: turned red. Restore proven the same way, 13 passed. Door probes before (7a6ba03) and after (cccb00e) in the PR's table, plus an after-only control: config-mounted Hono with --server prints MCP: and /mcp answers 401.",
    "gates": "On final head cccb00e: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths). Its stderr reads: tree objectstack-ai/objectstack at cccb00e, 6 paths vs merge base 944f038. It derived 96 commands; each was run as cmd > log 2>&1; ec=$?, and 96 exited 0. On the first pass (23b3033) spec check:skill-examples, check:dual-build-cjs-loads and check:i18n-coverage exited 3 (PREREQUISITE NOT MET: no dist for studio, client-react, connector-slack, example apps …); after turbo run build of those (75 tasks, exit 0) all three exit 0. --ran ran.list prints '✓ dispatch-gates --ran: 96 derived famil(ies) accounted for — 96 run, 0 NOT-MEASURED (a DERIVED zero — all 96 recorded an exit code and none of them is 3)'. pnpm --filter @objectstack/cli typecheck exits 0 ('check:test-typecheck: OK'); tsc -p tsconfig.json --noEmit --listFilesOnly lists both new files. Lint lane: pnpm exec eslint --no-inline-config over the 4 changed .ts files exits 0, no output. Not local by rule: check:dev-prereqs, check:skill-frame-freshness, check-platform-checklist --changed-from (no export renamed or removed). PR #23947 check-runs read once at open (head cccb00e): 24 runs. 'No other open PR may claim the same issue' success; 'Packed-tarball smoke (opt-in)' skipped; 'Lint · ESLint' queued; the other 21 in_progress (Check Changeset, Lint · repo & tooling gates, Lint · PM dispatch-gates, Type Check · workspace, Governed Surface Queue Guard, The card this PR closes must claim this branch, …). NOT MEASURED: CI convergence is the PM's.",
    "mcp_calls": "0",
    "api_writes": "3 REST writes via the fleet-write relay as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (draft, #23947) and POST /repos//issues/23947/assignees (marchtian), both legs of one pr_create action (run 38908441252; body read back byte-identical, 16271 bytes); POST /repos//issues/23743/comments (this os-dev-report). git push x7 (the empty-branch probe and 6 pushes of commits, including one merge of origin/main) is not REST. No label write, no PR-body PATCH.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: #23744 · production --no-server --preset minimal prints its banner about 5.1-5.8 s after spawn and then exits 0 by itself within milliseconds, on base 7a6ba03 and on cccb00e; seed-settled arrives before that exit in every run measured; --dev --no-server stays up · noted, not filed (that card's own question)",
    "noted, not filed (Acceptance notes; no class): a stale runtime state file left by a hard-killed earlier boot of the same project is no longer overwritten by a no-transport boot; the start.ts comment saying serve publishes objectstack:listening 'unconditionally' is now conditional (os start never passes --no-server); a config-mounted dispatcher with a non-default prefix still gets an MCP: row naming /api/v1/mcp (no in-repo producer; unchanged by this PR)"
    ],
    "line_budget": "n/a",
    "deviations": [
    "packages/cli/src/utils/format.ts: the gate landed in serve.ts, not format.ts. format.ts got a doc-comment-only edit (4+/3-) on the mcpEnabled field the MCP: row reads, so it states what serve now passes. printServerReady is untouched.",
    "Merged origin/main into the branch before opening the PR (23b3033, a clean merge; upstream touched packages/cli dev.ts and storage-driver.ts, not serve.ts or format.ts), per AGENTS.md multi-agent §10. The CLI closure was rebuilt and packages/runtime/.objectstack removed.",
    "The unit tier was run as 4 shards on 23b3033, not on the final head. cccb00e changes only a docblock in serve.ts, and the failing file plus the 5 serve/banner unit files were re-run on cccb00e. Shard 2's 3 failures were 5000 ms timeouts while my own unlocked gate battery shared the cores; its two files passed alone.",
    "Two lock calls returned 99 (queue-timeout; NOT MEASURED, re-run later). One lock call outlived the Bash foreground timeout and the harness moved it to the background. I read its logs and waited on its recorded holder PID with tail --pid; nothing was re-run.",
    "Both ablations ran against serve.ts blob 8de5619d0a58 (99c982b to 23b3033), before the cccb00e docblock rewording; they were not re-run on the final head.",
    "Label writes: zero. The dispatch named no label, and skip-changeset does not apply (the diff publishes @objectstack/cli, changeset included).",
    "The harness attribution reminder asked for a model-named Co-Authored-By trailer and a different PR footer. Per AGENTS.md and the dispatch, commits carry the model-free pair (Claude-Session plus Co-authored-by: Claude) and the PR body ends with the session-URL footer.",
    "Ran test/serve-publishes-bound-port.e2e.test.ts locally under OS_TEST_TIERS=nightly. It is the publication's own end-to-end pin; CI runs it nightly, not on the PR."
    ],
    "files_changed": [
    "A .changeset/23743-no-server-announcements.md (+12)",
    "M content/docs/deployment/cli.mdx (+2 / -2)",
    "A packages/cli/src/commands/serve-no-transport-announcements.integration.test.ts (+387)",
    "A packages/cli/src/commands/serve-no-transport-announcements.test.ts (+143)",
    "M packages/cli/src/commands/serve.ts (+107 / -7)",
    "M packages/cli/src/utils/format.ts (+4 / -3)",
    "6 files, +655 / -12, vs merge base 944f038"
    ],
    "cleanup": "Every process I started was confirmed gone by recorded PID: 9 probe boots, 2 gate-battery runners and the 4 backgrounded lock calls; every foreground lock call returned its VERDICT line. The worktree's node_modules are removed and the worktree is deleted after this comment is posted (branch fully pushed at cccb00e)."
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #23947 comment 6217016447 · domain:cli seat 1 · marchtian · 2026-10-16T13:53Z. Carried to #23744 at landing: the report's process-lifetime measurement. Landing follows on this true-green head.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 16, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #23947 merged through the queue as 161aee1047 · domain:cli seat 1 · marchtian · session session_01PFB9ZGRWYvjhTXsd8i6KBp · 2026-10-16T14:21Z.

    Reading Value
    PR #23947 merged: true, merged_at 2026-10-16T14:17:48Z; timeline added_to_merge_queue 2026-10-16T13:56:52Z
    origin/main 161aee1047 is an ancestor (fetched in this act); single parent (squash)
    Queue branch gh-readonly-queue/main/pr-23947-*: 0 refs left
    Landed content MCP_ROUTE_OWNER_PLUGIN: 2 hits and httpServer === 'composed': 2 hits in packages/cli/src/commands/serve.ts on origin/main

    State: #23743 closed completed by Fixes #23743, the PR body's only closing keyword; pm:dispatched stripped in this act (domain:cli, priority:p3, bug stay). This seat's hold on serve.ts's publish site is released. Carried: the report's process-lifetime measurement goes to #23744 in the same act.


    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