Skip to content

fix(cursor): recover Kimi tool calls emitted as history narration - #12723

Merged
diegosouzapw merged 17 commits into
cheaper-inference:release/v3.8.51from
patrykkopycinski:fix/cursor-kimi-narration-v3851
Sep 16, 2026
Merged

diegosouzapw merged 17 commits into
cheaper-inference:release/v3.8.51from
patrykkopycinski:fix/cursor-kimi-narration-v3851

Conversation

@patrykkopycinski

Copy link
Copy Markdown
Contributor

Problem

Kimi-k3 / kimi-k3-high served through the Cursor provider sometimes emit a tool call as visible text instead of a structured call. The client then renders raw narration plus delimiter junk, and because the bad turn is re-sent in conversation history, the leak compounds on every subsequent turn.

Observed in production via OmniRoute call logs (109 artifacts in a single session), e.g.:

…Assistant called tool terminal (call_resync_1) with arguments: {"command":"…"}<|close|>argument<|sep|><|close|>call<|sep|><|close|>tools<|sep|>

with finish_reason: "stop" and no tool_calls field on the message.

Root cause

Cursor's agent API accepts one user message per Run, so flattenMessages (open-sse/utils/cursorAgentProtobuf.ts) serializes prior assistant.tool_calls into plain text for the model to read as context:

Assistant called tool <name> (<id>) with arguments: <json>

Kimi imitates that narration format when it decides to call a tool: it emits the narration as visible content, appends the complete JSON arguments, then closes with its native generation-grammar delimiters (<|close|>argument<|sep|><|close|>call<|sep|><|close|>tools<|sep|>). Cursor's protobuf backend passes the whole thing through verbatim. The existing DeepSeek inline-tool-call fallback never fires because (a) isComposerModel("kimi-k3-high") is false and (b) this is a different grammar anyway.

Fix

New open-sse/utils/kimiToolCallNarration.ts:

  • detect the Assistant called tool <name> (<id>) with arguments: narration line
  • balanced-scan the JSON arguments (honors strings/escapes/nesting); bail if truncated or invalid JSON
  • strip the native delimiter-grammar tail wherever it appears
  • reassemble a structured OpenAI tool_calls entry and return the cleaned visible content

Wired into the cursor executor's two finalization paths — finalizeSseStream (streaming) and buildResponseFromCtx (non-streaming) — gated on ctx.toolCalls.length === 0 so it never fires on a healthy turn.

Validation

  • 9 new unit tests in tests/unit/kimi-tool-call-narration.test.ts — all pass.
  • Ran the parser against the actual leaked production payload — recovers buzz-dev-mcp__shell / id toolu_01PollBanner2 with clean JSON args and prose-only content; returns null for plain prose.
  • Existing cursor / composer / translator suites still green.
  • tsc -p tsconfig.json --noEmit introduces no new errors in the touched files.

Rebased onto release/v3.8.51 (this PR supersedes a mis-based earlier attempt).

@patrykkopycinski

Copy link
Copy Markdown
Contributor Author

CI failures are upstream regressions on release/v3.8.51, not this PR

All currently-failing checks reproduce on pristine base c3945a724c with this PR's changes absent. None of the failing files are touched by this PR (which changes only open-sse/executors/cursor.ts, adds open-sse/utils/kimiToolCallNarration.ts, and tests/unit/kimi-tool-call-narration.test.ts).

Evidence (reproduced locally against c3945a724c, no PR changes):

  • API Route Typecheck — open-sse/executors/glm.ts(244,5): error TS2554: Expected 2-15 arguments, but got 16. Pristine base emits this exact error under tsc -p tsconfig.typecheck-api.json. Root cause: an upstream commit added a 16th argument (65536 stream buffer) to the createSSETransformStreamWithLogger(...) call in glm.ts, but the function signature in open-sse/utils/stream.ts only declares 15 params and does not forward a buffer size to createSSEStream. The extra arg is both a type error and silently dropped. This is upstream's to fix (add the parameter + forward it, or revert the call-site change).
  • Unit Tests (1–4) — all 7 failing test files fail identically on pristine base: chat-rejects-image-only-model, error-sanitizer-sk-key-qv45, image-generation-handler, kiro-tool-call-validation, model-sync-route, tunnel-routes-error-sanitization, zai-web-silent-empty-repro. None relate to cursor/kimi/tool-call narration.
  • Merge integrity — changelog.d/fixes/reset-aware-model-family.md: fragment must start with a markdown bullet. This fragment does not exist on release/v3.8.51, on this branch, or in any current upstream ref; it was pulled in by the merged-result ref at the time of the first run.

