test(hono): resolve @objectstack/plugin-hono-server to source in the unit suite - #13339
Conversation
…unit suite `packages/adapters/hono/src/index.ts` imports createOriginMatcher, hasWildcardPattern, DEFAULT_CORS_ALLOW_HEADERS and DEFAULT_CORS_EXPOSE_HEADERS from @objectstack/plugin-hono-server as VALUES at module scope, and the suite's vitest config aliased only @objectstack/runtime — so that specifier resolved through the dependency's `exports` to its `dist/`, making this package's unit verdicts a function of another package's build state. The alias is added in ARRAY form with an anchored regex `find`; the existing @objectstack/runtime entry is carried over unchanged in reach (a bare string `find` still matches by prefix). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TvqBFLRzXdSPcbusDoED9k
…ill unaliased `check-test-source-alias` audits `KNOWN_UNALIASED_TEST_IMPORTS` for set EQUALITY, so the alias added in the previous commit makes the entry stale and the gate names the exact narrowing. Repo-wide the ledger goes 303 -> 302 (package, unaliased dep) pairs across an unchanged 61 packages; the only registry line that moves is hono's, and it only loses a member. `@objectstack/types` stays on the entry: hono's `src/index.ts` still imports four values from it through `dist/`. That is a separate remediation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TvqBFLRzXdSPcbusDoED9k
📓 Docs Drift Check
What this run could not see
Coarse fallback — 1 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
✅ PM review — ACCEPT once CI is green; ⛔ not while it is running (#12767)Undrafting now; arm follows on a complete green read. ⛔ No rework owed. Clause ②: does not attach — 2 files, nothing under ✅ The ledger fence held, verified from the diffThe binding fence was ⛔ never widen One member removed, nothing added, no other entry touched. Repo-wide 303 → 302 pairs across an unchanged 61 packages. ⭐ The positive control is the best part of this PRI asked for proof the alias actually took effect, because a passing suite never says which file it loaded. What came back does better than that — it measures the hazard live and then closes it, on one instrument:
The four failures are precisely the cases whose subject that function is ( Both legs proven on disk (anchor 1→0, marker 0→1, ⭐ The array-form conversion is not cosmetic, and the reasoning is worth keepingThe card's snippet would have been easy to paste. Instead the why was derived: the object form matches by PREFIX, so a bare key whose replacement is a file also swallows that package's subpaths into ⭐ And the trap on the other side was avoided: ⭐ The control is recorded in the ledger comment itself, next to the row it justifies, so the next reader of that registry finds the evidence rather than a bare shrink. Notes, none blocking
✅ The unfiled finding — I agree, and it stays unfiled
Generated by Claude Code |
Fixes #12767
What this changes
packages/adapters/hono/src/index.tsimportscreateOriginMatcher,hasWildcardPattern,DEFAULT_CORS_ALLOW_HEADERSandDEFAULT_CORS_EXPOSE_HEADERSfrom@objectstack/plugin-hono-serveras values, at module scope.packages/adapters/hono/vitest.config.tsaliased only@objectstack/runtime, so that specifier resolved through the dependency'sexportsto itsdist/— this package's 74 unit verdicts were a function of another package's build state.The alias, before and after
Before (object form, one entry):
After (array form; comments trimmed here, the file carries them):
The array form is forced by the gate's rule 5, not a style choice: an object-form key matches by PREFIX, so a bare key whose replacement is a FILE also swallows that package's subpaths and resolves them through a file extension — ENOTDIR at run time, in a config that reads as correct. An anchored regex
findcannot do that.The pre-existing
@objectstack/runtimeentry is carried over unchanged in reach: a bare stringfindstill matches by prefix in the array form, so the kernel mock keeps exactly the surface it had.@objectstack/runtimepublishes only.in itsexports, so there is no subpath here for that prefix to swallow.Positive control — the suite really does load source now
Re-running the gate is not verification, and a passing suite does not say which file it loaded. So the alias was measured by mutation. Same mutation, same un-rebuilt
dist/, once on each side of the change:In
packages/plugins/plugin-hono-server/src/pattern-matcher.ts, insidecreateOriginMatcher,if (!requestOrigin) return null;was replaced byif (requestOrigin) return null;— the matcher then rejects every origin. Source only;plugin-hono-serverwas not rebuilt, so itsdist/kept the correct behaviour throughout.pnpm --filter @objectstack/hono testTest Files 2 passed (2)·Tests 74 passed (74)Test Files 1 failed, 1 passed (2)·Tests 4 failed, 70 passed (74)The four failures after the alias are exactly the cases whose subject that function is:
That green row is the hazard stated as a measurement: with the specifier resolving to
dist/, the whole CORS-wildcard block passes over acreateOriginMatcherthat has been destroyed in the checkout.Both mutation legs were proven on disk, never by an exit code: anchor text count 1 to 0 and marker count 0 to 1, plus
git hash-objectdiffering fromgit rev-parse HEAD:PATH. Both restores were proven the same way —git checkout HEAD -- ABSOLUTE_PATH, marker count back to 0, disk hash equal to the HEAD blob,git diff HEADempty for that path. A first attempt at the mutation was caught by that same count check as a no-op (aperl s///whose replacement text contained the delimiter) and was re-run, so no reading was taken on an unmutated tree.Suite result
pnpm --filter @objectstack/hono testat8ea75a241, alias in place, tree clean:No breakage was surfaced by the switch to source — nothing was skipped, no
it.fails, no revert todist, no widened ledger. Cost of loading the dependency's source graph, before vs after: wall4.65sto5.09s, transform6.82sto7.72s, tests themselves unchanged (113msto111ms). The load is paid at module top by static imports, not inside a clocked window, so the timeout failure mode that rule exists for does not apply here.Ledger — it shrank, by exactly one member
KNOWN_UNALIASED_TEST_IMPORTSaudits for set EQUALITY, so the alias made the entry stale and the gate named the narrowing itself:The only registry line that moves in the diff:
Repo-wide: 303 to 302 (package, unaliased dep) pairs, across an unchanged 61 packages. Nothing was added and no entry was widened — the registry is shrink-only and this PR only removes from it. The entry's note was rewritten in the same edit rather than left describing a remediation that is now landed.
@objectstack/typesstays on the entry, correctly:src/index.tsstill importsreadEnvWithDeprecation,looksLikeInternalErrorLeak,INTERNAL_ERROR_MESSAGEandresolveThrownHttpErrorfrom it as values, throughdist/. That is a remediation of its own and is already recorded, mechanically, by the row that remains.check-type-source-resolution.mjsreadstsconfigpaths, notvitest.config.*, so its own entry for this package is untouched by this diff and its gate is green unchanged.Gates
Derived from the real change set with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(2 paths, merge base3f7f8f590), not recalled. Run at8ea75a241; each verdict below is the gate's own printed line, exit codes captured before any pipe.Green:
check:test-source-alias(OK — 72 packages with tests scanned; 61 registered as still resolving a workspace dep through dist/; 45 published subpath(s) resolved through every alias table),check:type-source-resolution(OK — 94 tsc program(s) across 77 packages scanned; 54 registered),check:agent-test-spelling,check:bash32-floor,check:cli-command-ids,check:cross-package-test-inputs,check:entry-guard,check:logger-receiver-detach,check:page-declaration-shape,check:parse-guard,check:pnpm-filter-targets,check:published-files,check:slot-lookup,check:watch-hint-literal,check-ci-filter-parity,check-comment-mask-adoption,check-cross-package-test-inputs,check-keyed-text-bounds,check-plugin-teardown-shape,check-shard-attestation,check-undeclared-dep-imports,check-affected-docs,check-drift-comment, plus both convention-triggered families this diff incurs by editing a gate script:scripts/pm/bare-root-worklist.mjs --self-testandcheck:pm-dispatch-gates.NOT MEASURED (recorded with the gate's own refusal text, never folded into the green list):
check:dual-build-cjs-loads— exit 3,PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/. … Run pnpm build first. ⛔ This is NOT a pass: nothing was measured.It needs a repo-wide build, which CI owns.scripts/check-test-completeness.mjs— exit 3,PREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was named. … running the family locally, record this gate as NOT MEASURED.Lint was narrowed to the changed files rather than run repo-wide, declared as a narrowing:
eslint --no-inline-config --format jsonon both paths reports 2 files linted, 0 errors, 0 warnings, 0 suppressed (the count read from the JSON, not from a summary line); this repo runs oneeslint.config.mjswhich never enables type-aware linting for ANY file (no parserOptions.project, no typed @typescript-eslint rules, stated and positive-controlled in that config's own header), so this diff cannot move the verdict of any file it does not touch. The repo-widepnpm lintrun belongs to CI.Changeset
None, deliberately. This diff publishes nothing from any package:
vitest.config.tsis not in@objectstack/hono'sfiles(dist,README.md,CHANGELOG.md), andscripts/check-test-source-alias.mjsbelongs to the private root package. There is no user-visible change — the published behaviour of both packages is byte-identical.skip-changesetapplied.Generated by Claude Code
Generated by Claude Code