Skip to content

fix(plugin-hono-server): a request for port 0 no longer warns that port 0 is in use - #24402

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24387-port-zero-warning
Oct 18, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-24387-port-zero-warning

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #24387

Clause-②: no (basis: a log line stops firing for a legal request; nothing accepted or exported moves, and no export, option or type changes)

What changed

HonoServerPlugin's kernel:listening hook compared the requested port with the bound port and warned Port 0 is in use, using port N instead whenever the two differed. Port 0 is a legal request for a kernel-assigned port: listen(0) can never bind the number it was given, so nothing was in use. The hook now warns only for a non-zero request that the adapter's EADDRINUSE walk moved (port !== 0 && actualPort !== port). A kernel-assigned boot prints only the existing HTTP server started successfully info line, which already names the bound port. No line is added.

  • packages/plugins/plugin-hono-server/src/hono-plugin.ts: the guard, with a comment saying why.
  • packages/plugins/plugin-hono-server/src/kernel-listening-port-notice.test.ts (new): the card's pins.
  • packages/cli/test/released-port-production-spawn.pin.test.ts: the ledger reason for serve-port-drift-notice.e2e.test.ts quoted this warning as the reason its negative arm cannot use --port 0, and this change makes that clause false. The reason now states only the arm's subject: a boot that binds exactly the non-zero port it asked for, which --port 0 cannot ask. The entry and its draws: 1 are unchanged.
  • .changeset/24387-port-zero-busy-warning.md: patch on @objectstack/plugin-hono-server.

Text that quotes or relies on the warning (git grep for in use, using port and for is in use over the tree): the pin ledger reason above, and nothing else. The helper docblock in packages/cli/test/helpers/serve-process.ts names the same subject ("a boot that must bind exactly the port it asked for, which --port 0 cannot ask") without the warning, and stays true. The boot-noise budget test (serve-boot-diagnostics-noise-budget.e2e.test.ts) pins no informational count, so it needs no change. No doc page quotes the line. The CLI's own drift notice (Port N is in use — serving on M instead.) is a different line in packages/cli/src and is not touched.

The pins, and why they sit at the plugin

Three cases run the plugin's real init()/start(), the REAL adapter (a real socket is bound) and the REAL core logger (createLogger, json format) at the levels the CLI runs it at. They read the records the hook writes by kind and count, not by wording:

  1. a request for 0 at the CLI's default kernel level (warn): no record at all;
  2. a request for 0 at info: exactly one record, at info, whose port is the bound port;
  3. a non-zero request whose port a TCP listener holds, at warn: the adapter really moved (bound differs from held), and exactly one warn record names both the requested and the bound port.

Why here and not in the CLI's boot-diagnostics tests: this hook is the line's only producer, and the CLI banner only replays what the kernel logger wrote. The CLI test that reads the Boot diagnostics block is a nightly e2e cold start of a scaffolded project, and it deliberately pins no informational count. The plugin test drives the producer through a real socket in milliseconds of test time and runs in every PR's Test Core. No file changed tier: the new file is a plain plugin unit test, and the CLI pin file's edit is one string literal (it ran under --project unit).

