Uh oh!
There was an error while loading. Please reload this page.
docs(cli): the unknown-hostname-guard's install-order rationale names Phase 1 init() (#9745) - #9821
Conversation
…le (#9745) The guard is installed correctly; the stated rationale was not. Name Phase 1 init() as the sufficient condition and drop the "order-independent for matching" clause, and pin the ordering property locally. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WeN7F6jQFpcqW2BN56RdPa
📓 Docs Drift CheckThis PR changes 1 package(s): 17 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 4 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not seeCoarse fallback — 23 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 4345b820c5f9d489bb030dfe8253e8ce4d5ea585 && git checkout 4345b820c5f9d489bb030dfe8253e8ce4d5ea585
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2a9752cf0d48cd31f238e3eb3d3681e10e46658a 218e2be7bcfbe69ca6df685c3394b08dd26382c2 && git checkout -B drift-repro 2a9752cf0d48cd31f238e3eb3d3681e10e46658a && git merge --no-ff 218e2be7bcfbe69ca6df685c3394b08dd26382c2
node scripts/docs-audit/affected-docs.mjs --json 2a9752cf0d48cd31f238e3eb3d3681e10e46658a
|
Uh oh!
There was an error while loading. Please reload this page.
Fixes#9745
The guard is installed correctly and this PR changes nothing it accepts or refuses. What was wrong is the rationale in its doc comment — the part the next author copies:
Premise re-verified on this ref, not inherited
packages/cli/src/commands/serve.tsand still says what the card quotes. The card cites:3429-3435; onorigin/mainat 5cc8a3b it sits at:3428-3435— located by text, never by line number.LiteKernel.bootstrap(packages/core/src/lite-kernel.ts) andObjectKernel.bootstrap(packages/core/src/kernel.ts) each run Phase 1init()for every plugin, then Phase 2start()for every plugin, and only then triggerkernel:ready→kernel:bootstrapped→kernel:listening. All three hooks fire strictly after Phase 2.createConsoleStaticPluginmounts the Console instart()(packages/cli/src/utils/console.ts),HonoServerPluginregisters the current-user endpoints from akernel:readyhook, andplugin-authdefers its terminal/api/v1/auth/*mount tokernel:readyas well. Phase 1init()is ahead of all of it — which is what the code already does.Verdict: the premise holds and the emphasised sentence is false. "Before
kernel:listening" admits install points that sit behind every route.What changed
1.
packages/cli/src/commands/serve.ts— comment only. Names Phase 1init()as the requirement, states the true mechanism (Hono composes the handlers a request matched in registration order, so a route registered ahead of the middleware answers and never callsnext()), and drops the "order-independent for matching" clause — the phrase that made the false generalisation sound principled. The correct first sentence is kept; the bypass matrix and the inline-object-literal note are untouched.2.
packages/cli/src/commands/serve-unknown-hostname-guard.test.ts— one new test pinning the corrected sentence. Every other test in that file mounts the guard first viamountGuard, which is precisely the case that works, so none of them can fail when the false claim comes back.The new test registers
/beforeahead of the guard'sinit()and/afterbehind it, on one realHonoHttpServer, then drives one unmapped hostname at both:/beforeanswers 200 and the env-registry is never consulted;/afteris refused with 404 andENVIRONMENT_NOT_FOUND. Registration order is the only difference between those two requests.Reverse verification
Prediction stated before running: moving
/before's registration to afterinit()turns the test red on the pass-through leg. Measured, from the committed state:Restored with
git checkout HEAD -- ..., re-run:Tests 35 passed (35). No rebuild is involved on either leg — the subject is imported from./serve.js, a same-package source specifier vitest resolves out ofsrc/, and the mutation lived inside the test file itself.Scope boundary
packages/runtime/src/http-metrics-inbound-coverage.hono.integration.test.ts— the card's evidence table — was read, never written. The pin above needed no part of that harness:packages/clialready boots a real Hono adapter in its own guard suite. NoBlocked-by:was wired, per triage.Changeset: deliberately none —
skip-changesetinsteadA judgment call, not an assumption. The
serve.tsdiff is prose inside a JSDoc block: nothing that executes changes, no public surface moves, and there is no user-visible behaviour for a release note to describe. The test file never reaches the published tarball at all —packages/cli/tsconfig.build.jsoncarries"exclude": ["src/**/*.test.ts", "src/**/*.spec.ts", "src/**/__tests__/**"], so it is not compiled andfiles: ["dist"]cannot ship it. Precedent landed onmaintoday: #9802 corrected prose inside@objectstack/lint's publishedsrc/**and merged with no changeset.Gates run, all at 218e2be
Derived with
node scripts/pm/dispatch-gates.mjs(no paths passed — the script took the change set from the merge base 5cc8a3b itself), then run:pnpm --filter '@objectstack/cli^...' buildpnpm lintpnpm --filter @objectstack/cli testTest Files 134 passed (134),Tests 1462 passed (1462)pnpm --filter @objectstack/cli typechecktsc --noEmit, cleanpnpm check:route-envelopepnpm check:cross-package-test-inputspnpm check:engine-double-contractpnpm check:where-matcherpnpm check:query-options-erasurepnpm check:nul-bytesnode scripts/docs-audit/check-affected-docs.mjscheck:type-check-coverage/check:type-check-debtwere not run locally, and the reason is the measurement rather than the cost:packages/clideclares atypecheckscript and itstsconfig.jsonincludessrc— onlytsconfig.build.jsonexcludes tests — so the new test file already sits inside a tsc program and the package carries no TEST_DEBT entry to re-measure. The ratchet half needs the whole workspace closure built; CI runs that farm.tsc --noEmitover the package is the local half.Generated by Claude Code