This PR's own validation: the 9 new kimi-tool-call-narration tests pass (9/9), and the api-typecheck gate reports OK — 0 errors on this branch's diff once upstream's glm.ts regression is excluded.

Suggest fixing the glm.ts 16-arg call on release/v3.8.51 (and the changelog fragment validator input) in a dedicated PR; this PR should not widen baselines to absorb upstream drift. Happy to rebase/re-trigger once the base is green.

@patrykkopycinski

Copy link
Copy Markdown
Contributor Author

Update (commit 62c3673b): fixed the two gates that were legitimately mine.

Refactored the two inline recovery blocks in cursor.ts into a single-line call to a new applyKimiToolCallRecovery() helper in kimiToolCallNarration.ts (structurally-typed ctx, optional emit callback — no module cycle). Locally, on the exact PR merge:

Gate Status Owner
file-size (cursor.ts) ✅ OK (was 1804 > 1759; modularized, then baseline ratcheted 1759→1764 — gate-sanctioned last resort, file hard-capped at base 1758, hook irreducible at 2 call sites) mine — fixed
complexity-ratchets (cursor.ts 11→12, 4→5) ✅ OK (2762 vs baseline 3218) mine — fixed
open-sse-typecheck ❌ open-sse/executors/glm.ts TS2554 (baseline 0, live 1) upstream — reproduces on pristine c3945a72 with this PR's changes absent
mutation-test-coverage ❌ open-sse/services/combo/quotaScoring.ts → reset-aware-request-scope-12600.test.ts missing from stryker.conf.json upstream — neither file is in this PR's diff
Merge integrity ❌ changelog.d/fixes/reset-aware-model-family.md fragment not bulleted upstream — fragment lives on the base, not in this PR's diff
Unit Tests (×4) ❌ 7 files fail on pristine base too upstream

This PR's own tests: 9/9 kimi narration, 458/459 cursor+composer (1 skip), eslint clean on all touched files. The remaining red is upstream drift on release/v3.8.51 that this PR should not absorb.

@diegosouzapw

Copy link
Copy Markdown
Collaborator

Great root-cause write-up (the actual leaked production payload as validation is
convincing) and a clean, self-contained fix. Ran the new suite against the PR head — 9/9
green, no new lint issues beyond the pre-existing base-red in cursor.ts. Only ask before
merge: add a changelog.d/fixes/ fragment.

@patrykkopycinski

Copy link
Copy Markdown
Contributor Author

Fragment added: changelog.d/fixes/12723-cursor-kimi-tool-call-narration.md (3d5f52a). It passes npm run check:changelog-integrity — the one invalid fragment that gate still reports (reset-aware-model-family.md) is the pre-existing base drift on release/v3.8.51, not from this branch.

@patrykkopycinski

Copy link
Copy Markdown
Contributor Author

Follow-up (2026-09-16): streaming scrubber closes the remaining leak paths

Live traffic on cursor/kimi-k3-high (and other kimi members via combos) surfaced three sibling defects of the narration bug this PR fixes. All three are now closed in 6fcc31a29/90faf4789; the deployed gateway has been leak-free since.

What was still leaking

  1. Recovery gated on "no structured calls". applyKimiToolCallRecovery bailed when ctx.toolCalls.length !== 0. Kimi regularly emits a structured tool call and narrates the call + delimiter tail as visible text in the same turn — that text passed through untouched (verified in a production transcript: 7 infected messages in one worker session).
  2. New dialect: tool-result mimicry. Kimi imitated the result serialization too:
    • Tool result (call_x): … (flattenMessages' role:"tool" line, cursorAgentProtobuf.ts:1486)
    • User: <tool_result><tool_name>…<tool_call_id>…<result>…</tool_result> (the openai-to-cursor translator's XML block)
  3. Live streaming made finalize-time cleanup useless. Text deltas emit immediately (emitChunk(ctx, { content: d.text })), so anything already streamed could not be retracted — the same problem the composer path solved with feedStreamingChunk holdback.

The fix

  • createNarrationStreamScrubber (kimiToolCallNarration.ts): incremental holdback state machine wired into the d.kind === "text" path. Trigger prefixes (Assistant called tool, Tool result (, User:, <tool_result>) are buffered, not emitted; once a construct completes it is dropped wholesale (narration line + JSON args + <|close|>/<|sep|> grammar tail, result line, or XML block). Narrated JSON args surface through onToolCall as a real structured tool_calls chunk mid-stream. finish() flushes benign partial-trigger suffixes as prose.
  • Ungated recovery: applyKimiToolCallRecovery now scrubs even when structured calls exist (synthesizing new calls stays gated on none existing).
  • Request-side hygiene: flattenMessages scrubs dialect constructs out of prior assistant text before re-sending history, breaking the compounding loop (poisoned history → imitation → more poison). User text is untouched.
  • Dead code flagged by eslint dropped (unused type, arg, consts — pre-existing on the base, fixed here so the PR's lint gate stays green).

Verification

  • 28 unit tests (12 new): char-by-char, chunked, and batch feeds; production leak specimen from the 2026-09-15 incident scrubbed completely; 4/4 mutation kills (gate removal, prefix-drop, enterState step-call, keyword+token split).
  • Scoped suites green: narration + cursor-agent-protobuf + cursor-agent-tool-calls + cursor-agent-session + cursor-empty-turn-failover = 120/120; tsc -p tsconfig.typecheck-core.json clean; eslint 0 on changed files.
  • Live e2e against the deployed gateway, both paths:
    • dialect echo prompt → content exactly "Checking the weather now.", no dialect in any content delta (markers appear only in reasoning_content, which is correct);
    • pure-narration prompt (no structured call) → gateway synthesized tool_calls (call_probe_9 / terminal / {"cmd":"date"}), finish_reason:"tool_calls".

Reproducing the numbers

  • Tests: npx tsx --test tests/unit/kimi-tool-call-narration.test.ts (28 pass).
  • Scoped regression: npx tsx --test tests/unit/kimi-tool-call-narration.test.ts tests/unit/cursor-agent-protobuf.test.ts tests/unit/cursor-agent-tool-calls.test.ts tests/unit/cursor-agent-session.test.ts tests/unit/cursor-empty-turn-failover-v9.test.ts (120 pass).
  • Typecheck: NODE_OPTIONS=--max-old-space-size=8192 npx tsc --pretty false -p tsconfig.typecheck-core.json (rc=0).
  • Lint: npx eslint open-sse/utils/kimiToolCallNarration.ts open-sse/executors/cursor.ts open-sse/utils/cursorAgentProtobuf.ts tests/unit/kimi-tool-call-narration.test.ts (0 issues).

CI note — failures on this head are base debt, not from this diff

Gate Failure In my diff?
API Route Typecheck open-sse/executors/glm.ts TS2554 (1 error beyond frozen baseline) No — reproduces identically on origin/release/v3.8.51 (verified locally via node scripts/check/check-api-typecheck.mjs at the base SHA). GLM executor untouched by this PR.
Unit Tests (1/4) models-catalog-route — jina model-id prefix (jina-ai/ vs jina/) No — passes locally on both this branch and base; upstream catalog drift.
Unit Tests (2/4) attempt-logging-early-keepalive-merge — row not persisted No — passes locally on both branch and base; CI-env red.
Unit Tests (4/4) dashboard-request-failed-redaction — probe fixture exits non-zero No — passes locally on both branch and base; CI-env red.
Fast Quality Gates forgotten-sibling-tests: Invalid string length (script crash) No — impact-map script OOM/crash, unrelated files.
Merge integrity agent-skills-sync + omni-settings / + cli-tunnel regeneration red No — acknowledged upstream base-red; #13826 exists to clear it.

Every red gate was reproduced locally and verified to fail identically (or pass locally where CI env fails) without this PR's changes. Happy to help land #13826 if it unblocks this merge.

@patrykkopycinski
patrykkopycinski force-pushed the fix/cursor-kimi-narration-v3851 branch from 90faf47 to 4a50fdd Compare September 16, 2026 05:30
@patrykkopycinski
patrykkopycinski force-pushed the fix/cursor-kimi-narration-v3851 branch 2 times, most recently from c5c06a6 to 5d76a7a Compare September 16, 2026 15:08
@patrykkopycinski
patrykkopycinski force-pushed the fix/cursor-kimi-narration-v3851 branch from 5d76a7a to 50f95d3 Compare September 16, 2026 15:39
Kimi-k3 / kimi-k3-high on the Cursor provider imitate the executor's own
flattenMessages history narration ('Assistant called tool <name> (<id>) with
arguments: <json>') when they decide to call a tool, then close with their
native generation delimiters (<|close|>argument<|sep|><|close|>call<|sep|><|close|>tools<|sep|>).

Cursor's protobuf backend passes the narration through verbatim as text with
finish_reason 'stop', so clients render raw narration + delimiters instead of
a tool card, and the leaked turn compounds on every subsequent request via
history re-send.

Add open-sse/utils/kimiToolCallNarration.ts: detect the narration line, scan
the balanced JSON arguments, strip the delimiter tail, and reassemble a
structured OpenAI tool_calls entry. Wire it into the cursor executor's two
finalization paths (finalizeSseStream streaming + buildResponseFromCtx
non-streaming), gated on 'no structured tool calls yet' so it never fires on
a healthy turn. Validated against the live leaked payload and 9 new unit
tests; existing cursor/composer/translator suites still green.
The 4 failing checks (Merge integrity, API Route Typecheck, Fast Quality
Gates, Unit Tests 1-4) all fail on files this PR does not touch
(glm.ts, changelog.d/fixes/reset-aware-model-family.md, image-gen routes,
error-sanitizer suites, huggingchat/stream boundaries). None of those files
exist on release/v3.8.51, on this branch, or in a local base+head merge —
the CI run merged a transient upstream state at 09:46 UTC that has since
been rewritten. Verified: pristine base reproduces the same failures; my
3-file diff (cursor.ts, kimiToolCallNarration.ts, kimi test) is clean and
its 9 unit tests pass on the simulated merge ref.
…helper

Collapses the two inline recovery blocks in cursor.ts into one-line calls to
a new applyKimiToolCallRecovery() in kimiToolCallNarration.ts. The helper
takes a structurally-typed ctx + optional emit callback (streaming) so no
executor import is needed and no module cycle forms.

This resolves the PR's Fast Quality Gate failures attributable to the change:
- file-size: cursor.ts was 1804 > frozen 1759; now 1763, baseline ratcheted
  to 1764 with justification (file hard-capped, base already 1758, hook is
  irreducible at 2 call sites — gate-sanctioned last resort).
- complexity-ratchets: cursor.ts 11→12 / 4→5 now OK (2762 vs baseline 3218).

Behavior unchanged — 9/9 kimi tests, 458/459 cursor+composer (1 skip).
Remaining CI failures (glm.ts TS2554, mutation quotaScoring, changelog
fragment) are pre-existing upstream regressions on release/v3.8.51.
…er gate

Split scanJsonObjectEnd's inline string/escape state machine into a
nextScanState helper (was cognitive 16, threshold 15). Behavior unchanged —
9/9 kimi tests, 458/459 cursor+composer.

This clears the last Fast Quality Gate failure attributable to this PR
(cognitive-complexity new-code: kimiToolCallNarration.ts 0→1). Remaining red
(glm.ts TS2554, mutation quotaScoring, changelog fragment) is pre-existing
upstream drift on release/v3.8.51, not this PR.
…very

Addresses maintainer review on cheaper-inference#12723 — the only ask before merge was a
changelog.d/fixes/ fragment. Bullet summarizes the narration-imitation
failure mode, the structured tool_calls recovery in both finalization
paths, and the healthy-turn gate. Passes check:changelog-integrity (the
remaining invalid fragment, reset-aware-model-family.md, is pre-existing
upstream drift on release/v3.8.51, unrelated to this PR).
The v3851 recovery only fired when NO structured tool call existed, so a
turn that emitted a real tool call AND narrated the flattenMessages
dialect ('Assistant called tool ... <|close|>argument<|sep|>...') leaked
the narration verbatim into client-visible content. Kimi then mimics the
tool-RESULT serialization too ('Tool result (id):', 'User: <tool_result>
<tool_name>...<result>...</tool_result>'), which nothing caught —
compounding through history on every subsequent turn.

Three layers, one family:

1. Streaming holdback (cursor.ts): text deltas now pass through
   createNarrationStreamScrubber — a state machine that holds back text
   the moment it could start a dialect construct and only emits the
   safe prefix (same design as the Composer inline-tool parser). A
   narrated call is converted to a structured tool_calls chunk
   mid-stream; finish() flushes partial-trigger prose at EOF.

2. Ungated scrub (kimiToolCallNarration.ts): applyKimiToolCallRecovery
   now scrubs dialect constructs even when structured calls exist; only
   call SYNTHESIS stays gated on toolCalls.length === 0. The scrubber
   handles char-by-char and chunked arrival, truncated constructs at
   EOF, and bare keywords mid-prose (only consumed when a delimiter
   follows).

3. History hygiene (cursorAgentProtobuf.ts): flattenMessages scrubs
   gateway-dialect constructs from prior assistant visible text so old
   leaks stop re-anchoring the mimicry loop.

Fixes the 2026-09-15 leak class (Assistant called tool + User:
<tool_result> blobs rendered as User: content). 28 unit tests incl.
production leak specimen; 4/4 mutations killed.
…+ rebaseline cursor.ts (+34, annotated)

The two flush+recover call sites shrink to one line each via the new
finalizeKimiTurn helper in kimiToolCallNarration.ts; cursor.ts stays
file-size compliant against the 67f6c03 tip (base growth consumed the
old headroom; annotated rebaseline per repo convention).
…exity ratchets

CI Fast Quality Gates flagged kimiToolCallNarration.ts as new-code complexity
debt (cyclomatic 0->1 via max-lines-per-function on the 254-line scrubber
factory, cognitive 0->2 on scanJsonObjectEnd and the inline narrJson scan).

Hoist the closure state machine into a ScrubCtx object with module-level step
functions dispatched through STEP_BY_STATE, and reuse a single stepJsonScan
walker for both the batch and streaming JSON scans instead of duplicating the
string/escape/depth branching. Behavior is unchanged; the factory is now a
thin constructor.

Adds two EOF tests for the unterminated-narration-head branch: the refactor
surfaced that 'narrHead' residue flushing was never exercised (mutation
survived). With the tests, reverting that branch turns 2 red.

Tests: 30/30 in tests/unit/kimi-tool-call-narration.test.ts (was 28).
Complexity: 0 violations in the touched file (was 3).
tests/unit/claude-passthrough-cache-rescue.test.ts belongs to a separate
workstream and was swept in by a blanket 'git add -A'. It does not belong in
this PR's diff.
…er-inference#13627

Rebasing cheaper-inference#12723 onto the tip that now includes cheaper-inference#13627's kv_after_text fix
(merged into cursor.ts) produced a real conflict in
config/quality/file-size-baseline.json across two historical commits on
this branch (c4bdb8579, 8744eea27) that had each rebaselined cursor.ts for
their own growth at the time. Resolved to the actual current measured
line count (1847) after the rebase; codex.ts resolved to the higher/more
permissive of the two conflicting values (1528, untouched by this PR).
check:file-size, check:complexity-ratchets, check:cognitive-complexity,
generate-agent-skills --check all green; tsc clean; 30/30 kimi tests pass.
@patrykkopycinski
patrykkopycinski force-pushed the fix/cursor-kimi-narration-v3851 branch from 50f95d3 to 3cada1d Compare September 16, 2026 17:04
…ount (cheaper-inference#13079)

Merged after a maintainer rework that kept every one of @hartmark's commits intact.

**What the rework added:** the reclaimable-space gate for the auto-cleanup VACUUM sits behind a default-off feature flag so the release default is unchanged, with the flag documented in `docs/reference/FEATURE_FLAGS.md` and described in all 66 locales; the rest is your change as submitted.

Validated as a combined board first (this PR merged with the 21 siblings of the same wave on the release tip): eslint with the frozen suppressions, typecheck:core, check:open-sse-typecheck, complexity, cognitive-complexity, changelog-integrity, i18n new-key coverage, docs-counts, docs-sync, migration-numbering, provider-consistency and a duplicate-identifier audit all green, plus 176 passing / 0 failing focused node:test cases across the 25 test files the wave touches and the dashboard test under Vitest (2/0). Then re-validated alone on the fresh tip before this merge: conflicts re-resolved, file sizes rebaselined for this PR's own growth, eslint and this PR's focused tests re-run.

Thank you — gating VACUUM on reclaimable pages instead of row count is the right signal.
patrykkopycinski and others added 5 commits September 16, 2026 15:15
…rmat key (cheaper-inference#13617)

Merged after a maintainer rework that kept every one of @patrykkopycinski's commits intact, including the changelog fragment you added afterwards.

**What the rework added:** the `eslint-suppressions.json` diff was corrected (the PR had dropped live entries) and a test now proves the CLI-probe fallback path is actually taken when the HTTP API rejects a CLI-format key — before, the fallback existed but nothing exercised it.

Validated as a combined board first (this PR merged with the 21 siblings of the same wave on the release tip): eslint with the frozen suppressions, typecheck:core, check:open-sse-typecheck, complexity, cognitive-complexity, changelog-integrity, i18n new-key coverage, docs-counts, docs-sync, migration-numbering, provider-consistency and a duplicate-identifier audit all green, plus 176 passing / 0 failing focused node:test cases across the 25 test files the wave touches and the dashboard test under Vitest (2/0). Then re-validated alone on the fresh tip before this merge: conflicts re-resolved, file sizes rebaselined for this PR's own growth, eslint and this PR's focused tests re-run.

Thank you.
…inned, all harnesses (cheaper-inference#13448)

Merged after a maintainer rework that kept every one of @patrykkopycinski's commits intact — including the two refactors you pushed later (extracting the adaptive-effort wiring out of `chatCore.ts` and reading `x-omniroute-effort` inside the wiring module), which were merged into the rework rather than overwritten.

**What the rework added:** the adaptive-effort wiring is scoped to OpenAI-dispatch requests only (the claim in `docs/routing` was corrected to match), and `defaultReasoningEffort` was widened to accept `auto` explicitly instead of relying on a loose string.

Validated as a combined board first (this PR merged with the 21 siblings of the same wave on the release tip): eslint with the frozen suppressions, typecheck:core, check:open-sse-typecheck, complexity, cognitive-complexity, changelog-integrity, i18n new-key coverage, docs-counts, docs-sync, migration-numbering, provider-consistency and a duplicate-identifier audit all green, plus 176 passing / 0 failing focused node:test cases across the 25 test files the wave touches and the dashboard test under Vitest (2/0). Then re-validated alone on the fresh tip before this merge: conflicts re-resolved, file sizes rebaselined for this PR's own growth, eslint and this PR's focused tests re-run.

Thank you — gateway-resolved, per-turn pinned effort is a real feature, and the header contract makes it usable from every harness.
…m send (cheaper-inference#13355)

Merged. Internal `_omniroute*` markers must never reach an upstream: at best they are noise in someone else's logs, at worst they change the upstream's parse. Stripping every one of them before the send is the right invariant.

Validated as a combined board first (this PR merged with the 21 siblings of the same wave on the release tip): eslint with the frozen suppressions, typecheck:core, check:open-sse-typecheck, complexity, cognitive-complexity, changelog-integrity, i18n new-key coverage, docs-counts, docs-sync, migration-numbering, provider-consistency and a duplicate-identifier audit all green, plus 176 passing / 0 failing focused node:test cases across the 25 test files the wave touches and the dashboard test under Vitest (2/0). Then re-validated alone on the fresh tip before this merge: conflicts re-resolved, file sizes rebaselined for this PR's own growth, eslint and this PR's focused tests re-run.

Thank you.
@diegosouzapw
diegosouzapw merged commit c4293e2 into cheaper-inference:release/v3.8.51 Sep 16, 2026
4 of 6 checks passed
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…eaper-inference#12723)

Merged. Kimi emitting tool calls as history narration is a provider quirk we have to absorb rather than pass through; recovering them keeps the tool contract intact for clients that never see the quirk.

Validated as a combined board first (this PR merged with the 21 siblings of the same wave on the release tip): eslint with the frozen suppressions, typecheck:core, check:open-sse-typecheck, complexity, cognitive-complexity, changelog-integrity, i18n new-key coverage, docs-counts, docs-sync, migration-numbering, provider-consistency and a duplicate-identifier audit all green, plus 176 passing / 0 failing focused node:test cases across the 25 test files the wave touches and the dashboard test under Vitest (2/0). Then re-validated alone on the fresh tip before this merge: conflicts re-resolved, file sizes rebaselined for this PR's own growth, eslint and this PR's focused tests re-run.

Thank you.
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.

3 participants