Measurement, fix, ablation

  • Premise, measured by the pin on unchanged source (commit c18c1ff is the pin alone): cases 1 and 2 red, case 3 green. The red records read "level": "warn", "msg": "Port 0 is in use, using port 36051 instead" at warn, and the same line beside the started line at info.
  • With the fix (b2509f8): 3 of 3 pass.
  • Ablation (fix committed first; scripts/ablation-replace.mjs in wrap mode, plus a trap restore on EXIT INT TERM against the absolute path): anchor if (port !== 0 && actualPort !== port) { hit 1 time, 1 -> 0; replacement if (actualPort !== port) { 0 -> 1; blob 70d649417902 -> c5a5b2f078ce. Independent on-disk count during the mutation: guard 0, reverted 1. Pin result: cases 1 and 2 red (Port 0 is in use, using port 44497 instead), case 3 green. Restore: blob after restore 70d649417902 == HEAD blob 70d649417902, git diff HEAD empty, git status --porcelain empty. The pin imports ./hono-plugin by relative path from src/, so no dist/ is on its path and the dist preflight does not apply.
  • Public door after the fix (one-shot reading, not a test; tsx os serve objectstack.config.ts --port 0 against export default {};, plugin dist/ rebuilt from b2509f8): default level, banner reached, 0 busy-port lines, no Boot diagnostics block, API: http://localhost:42961/; --log-level info, banner reached, 0 busy-port lines, one HTTP server started successfully {"port":38147,...} line matching API: http://localhost:38147/. Both servers stopped by recorded PID.

Local verification (all at b2509f8)

  • pnpm --filter '@objectstack/plugin-hono-server^...' build: exit 0.
  • pnpm --filter @objectstack/plugin-hono-server test: 32 files, 393 tests passed.
  • pnpm --filter @objectstack/plugin-hono-server typecheck: exit 0 (tsc --listFiles -p tsconfig.test.json lists the new test file).
  • pnpm --filter @objectstack/cli exec vitest run --project unit test/released-port-production-spawn.pin.test.ts test/vitest-tiers-partition.test.ts: 2 files, 26 tests passed.
  • pnpm --filter @objectstack/cli typecheck: exit 0.
  • eslint --no-inline-config over the three changed TypeScript files: exit 0, no output.
  • node scripts/pm/dispatch-gates.mjs --commands: 66 derived commands, each run with its exit code captured before any pipe, plus the 11 declared-wide families: all exit 0. check:dual-build-cjs-loads and check:lean-entry-closure first exited 3 (PREREQUISITE NOT MET, no workspace dist/); after check:type-check-debt's own full build they were re-run and exited 0. --ran: 66 derived, 66 run, 0 NOT-MEASURED, 0 UNRUN. The four roster gates whose rosters sit beside these paths (check-changeset-fixed, check:authz-resolver, check:error-code-casing, check:filter-alias-parity): exit 0.
  • Declared narrowing: the CLI's full unit and integration tiers and test:repo are left to CI's Test Core. The CLI diff is one string literal in a unit-tier pin, and packages/cli/src is untouched.

Acceptance notes

  • hono-plugin.test.ts's should start without errors case comments "Plugin should register kernel:ready hook to start listening", but the socket opens on kernel:listening. A stale comment, noted and not filed.
  • HonoServerPlugin.destroy() calls the adapter's async close() without awaiting it. Noted, not filed: nothing measured here depends on it.

Generated by Claude Code

… a real busy port

A request for port 0 that binds port N must print no busy-port line at the
CLI's default level or at info; a held non-zero port must still warn, naming
the requested and the bound port. Red on this commit: the fix follows.

Claude-Session: https://claude.ai/code/session_01SYEJqDL3NXxrJRBVqaMu9T
Co-authored-by: Claude <noreply@anthropic.com>
…rt 0 is in use

kernel:listening compared the requested port with the bound one and warned
whenever they differed. Port 0 asks for a kernel-assigned port, so the two
can never match and nothing was in use. The warning now fires only for a
non-zero request the adapter's EADDRINUSE walk moved; the started line
already names the bound port.

The released-port ledger's reason for serve-port-drift-notice.e2e.test.ts
quoted that warning as why its negative arm cannot use --port 0. It now
states only the arm's subject: a non-zero request, which --port 0 cannot ask.

Claude-Session: https://claude.ai/code/session_01SYEJqDL3NXxrJRBVqaMu9T
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Oct 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 9 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json d79dc4883c5698cf05680a545758bdbba0d8a7a2 → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT (lane review) · domain:cli seat 1 (seat post #6024) · zhuangjianguo · session session_01SYEJqDL3NXxrJRBVqaMu9T · 2026-10-18T22:05Z · on head b2509f8b0 · #24387 (p3, claim 6255274656, report 6255708185). This is the seat's own review at the default tier, read against GitHub, not the report.

  1. Shape:
    • Draft against main, Fixes #24387, a line-initial Clause-②: no with its basis.
    • 4 files, +185 / −3. One patch changeset on @objectstack/plugin-hono-server. Not governed, under 3,000.
    • Inside the claimed surface: no packages/cli/src/**, port-contract.ts or packages/spec/src/** file, and one ledger entry.
  2. The fix, read on the diff: kernel:listening warns only when port !== 0 && actualPort !== port. A request for 0 keeps the existing HTTP server started successfully info line, which names the bound port, and no line is added. A non-zero request that the adapter's EADDRINUSE walk moved still warns.
  3. Pins (kernel-listening-port-notice.test.ts, new, plugin unit tier):
    • They run the real init() / start(), the real adapter on a real socket, and the real core logger at the CLI's default warn and at info. They read records by kind and count.
    • 0 at warn: nothing. 0 at info: exactly one record, naming the bound port. A TCP-held non-zero port: one warn record naming both ports.
    • The premise was measured red on unchanged source: 2 failed | 1 passed.
    • Ablation: the guard reverted gives exactly the two 0 arms red, with the held-port arm green. The restore was proven: blob == HEAD, git diff HEAD empty.
  4. The pin ledger: serve-port-drift-notice's reason no longer quotes the warning. It names only the arm's subject, a non-zero request. The entry and draws: 1 are unchanged, and the pin passes.
  5. Tests and gates:
    • plugin suite: 32 files, 393 tests. Typecheck exits 0.
    • The CLI pin and the tier partition: 26/26.
    • eslint exits 0.
    • dispatch-gates: 66 derived, 66 run, 0 NOT-MEASURED. The 11 wide families exit 0.
    • The public door after the fix: os serve --port 0 prints no busy-port line at either level.
    • CI on this head was running at this stamp.
  6. Acceptance notes (not filed): a stale hook-name comment in hono-plugin.test.ts, and destroy() not awaiting the adapter's close(). Both are minor and neither has a measured reach.
  7. Landing: ready plus auto-merge through the queue once every check on this head is green or an expected skip. The card closes on the merge.

Generated by Claude Code

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

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants