Skip to content

fix(cross-runtime): make YAML, workspace imports and std/testing resolve off Deno - #3526

Merged
kojiwakayama merged 7 commits into
mainfrom
fix/cross-runtime-node-suite
Aug 10, 2026
Merged

fix(cross-runtime): make YAML, workspace imports and std/testing resolve off Deno#3526
kojiwakayama merged 7 commits into
mainfrom
fix/cross-runtime-node-suite

Conversation

@kojiwakayama

@kojiwakayama kojiwakayama commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

deno task test:node fails on 284 test files on main. This fixes three of the four causes, taking it to 101 on the same machine and command.

Cause Before After
Cannot find package '@std/yaml' 94 0
ERR_PACKAGE_IMPORT_NOT_DEFINED 32 0
ERR_PACKAGE_PATH_NOT_EXPORTED 20 0
@veryfront/react-*-upstream 72 see below

Deno is unaffected: 3,781 passed, 0 failed.

YAML — third-party parser in an extension, contract in core

jsr:@std/yaml resolves under Deno alone. The obvious fix — npm:yaml in the root import map — works and is wrong: scripts/lint/audit-core-deps.ts:25 exempts jsr:@std/* and nothing else, so core may depend on Deno stdlib but never on a third party. Three lints enforce that, each with its own test.

So the sanctioned split is used instead:

  • npm:yaml@2.9.0 lives only in extensions/ext-yaml, where npm deps already live (jose, esbuild, es-module-lexer)
  • a YamlParserProvider contract sits in core
  • src/platform/compat/std/yaml.ts resolves the contract and delegates, exactly as platform/compat/opaque-deps.ts already does for DocumentExtractor

All five call sites move onto it — including extensions/ext-yaml/src/adapter.ts, whose {allowDuplicateKeys: false, schema: "json"} semantics are preserved.

Deliberate behaviour differences, each pinned by a test and documented in the extension README: the YAML 1.2 core schema drops 1.1 timestamps, << merge keys, and 1_000 underscore separators. The Skill-document path is unchanged, because schema: "json" already suppressed those.

Workspace member imports

Deno applies a member's own imports to modules inside that member's directory; the Node resolver read only the root map, so react/'s aliases escaped to a real package lookup. Scopes are now derived from the member configs the loader already parses, deepest match wins — no hand-maintained table.

#std/testing/time and unexported subpaths

The specifier had no local shim, so Node reported the # import undefined. Adds a cross-runtime FakeTime plus the missing export paths.

A ratchet so the class cannot return

lint:cross-runtime-jsr fails on a jsr: mapping neither alternate harness can substitute a local file for, and on new dependents of the ones already baselined (5 today). Wired into lint:ci.

Gates

fmt --check, lint, lint:core-deps, lint:dependency-boundaries, lint:ci, typecheck — all exit 0, re-run after a rebase onto current main. Core still carries no third-party runtime dependency.

Why test:node still cannot pass from a clean checkout

Not because of anything unfixed here. @veryfront/react-*-upstream are dnt build artifacts produced by scripts/build/npm-react-shims.ts; they exist only after deno task build:npm and are absent from any source checkout. tests/ensure-npm-links.mjs:50 returns silently when npm/node_modules is missing — "Best effort; tests can still rely on existing node_modules resolution." — so the dependency is undeclared and fails open.

That accounts for the remaining ~79 files and must be settled before either runtime is worth gating in CI: today a Node job would be green or red depending on whether a build artifact happened to be lying around.

Two further caveats, stated rather than buried:

  • My 101 figure comes from a run where the 50-minute cap hit and 3 of 4 shards reported. It is a real improvement on a like-for-like comparison, not a certified whole-suite number.
  • deno task test:node does not self-terminate — measured on pristine main too, so pre-existing and not introduced here.

Closes part of veryfront-issue-inbox#433.

Summary by CodeRabbit

  • New Features

    • Added a standalone YAML parser with configurable schemas, duplicate-key handling, and provider registration.
    • Added cross-runtime fake timers and date controls for deterministic testing.
    • Improved workspace-aware module resolution across supported runtimes.
  • Documentation

    • Expanded YAML parser API documentation, usage examples, supported behavior, and licensing notices.
  • Bug Fixes

    • Improved YAML error handling, security protections, and single-document validation.
  • Tests

    • Expanded coverage for YAML parsing, fake timers, runtime resolution, and configuration parity.

…lve off Deno

`deno task test:node` failed on 284 test files. Three of the four causes are
fixed here, taking it to 101 on the same machine and command.

**YAML (94 files).** `jsr:@std/yaml` resolves under Deno alone. Putting
`npm:yaml` in the root import map fixes resolution and breaks a product
invariant: `audit-core-deps.ts:25` exempts `jsr:@std/*` and nothing else, so
core may depend on Deno stdlib but never on a third party. The sanctioned
split is used instead -- `npm:yaml` lives in `extensions/ext-yaml`, a
`YamlParserProvider` contract sits in core, and the compat shim resolves the
contract and delegates, as `platform/compat/opaque-deps.ts` already does for
`DocumentExtractor`. All five call sites move onto it. The 1.2 core schema
drops YAML 1.1 timestamps, `<<` merge keys and `1_000` underscore separators;
each difference is pinned by a test and documented in the extension README.

**Workspace member imports (72 files, partial).** Deno applies a member's own
`imports` to modules inside that member's directory; the Node resolver only
read the root map, so `react/`'s aliases escaped to a real package lookup. The
resolver now derives scopes from the member configs it already parses, deepest
match wins. This does not close the class on its own -- see below.

**`#std/testing/time` and unexported subpaths (52 files).** The specifier had
no local shim, so Node reported the `#` import undefined. Adds a cross-runtime
`FakeTime` and the missing export paths.

**A ratchet so the class cannot return.** `lint:cross-runtime-jsr` fails on a
`jsr:` mapping that neither alternate harness can substitute a local file for,
and on new dependents of the ones already baselined. Wired into `lint:ci`.

Deno is unaffected: 3781 passed, 0 failed. `lint:core-deps`,
`lint:dependency-boundaries`, `lint:ci`, `typecheck` and `fmt --check` all exit
0 -- core still carries no third-party runtime dependency.

Not fixed here, and the reason `test:node` still cannot pass from a clean
checkout: the `@veryfront/react-*-upstream` packages are dnt build artifacts
(`scripts/build/npm-react-shims.ts`), so they exist only after `deno task
build:npm`. `tests/ensure-npm-links.mjs:50` returns silently when
`npm/node_modules` is absent, so the dependency is undeclared and fails open.
That has to be settled before either runtime is worth gating in CI.
@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kojiwakayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 48 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3beacd80-c0ba-4b1d-9ad3-be02c147a0a2

📥 Commits

Reviewing files that changed from the base of the PR and between 4937359 and 31e6360.

📒 Files selected for processing (4)
  • scripts/lint/audit-cross-runtime-jsr.test.ts
  • scripts/lint/audit-cross-runtime-jsr.ts
  • scripts/lint/tsconfig-paths.ts
  • src/config/tsconfig-paths-parity.test.ts
📝 Walkthrough

Walkthrough

This PR adds provider-based YAML parsing, cross-runtime JSR auditing, FakeTime, workspace-aware Node resolution, and local React SSR test setup. It also updates import maps, package metadata, tests, documentation, and verification tasks.

Changes

YAML parser portability

Layer / File(s) Summary
Provider contract and compatibility path
src/extensions/parser/*, src/platform/compat/std/yaml.*, deno.json, tsconfig.json
Adds validated synchronous YAML providers, default-provider loading, provider selection, compatibility aliases, and tests.
YAML 1.2 extension implementation
extensions/ext-yaml/src/*, extensions/ext-yaml/deno.json, scripts/build/npm-package-metadata.ts
Uses yaml 2.9.0, adds general YAML parsing, validates tags, and registers both providers.
Validation and documentation
extensions/ext-yaml/README.md, docs/api-reference/veryfront/extensions.md, extensions/ext-yaml/src/adapter.test.ts, extensions/ext-yaml/src/index.test.ts
Adds parser, provider, schema, and prototype-handling coverage. Updates API and extension documentation.
Import migration
src/build/compiler/*, src/platform/compat/shims/*, tests/bun/preload.ts
Routes YAML imports through the compatibility implementation.

Cross-runtime JSR audit

Layer / File(s) Summary
Audit engine and baseline checks
scripts/lint/audit-cross-runtime-jsr.ts
Models Node and Bun resolution, scans runtime imports, detects direct JSR imports, compares baselines, and reports failures.
Audit tests and verification wiring
scripts/lint/audit-cross-runtime-jsr.test.ts, deno.json, src/config/tsconfig-paths-parity.test.ts, tsconfig.json
Tests audit behavior, runs the audit in verification tasks, and checks path parity.

Cross-runtime fake time

Layer / File(s) Summary
FakeTime implementation and tests
src/platform/compat/std/testing/time.ts, src/platform/compat/std/testing/time.test.ts
Adds timer, interval, Date, microtask, disposal, singleton, and clock-advancement behavior with tests.

Workspace-aware Node resolution

Layer / File(s) Summary
Workspace import-map resolution
tests/node/resolver-hooks.mjs
Adds workspace scopes, deepest-scope selection, remote target parsing, relative resolution, and npm subpath forwarding.
Resolver validation
tests/node-resolver-workspace-imports.test.ts
Tests workspace registration, scope boundaries, remote targets, and subpath preservation.

Local React SSR test setup

Layer / File(s) Summary
SSR adapter test wiring
src/react/compat/ssr-adapter/_test-setup.ts, src/rendering/rsc/server-renderer/*test.ts
Adds automatic local React SSR module setup for RSC renderer tests.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: kwakayama

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 41.82% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main cross-runtime changes to YAML, workspace imports, and std/testing resolution.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cross-runtime-node-suite

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🧹 Nitpick comments (3)
scripts/lint/audit-cross-runtime-jsr.test.ts (1)

97-112: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a case for two wildcard keys that share a prefix.

The current cases use keys with empty suffixes, so the second loop in resolveTsconfigPath always picks a compatible key. A case such as { "#a/*.ts": "./typed/*.ts", "#a/*": "./plain/*" } resolved for "#a/x.ts" exposes the key-selection defect flagged in scripts/lint/audit-cross-runtime-jsr.ts at Line 320.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/lint/audit-cross-runtime-jsr.test.ts` around lines 97 - 112, Add a
test in the resolveTsconfigPath suite covering overlapping wildcard keys with a
shared prefix, such as "`#a/`*.ts" and "`#a/`*", and resolve "`#a/x.ts`" to verify the
more specific compatible pattern and corresponding substitution are selected.
Keep the existing exact-match, longest-prefix, and unmapped-specifier cases
unchanged.
src/platform/compat/std/testing/time.test.ts (1)

152-156: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a case for a non-finite tick duration.

The suite covers a negative duration. It does not cover tick(NaN), which currently passes the backwards check and fires every pending timer. Add the case with the guard proposed on src/platform/compat/std/testing/time.ts lines 101-105.

As per coding guidelines: "For behavior changes, add or update a focused failing test before changing implementation."

💚 Proposed test
   it("refuses to move the clock backwards", () => {
     using time = new FakeTime(1000);
 
     assertThrows(() => time.tick(-1), RangeError);
   });
+
+  it("refuses a non-finite tick duration", () => {
+    using time = new FakeTime(1000);
+    let fired = false;
+
+    setTimeout(() => {
+      fired = true;
+    }, 10);
+
+    assertThrows(() => time.tick(Number.NaN), RangeError);
+    assertEquals(fired, false);
+    assertEquals(time.now, 1000);
+  });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/compat/std/testing/time.test.ts` around lines 152 - 156, Add a
focused test alongside the existing “refuses to move the clock backwards” case
in the FakeTime suite that asserts time.tick(NaN) throws RangeError, covering
non-finite tick durations before updating the corresponding guard in
FakeTime.tick.

Source: Coding guidelines

src/platform/compat/std/testing/time.ts (1)

216-228: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Consider an apply trap so Date() reads the fake clock.

The proxy traps construct and get. It does not trap apply. A call to Date() without new therefore returns a string built from the real clock. Add an apply trap if you want full parity with the faked clock.

♻️ Proposed trap
     return new Proxy(this.#originals.Date, {
+      apply: (target) => new target(readNow()).toString(),
       construct(target, args, newTarget) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/platform/compat/std/testing/time.ts` around lines 216 - 228, Update
`#createDate`() to add an apply trap for direct Date() calls, returning a date
string based on readNow() rather than the real clock. Preserve the existing
construct behavior for new Date() and get behavior for Date.now.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@extensions/ext-yaml/src/adapter.ts`:
- Around line 80-110: Update parseAllDocuments in the adapter’s YAML parsing
flow to pass schema: jsonSchema ? "json" : "core". Adjust the document
diagnostic handling so only UNRESOLVED_SCALAR diagnostics are ignored under the
JSON schema, while all other errors remain failures; preserve ordinary unquoted
metadata such as name: research and decode value: 0o7 as the string "0o7". Add
coverage for both cases.

In `@scripts/lint/audit-cross-runtime-jsr.test.ts`:
- Around line 1-2: Update the imports in the audit cross-runtime test to use
assertEquals from `#veryfront/testing/assert.ts` and describe/it from
`#veryfront/testing/bdd.ts`, matching the established testing convention used by
the related parity test.

In `@scripts/lint/audit-cross-runtime-jsr.ts`:
- Around line 299-331: Update scripts/lint/audit-cross-runtime-jsr.ts lines
299-331 so resolveTsconfigPath retains the matched prefix, suffix, and target
together during one pass, eliminating the second loop and ensuring the selected
wildcard key is used. Add a shared wildcard-suffix test case in
scripts/lint/audit-cross-runtime-jsr.test.ts lines 97-112 using keys such as
"`#a/`*.ts" and "`#a/`*". In src/config/tsconfig-paths-parity.test.ts lines 32-55,
import and use the shared resolveTsconfigPath helper instead of maintaining a
duplicate resolveThroughPaths implementation.
- Around line 464-486: Update collectCrossRuntimeFiles so the for-await
iteration over Deno.readDir(root) is inside the try/catch; ignore only
Deno.errors.NotFound and rethrow all other errors, while preserving the existing
directory traversal and file collection behavior.

In `@src/config/tsconfig-paths-parity.test.ts`:
- Around line 18-29: Update readRepoJson in the parity test to use a
runtime-neutral filesystem API that does not reference the Deno global, so Node
and Bun execute the test and preserve the existing expected coverage. Keep the
repository-root URL and JSON parsing behavior unchanged.

In `@src/extensions/parser/yaml-defaults.ts`:
- Around line 13-16: Update the first-party import in yaml-defaults.ts to use
the `#veryfront/extensions/first-party-import.ts` internal alias, while keeping
sibling imports such as ./yaml-parser.ts relative.

In `@src/platform/compat/std/testing/time.ts`:
- Around line 101-105: Update the tick method to validate that ms is finite
before computing target, rejecting NaN and positive or negative infinity with an
appropriate RangeError. Preserve the existing backwards-time check and timer
behavior for finite values.

In `@tests/node-resolver-workspace-imports.test.ts`:
- Around line 14-21: Move this test file beside resolver-hooks.mjs under the
tests/node directory, naming it resolver-hooks.test.ts, and update its relative
import from "./node/resolver-hooks.mjs" to reference the colocated module.

In `@tests/node/resolver-hooks.mjs`:
- Around line 256-265: Update resolveAliasSpecifier to resolve scope.imports
before the root import map whenever a workspace scope exists, using the root map
only when the member map has no match; retain fallbackAliasMap handling
afterward. Add a focused resolve() test in
tests/node-resolver-workspace-imports.test.ts covering a member parent URL and
colliding React specifier, before implementing the resolver change.

In `@tsconfig.json`:
- Around line 20-21: Update the `#std/testing/time` and `#std/testing/time.ts`
entries in deno.json to point to ./src/platform/compat/std/testing/time.ts,
matching the TypeScript paths and ensuring runtime resolution uses FakeTime
instead of the JSR target.

---

Nitpick comments:
In `@scripts/lint/audit-cross-runtime-jsr.test.ts`:
- Around line 97-112: Add a test in the resolveTsconfigPath suite covering
overlapping wildcard keys with a shared prefix, such as "`#a/`*.ts" and "`#a/`*",
and resolve "`#a/x.ts`" to verify the more specific compatible pattern and
corresponding substitution are selected. Keep the existing exact-match,
longest-prefix, and unmapped-specifier cases unchanged.

In `@src/platform/compat/std/testing/time.test.ts`:
- Around line 152-156: Add a focused test alongside the existing “refuses to
move the clock backwards” case in the FakeTime suite that asserts time.tick(NaN)
throws RangeError, covering non-finite tick durations before updating the
corresponding guard in FakeTime.tick.

In `@src/platform/compat/std/testing/time.ts`:
- Around line 216-228: Update `#createDate`() to add an apply trap for direct
Date() calls, returning a date string based on readNow() rather than the real
clock. Preserve the existing construct behavior for new Date() and get behavior
for Date.now.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e06c0372-a159-4178-bc54-e29eeae230bd

📥 Commits

Reviewing files that changed from the base of the PR and between ed7e4b4 and a51e4b0.

⛔ Files ignored due to path filters (1)
  • deno.lock is excluded by !**/*.lock
📒 Files selected for processing (33)
  • deno.json
  • docs/api-reference/veryfront/extensions.md
  • extensions/ext-yaml/README.md
  • extensions/ext-yaml/THIRD_PARTY_NOTICES.md
  • extensions/ext-yaml/deno.json
  • extensions/ext-yaml/src/adapter.test.ts
  • extensions/ext-yaml/src/adapter.ts
  • extensions/ext-yaml/src/index.test.ts
  • extensions/ext-yaml/src/index.ts
  • scripts/build/npm-package-metadata.ts
  • scripts/lint/audit-cross-runtime-jsr.test.ts
  • scripts/lint/audit-cross-runtime-jsr.ts
  • src/build/compiler/mdx-compiler/frontmatter-parser.ts
  • src/build/compiler/mdx-to-js.ts
  • src/config/tsconfig-paths-parity.test.ts
  • src/extensions/parser/index.ts
  • src/extensions/parser/yaml-defaults.ts
  • src/extensions/parser/yaml-parser.test.ts
  • src/extensions/parser/yaml-parser.ts
  • src/extensions/recommendations.ts
  • src/platform/compat/shims/std-front-matter.ts
  • src/platform/compat/std/front-matter-yaml.ts
  • src/platform/compat/std/testing/time.test.ts
  • src/platform/compat/std/testing/time.ts
  • src/platform/compat/std/yaml.test.ts
  • src/platform/compat/std/yaml.ts
  • src/react/compat/ssr-adapter/_test-setup.ts
  • src/rendering/rsc/server-renderer/rsc-renderer.test.ts
  • src/rendering/rsc/server-renderer/tree-processor.test.ts
  • tests/bun/preload.ts
  • tests/node-resolver-workspace-imports.test.ts
  • tests/node/resolver-hooks.mjs
  • tsconfig.json

Comment thread extensions/ext-yaml/src/adapter.ts
Comment thread scripts/lint/audit-cross-runtime-jsr.test.ts Outdated
Comment thread scripts/lint/audit-cross-runtime-jsr.ts Outdated
Comment thread scripts/lint/audit-cross-runtime-jsr.ts
Comment thread src/config/tsconfig-paths-parity.test.ts
Comment thread src/extensions/parser/yaml-defaults.ts Outdated
Comment thread src/platform/compat/std/testing/time.ts
Comment thread tests/node-resolver-workspace-imports.test.ts
Comment thread tests/node/resolver-hooks.mjs Outdated
Comment thread tsconfig.json

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a51e4b008e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/ext-yaml/src/adapter.ts
Comment thread tests/node/resolver-hooks.mjs Outdated
Comment thread src/config/tsconfig-paths-parity.test.ts Fixed
…ng members

Two review findings, both real, both reproduced before fixing.

`schema: "json"` was computed and never passed to the parser, so the core
schema ran and `0o7` decoded to the number 7 -- the exact widening the option
exists to prevent at a Skill-document trust boundary. It is forwarded now.

Forwarding it alone would have been worse than the bug. Under this schema the
library raises TAG_RESOLVE_FAILED for every ordinary unquoted string, so
`name: code-review` raises it twice and the existing check -- which threw on
`errors[0] ?? warnings[0]` -- would have rejected every Skill document. The
diagnostic is filtered per entry rather than by position, because a document
that raises it also raises the real ones beside it: measured, `a: 1\na: 2`
reports TAG_RESOLVE_FAILED twice before DUPLICATE_KEY, so reading the first
would have hidden the duplicate. `!!binary` still decodes to a Buffer here, so
the explicit-tag assertion stays load-bearing.

Separately, the Node resolver consulted the root import map before a workspace
member's own. Deno gives the member precedence inside that member, and the
previous order silently resolved the six React specifiers that appear in both
maps to the root's targets, so the aliases the member declared never applied.

Checked in the direction that matters: reverting the schema forwarding fails
the suite, and widening the diagnostic filter to swallow every diagnostic --
which would hide DUPLICATE_KEY -- fails it too.
`FakeTime.tick(NaN)` passed the backwards check, because `NaN < now` is false,
and then `#due` treated every pending timer as due, because `due > NaN` is
false too. The clock ended up NaN and every later assertion on it was quietly
meaningless. Rejected now, with a test that fails without the guard.

`collectCrossRuntimeFiles` guarded the `Deno.readDir` call, but readDir is
lazy: a missing root raises when iteration starts, so the catch never ran. The
loop is guarded instead, and only NotFound is swallowed -- a permissions or
I/O failure is a reason to stop, not to audit fewer files than the caller
believes were scanned.

The lint's test imports its helpers from `#veryfront/testing`, as its sibling
in this PR already did, and `yaml-defaults.ts` reaches `first-party-import`
through the `#veryfront/` alias rather than a relative path out of its module.

The new FakeTime case was written with `Deno.test` at first, which would have
put `Deno.` into a file both alternate runners exclude on sight -- removing the
coverage it was added for. It uses describe/it like the rest of the file, and
the file names no runtime API.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@extensions/ext-yaml/src/adapter.test.ts`:
- Around line 166-172: Strengthen the test in the “still reports the real error
hiding behind those diagnostics” case by capturing the thrown SyntaxError from
parseYamlSource and asserting its message or diagnostic identifies the duplicate
key. Keep the existing JSON-schema duplicate-input setup and ensure the
assertion would fail if the earlier TAG_RESOLVE_FAILED diagnostic were exposed.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6c5b7e36-4acb-4575-b69c-d535d3aeff40

📥 Commits

Reviewing files that changed from the base of the PR and between a51e4b0 and 29b1577.

📒 Files selected for processing (3)
  • extensions/ext-yaml/src/adapter.test.ts
  • extensions/ext-yaml/src/adapter.ts
  • tests/node/resolver-hooks.mjs
🚧 Files skipped from review as they are similar to previous changes (1)
  • extensions/ext-yaml/src/adapter.ts

Comment thread extensions/ext-yaml/src/adapter.test.ts
CodeQL was right, and it was the red check rather than infrastructure:
`best.target.replace("*", captured)` substitutes one occurrence, so a tsconfig
target carrying two wildcards kept a literal `*` and compared unequal. Uses
replaceAll.

The workspace containment check appended a literal `/` while both sides come
from pathResolve and fileURLToPath. On Windows those are backslash-separated,
so no file matched its member scope and every member map silently failed to
apply -- the platform separator is used instead.

And the duplicate-key test I added in the previous commit asserted only that a
SyntaxError was thrown, which the benign TAG_RESOLVE_FAILED preceding it would
also have satisfied. It asserts the message now, and reverting the diagnostic
filter to `errors[0]` fails it -- which the earlier version did not.

That is the third test in this branch to have passed for the wrong reason, and
the second one I wrote while fixing the first.
`tests-proxy-binary` verifies the lock is current by regenerating it and
failing on any diff. Routing YAML through `ext-yaml` removed `jsr:@std/yaml`
from the proxy's dependency graph, so the committed lock still named a
dependency the proxy no longer has.

Regenerated rather than hand-edited. The removal of that specifier is the whole
change and is exactly what the extension move implies.

I called this failure infrastructure twice on the strength of a `curl 404` in
the setup step. It was reproducible on this branch all three times, and the
failing step was "Verify proxy dependency lock is current" throughout.
@kojiwakayama
kojiwakayama added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit 9247aa2 Aug 10, 2026
33 checks passed
@kojiwakayama
kojiwakayama deleted the fix/cross-runtime-node-suite branch August 10, 2026 13:03
kojiwakayama added a commit that referenced this pull request Aug 10, 2026
The first cross-runtime PR landed the Deno-side resolution, but the verified follow-up tree still carries the CI gates and residue cleanup that make Node and Bun failures visible instead of silently passing with stale links or unresolved runtime assumptions.

This keeps the already-merged #3526 behavior intact, preserves current main's filesystem adapter behavior, and regenerates the API reference from the combined tree so the public docs match the resolved exports.

Constraint: PR #3526 is merged, so this branch applies only the 31e6360..6750f88bf follow-up delta onto current origin/main.

Rejected: Push more changes to fix/cross-runtime-node-suite | the source PR is merged and stale.

Rejected: Restore the redundant node-filesystem-adapter-remove test | current main already carries the a63ffc0 filesystem adapter behavior this follow-up must preserve.

Confidence: high

Scope-risk: moderate

Reversibility: clean

Directive: Keep Node and Bun CI gates fail-loud; do not weaken these checks without re-running the clean-state runtime suites.

Tested: deno task lint:ci

Tested: deno task typecheck

Tested: deno fmt --check (4980 files)

Tested: git diff --check

Tested: Deno 4246 pass / 32114 steps / 1 ignored

Tested: Node clean-state 4031 pass

Tested: Bun 6 contracts plus 1297 files

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants