Skip to content

Consolidate repo under src/ and tools/, fix the rename regressions and vacuous tests it exposed - #200

Merged
MelbourneDeveloper merged 29 commits into
mainfrom
cleanup
Aug 4, 2026
Merged

Consolidate repo under src/ and tools/, fix the rename regressions and vacuous tests it exposed#200
MelbourneDeveloper merged 29 commits into
mainfrom
cleanup

Conversation

@MelbourneDeveloper

@MelbourneDeveloper MelbourneDeveloper commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

TLDR

Consolidate the repository under src/ and tools/, then fix the correctness regressions, vacuous tests, coverage gaps and high-severity CVEs that the move exposed.

Details

Restructure (483 renames, no content change). editors/src/editors/, sidecars/src/sidecars/, website/src/website/, scripts/tools/. Coverage config moves to .config/coverage/. The monolithic Makefile splits into tools/make/*.mk, and the single CI workflow splits into reusable legs (ci-lint, ci-rust, ci-dotnet, ci-vsix, ci-vsix-windows) orchestrated by ci.yml. Four files are deleted without a relocated twin, each with a replacement in tree: scripts/check-coverage.shtools/coverage/check-coverage.mjs; editors/vscode/.eslint.jseslint.config.mjs; docs/bugs/BUILD-GENERATEDEPSFILE-LOCK-BUG.md → covered by docs/specs/DISTRIBUTION-SPEC.md; .claude/settings.local.json (machine-local).

Rename correctness — C# sidecar. HasDeclarationConflict treated locals, parameters, type parameters and range variables as colliding with same-named members of the enclosing type. Those kinds legally shadow a member, so the check now defers to Roslyn's Renamer for them. Before the fix the rename returned an empty edit, which reaches the editor as a null workspace edit — it silently did nothing, with no error.

Rename correctness — Rust host. Cross-language enrichment in semantic.rs is now best-effort. A crashed or wedged fallback sidecar previously propagated its error and discarded a rename the primary sidecar had already computed correctly, and a single unconvertible document path failed the whole edit. Failures are logged and the primary edits returned unchanged.

Rename correctness — F# sidecar. Record types, escaped backtick identifiers and indexers (Item / explicit DefaultMember) now rename correctly, fixed at source rather than in tests. Also fixes three code-generation defects in FSharpCodeActions.fs: stubs emitted trailing whitespace, record defaults emitted bare Guid instead of System.Guid (FS0039), and a match! stub omitted the return inside a computation expression (FS0193).

Code-action resilience. GetCodeActionsAsync reinstates the direct TextSpan.FromBounds path with clamping, replacing a helper that dropped the request when an end position fell outside the document.

Test fixtures are now built before the extension host launches. Nothing restored or built test-fixtures/workspace, so on a clean checkout Roslyn had no resolved references. Unused-package detection intersects declared PackageReferences with the assemblies Roslyn resolved, so with nothing restored the result was empty — and the tests asserted that empty result. They passed on CI while proving nothing, and failed on any machine where the fixture happened to be built. This has to run in pretest: Roslyn loads the solution on the first C# file any suite opens, and a build concurrent with a running chunk actively poisons it.

Coverage. Roughly 2,700 lines of new C# and ~560 lines of new F# landed on this branch tested only through the VS Code extension host, which exercises the code but produces no sidecar coverage. HeadlessOverrideSyntax.cs was the extreme case at 0 of 198 lines. New sidecar-level suites cover the headless override generator, the style-rewrite analyzer chain, the merge-declaration refactoring, and the F# rename and code-action engines.

Security. brace-expansion was pinned by an override to 2.0.3, carrying three high-severity advisories (GHSA-3jxr-9vmj-r5cp, GHSA-mh99-v99m-4gvg, GHSA-rgw5-rvv9-x895); the 5.x pin at 5.0.8 was also vulnerable to the third. Bumped to 2.1.4 / 5.0.9, plus npm audit fix for fast-uri and undici. npm audit: 0 high, 0 critical, down from 5.

Test-suite integrity. The SIGKILL auto-recovery test (GitHub #8) guarded itself off with this.skip() on win32 because it shelled out to POSIX ps — silently dropping that coverage on the platform the Windows VSIX leg exists to protect. Process enumeration is now cross-platform via Get-CimInstance Win32_Process, matching on exact executable path. A profiler heap-dump test raced the target's startup and is now retried until the hotspot type is live, with the assertion unchanged (#202). .vscode-test/ is excluded from eslint — it made make lint pass in CI and fail locally with 3090 parse errors on vendored .d.ts.

How Do The Automated Tests Prove It Works?

C# rename shadowingWorkspaceManagerRenameShadowingTests. A theory renames the parameter seed and the local total onto the existing field name _counter, asserting Assert.NotEmpty(edit.DocumentChanges). Both fail against the pre-fix code with Assert.NotEmpty() Failure: Collection was empty. The control — renaming field _counter onto the existing method name Compute — still asserts Assert.Empty, proving the conflict check was narrowed, not removed.

Rust rename toleranceunconvertible_document_path_is_skipped_not_fatal builds a result with one relative (unconvertible) and one absolute path, asserting the absolute document's edit survives while only the unconvertible one is dropped.

NuGet unused detection — now asserts resp.unused deep-equals [{ id: 'Serilog', version: '4.4.0' }] rather than asserting the array is empty; the old assertion would also have been satisfied by a pipeline returning nothing. The command test drives the real modal through installUiStubs(), asserts the prompt names Remove 1 unused package, Serilog and TestFixtures.csproj, then asserts the checked-in .csproj is byte-identical after cancelling.

Headless override generation — five tests apply the action (previously it was only ever asserted as offered, so the entire declaration-building half never ran) against a base type covering plain and generic methods, nullable-annotated type parameters forcing where T : default and where TRef : class, read/write, get-only and init-only properties, an indexer, an event and a protected member. Asserts accessibility is carried across rather than widened, init survives as an accessor, bodies throw rather than returning a default, members the type already overrides are not regenerated, and the result parses.

Merge-declaration refactoring — eight tests apply the transform and cover the cases it must decline: an already-initialized declaration, an assignment to a different symbol, and a declaration whose next statement is not an assignment.

Analyzer chain — seven tests prove providers are discovered by reflection and de-duplicated, only analyzers backing one of the four rewrite ids are selected, and each rewrite is offered exactly once (both the syntax and semantic passes report IDE0161, so the de-duplication in FilterDiagnostics is load-bearing).

Cross-language rename determinismRepository_mixed_solution_resolves_the_exact_FSharp_identity_into_CSharp passed only where the fixture happened to be built: MSBuildWorkspace cannot load an .fsproj, so the project reference degrades to a metadata reference read off disk. Reproduced by moving the fixture's bin/obj aside, then fixed by having the test build the project itself, pinned to Debug because MSBuildWorkspace opens under MSBuild's default configuration. Verified from a fully cleaned fixture tree.

Suite totals — Rust 654 tests across four binaries, 0 failures, cargo clippy --all-targets -- -D warnings and cargo fmt --all -- --check clean. .NET 942+ tests, 0 skipped. VS Code Windows chunks all pass through a real extension host: lsp, fsharp, explorer, lifecycle, debug, profiler, packages.

Coverage gatessharplsp-sidecar-csharp 89.06% → 94.69%, sharplsp-sidecar-fsharp 88.77% → ~94.45%. Stored thresholds are untouched at 95%: check-coverage.mjs hard-fails if a committed threshold ever decreases and only ratchets upward. Both now pass on the 1pp tolerance rather than at the historical 95% bar; tracked in #203 with the remaining gaps enumerated.

Related

… real

Regressions from the restructure/cleanup commits, plus two vacuous tests the
restructure exposed.

C# rename silently no-opped on legal shadowing. HasDeclarationConflict scanned
the enclosing type's members for locals, parameters, type parameters and range
variables too, but those legally shadow a same-named member. Renaming a
parameter onto a field name returned an empty edit, which reaches the editor as
a null workspace edit: the rename appeared to do nothing, with no error.

Rust rename discarded correct edits on any cross-language hiccup. A crashed or
restarting fallback sidecar made the enrichment step propagate an error and kill
a rename the primary sidecar had already computed; a single unconvertible
document path failed the whole edit. Enrichment is now best-effort with a
warning, and per-document conversion tolerance is restored.

codeAction resilience: reinstate the direct TextSpan.FromBounds path so an
out-of-range end position clamps instead of dropping the request.

NuGet unused-detection tests were passing vacuously. Adding
<Compile Remove=crosslanguage/**/*.cs /> to TestFixtures.csproj was correct --
those files belong to the downstream CSharpConsumer project -- but until then
TestFixtures compiled FSharpConsumer.cs without the F# project reference, so the
compilation had errors and GetUsedAssemblyReferences conservatively reported
every reference as used. That produced an empty unused set, which the tests
asserted. Both now assert the truth: the fixture declares Serilog and no
compiled source references it, so detection must flag exactly Serilog 4.4.0. The
command test drives the real modal through the UI-stub harness and asserts
cancelling leaves the checked-in project file byte-identical.

Sequester the unshipped formatting implementation from the deslop and lint
gates, and add a scratch-file guard to .gitignore.
Apply `dotnet csharpier format` to five sidecar files the CI format gate
rejected.

lsp-lifecycle: the SIGKILL auto-recovery test guarded itself off with
`this.skip()` on win32 because the helper shelled out to POSIX `ps`. The Windows
VSIX leg is a real CI job, so that silently dropped GitHub #8 coverage on the
platform the extension most needs it. Process enumeration is now
cross-platform: `Get-CimInstance Win32_Process`, the supported replacement for
the removed `wmic`, projects pid and executable path directly, so paths
containing spaces survive intact rather than being truncated by a command-line
split. Verified locally: 171 processes parsed, 79 of them with space-bearing
paths, the VS Code install path among them. Matching stays exact-path and uses
the host filesystem's case sensitivity, so the kill can only ever hit the test
host's own staged sharplsp binary.
…CVEs

Three CI failures, all real.

Repository_mixed_solution_resolves_the_exact_FSharp_identity_into_CSharp passed
only on machines that had already built the fixture. Roslyn's MSBuildWorkspace
cannot load an .fsproj, so CSharpConsumer's project reference degrades to a
metadata reference resolved from the F# project's build output on disk. On a
clean checkout that assembly does not exist, FSharpOrigin never binds, the
foreign rename matches nothing, and DocumentChanges comes back empty. Confirmed
by moving the fixture's bin/obj aside and reproducing the exact CI failure
locally, then confirming a lone `dotnet build` of FSharpFixtures.fsproj makes it
pass. The test now builds that project itself, once, gated by a semaphore. The
configuration is pinned to Debug rather than inherited because MSBuildWorkspace
opens the solution under MSBuild's default configuration, so Debug is where it
looks regardless of how the test assembly was built. Verified from a fully
cleaned fixture tree.

Dependency review: brace-expansion was pinned by an override to 2.0.3, which
carries three high-severity advisories (GHSA-3jxr-9vmj-r5cp, GHSA-mh99-v99m-4gvg,
GHSA-rgw5-rvv9-x895). Bumped to 2.1.4, the first version patched against all
three. The 5.x override was pinned to 5.0.8, still vulnerable to
GHSA-rgw5-rvv9-x895, so it moves to 5.0.9. `npm audit fix` additionally clears
high-severity advisories in fast-uri and undici. npm audit now reports 0 high and
0 critical, down from 5; the 3 remaining low findings are below the gate's
fail-on-severity threshold. package.json was edited through a JSON parse rather
than text splicing, and the diff is the two override values only.

eslint: ignore .vscode-test/. It holds the VS Code build the test host
downloads, so it exists only on a machine that has run the VSIX suite — `npx
eslint .` passed in CI and failed locally with 3090 parse errors on vendored
.d.ts files that are not our source.
The e2e suites drive a real LSP over test-fixtures/workspace, but nothing ever
restored or built that solution, so on a clean checkout Roslyn had no resolved
references to reason about.

Unused-package detection is the case that exposed it. Detection intersects a
project's declared PackageReferences with the assemblies Roslyn actually
resolved, so with nothing restored there is no Serilog assembly in the
compilation's reference set, nothing can be classified, and the request returns
an empty list. The suite asserted that empty list, so it passed on CI while
proving nothing, and failed on any developer machine where the fixture happened
to be built. CI confirmed the inversion exactly: expected [Serilog 4.4.0],
actual [].

This has to run in pretest rather than a suite setup. The extension activates
and Roslyn loads the solution on the first C# file any suite opens, and building
after that point does not refresh the already-loaded snapshot -- and a build
concurrent with a running chunk actively poisons it with project-wide compiler
errors. Debug is pinned because MSBuildWorkspace opens the solution under
MSBuild's default configuration.

Verified by deleting every bin/obj under the fixture tree, running the new step,
confirming Serilog resolves into obj/project.assets.json, then running the
Package Maintenance suites through a real extension host: 20 passing, 0 failing.
Three defects made F# rename abort or silently refuse. Each was pinned by
probing FCS on a real multi-file project, not by reading the code.

Record types could not be renamed at all when the project contained a
copy-and-update expression anywhere. FCS reports `{ value with Field = 1 }`
as a use of the record type at a ZERO-WIDTH range on the `{`. There is no
identifier there to rewrite, but a single unlocatable use failed the whole
rename with "could not classify every semantic use". Zero-width uses are
compiler-inferred and are now skipped, the same way an implicit indexer use
already was.

Escaped identifiers were refused outright. FCS reports `DisplayName` for
``an escaped identifier`` carrying its backticks, while the token comparison
stripped backticks from the token side only, so the two never matched:
prepareRename returned null at every column and rename produced no edits.
Both sides are now compared as logical names.

Renaming an indexer offered a rename that then failed. An `x.[i]` call site
reports the property's getter rather than the property, and
`FSharpSymbol.Equals` does not hold across separately-read symbol instances,
so the accessor never resolved back to its declaring property. Identity now
uses the compiler's own `IsEffectivelySameAs`. Index parameters live on the
accessor, not on the property symbol, so the property's own (empty) parameter
groups are no longer the sole test for an indexed property.

The indexer rename writes DefaultMember metadata for the new name so `.[i]`
call sites keep binding; the VS Code test asserts the usages file stays free
of compiler errors, which is what actually proves it.

Adds FSharpRenameSemanticTests.fs covering all three against real .fsproj
fixtures and live FCS results. Replaces the VS Code test that asserted an
indexer rename is rejected -- it contradicted the shipped DefaultMember
support -- with one that drives the rename through the editor and verifies
the result compiles.

F# sidecar suite 350/350, 0 skipped. VS Code fsharp chunk 124 passing,
0 failing through a real extension host.
The C# sidecar coverage gate failed at 89.0604% against an effective 94%
threshold. HeadlessOverrideSyntax.cs was the single largest hole: 0 of 198
lines, never executed by any test.

The cause was that the "Generate overrides..." action was only ever asserted as
*offered*. Nothing resolved it, and the entire declaration-building half of the
feature only runs on resolve. Roslyn's own implement/override components are
MEF-only and unavailable headlessly, which is exactly why the sidecar builds
these declarations itself -- so the generator could have emitted uncompilable
C# and no test would have noticed.

These five tests load a real MSBuild project whose base type covers every shape
the generator special-cases -- plain and generic methods, generic methods whose
nullable annotations force an explicit constraint clause, read/write, get-only
and init-only properties, an indexer, an event, and a protected member -- then
resolve the action and assert on the C# that comes back: that accessibility is
carried across rather than widened, that `where T : default` and
`where TRef : class` are restated, that `init` survives, that bodies throw
rather than returning a default, that a member the type already overrides is
not generated a second time, and that the resulting file still parses.

Coverage for the package moves from 87.5789% to 91.8770% locally, with
HeadlessOverrideSyntax.cs going from 0/198 to 162/198.

Filed #201 for a defect this surfaced: Roslyn's own MEF-based
"Generate overrides..." can be offered alongside the headless one under the
identical title, and throws IPickMembersService on resolve. Left out of this
change to keep its scope honest.
AnalyzerDiagnosticResolver was the next largest coverage hole after the override
generator: 154 of 196 lines, with the whole discovery-and-filter chain unproven.

The `use var` and `file-scoped namespace` rewrites are code *fixes*, not
refactorings, so they only appear when the matching IDE analyzer actually
reports over the requested span. Three things have to line up for that: the
Roslyn feature assemblies found by reflection (they are MEF-composed and cannot
be resolved through a headless workspace), the project's .editorconfig driving
the style preference, and a span filter that connects a diagnostic on the
namespace declaration to a caret on the `namespace` keyword. None of it was
covered, so a regression in discovery or filtering would have turned the entire
rewrite family off without a single failing test.

The repository's own VS Code fixture sets EnableNETAnalyzers=false and
AnalysisMode=None, so these rules can never fire there. This project turns them
on and supplies the .editorconfig they need.

Seven tests: providers are discovered and de-duplicated by concrete type, only
analyzers backing one of the four rewrite ids are selected, an empty provider
set selects nothing, a caret on the `namespace` keyword offers the file-scoped
rewrite, an explicitly typed local offers the `var` rewrite, and a caret inside
the namespace body sees each rewrite exactly once -- the resolver unions syntax
and semantic diagnostics and both passes report IDE0161, so the de-duplication
in FilterDiagnostics is load-bearing.
…hing

Two of the assertions in the previous commit were weaker than they looked.

`Assert.Contains("init", generated)` matched a substring, not an accessor --
"init" occurs inside plenty of unrelated identifiers, so it would have passed
against a property regenerated with `set`. It now bounds the search to the one
declaration and asserts `init` is present and `set` is not.

The already-overridden check only covered a non-generic method and a plain
property, so the signature comparison's interesting half never ran. `Circle`
now also overrides the three generic members, which exercises type-parameter
ordinal and kind matching, array rank and element type recursion, and
constructed generic arguments. Those feed the "is this slot already filled"
decision, and a false negative there emits a duplicate member that does not
compile. Counts are taken inside `Circle` only, since the abstract declarations
in `Shape` carry the same names and would mask a duplicate.

Worth recording: the generic overrides initially appeared to expose a
duplicate-generation bug in the sidecar. They did not. `Circle.PickReference`
without restating `where TRef : class` is CS0115 -- `TRef?` binds as
`Nullable<TRef>`, which requires a value type, so the signature genuinely does
not match the base and the slot really was unfilled. Confirmed by compiling the
fixture shapes standalone before drawing a conclusion. The fixture was wrong,
not the generator.
… allocations

test_profiler_object_graph_roots_inspect_and_diff_full_stack failed on CI with
"baseline heap dump must contain StringBuilder instances (ProfileTarget
allocates them constantly)".

The comment is true in steady state but not at process start.
start_profiler_session returns as soon as the target process and the LSP client
are up -- it does not wait for the target to reach its allocation loop -- and
the test took the baseline dump immediately afterwards. A dump that lands before
the loop's first iteration legitimately contains no StringBuilder at all, and
harvest_heap_address returns None.

The baseline is now collected repeatedly until the hotspot type is live. Nothing
is weakened: if StringBuilder never appears, the final attempt still fails on
exactly the same requirement with the same message. Closes #202.

Verified: the test passes locally, and cargo clippy --all-targets -- -D warnings
and cargo fmt --all -- --check are both clean.
…g it

MergeDeclarationAssignmentCodeRefactoringProvider sat at 51.5% line coverage.
Like the override generator, it was only ever asserted as *offered* -- nothing
resolved it, so the whole rewriting half never ran: building the initializer,
carrying the assignment's trivia across, and deleting the now-redundant
statement. A provider that emitted uncompilable C#, or that offered itself on a
declaration it must not touch, would have shipped unnoticed.

Eight tests drive the real provider through a loaded MSBuild project: merging
from the declaration and from the assignment, an already-initialized
declaration left alone, an assignment targeting a different symbol, and a
declaration whose next statement is not an assignment.

This is claude-refactor-finisher's work, committed from the shared worktree so
the C# sidecar coverage gate clears in one CI cycle rather than two -- it is the
~1.3pp between the 93.47% CI last measured and the 94% effective threshold.
…via VSIX

Fixing the C# sidecar coverage gate unmasked the F# one: fail-fast had been
stopping the run before it was ever evaluated. F# sat at 88.77% against the same
94% effective threshold.

The cause mirrors the C# side exactly. FSharpRenameAliases, FSharpRenameIndexers
and FSharpRenameToken are roughly 560 lines all new on this branch, and their
only tests ran through the VS Code extension host. Those exercise the code but
produce no sidecar coverage, so from the gate's point of view the rename engine
was largely untested -- worst was FSharpRenameAliases at 29%.

These tests drive the same paths directly through the sidecar: module
abbreviations, explicit DefaultMember indexers, escaped backtick identifiers,
record-type classification, and the indexer call-site and partial interface stub
cases.

Also deletes locateUsesAs from FSharpRename.fs. It had no callers -- dead code
counted against the denominator while being impossible to cover.

F# sidecar coverage moves 88.77% -> 94.4533%, above the 94% effective threshold,
with the stored 95% left untouched. All 373 F# sidecar tests pass, 0 skipped.
dotnet csharpier check and make _lint-dotnet are both clean.

This is claude-refactor-finisher's work, committed from the shared worktree to
land it in the same CI cycle as the C# gate fix.
Completes the F# coverage work started in 5bde4d6, which I committed from the
shared worktree while it was still being split into two files and so caught only
part of it. This is the remainder: the code-action tests moved out of
FSharpRenameSemanticTests.fs into their own file, plus the Compile entry that
registers it.

Same root cause as the rename engine and as the C# side: the code-action paths
were exercised only through the VS Code extension host, which produces no
sidecar coverage, so the gate saw them as untested.

F# sidecar coverage 88.77% -> 94.4533%, above the 94% effective threshold, with
the stored 95% untouched. All 375 F# sidecar tests pass, 0 skipped. dotnet
csharpier check and make _lint-dotnet are clean.

Measured and committed from a hash-verified identical tree this time, so the
number above describes exactly what landed.

claude-refactor-finisher's work, committed from the shared worktree.
Renaming an indexer to an escaped identifier must put the *logical* name in the
DefaultMember literal: backticks are source syntax, not part of the member name,
and `[<DefaultMember("``My Slot``")>]` would not bind. Renaming an indexed
property that is neither named `Item` nor already carries DefaultMember metadata
has no way to keep `x.[i]` binding at all, so it must fail loudly instead of
emitting a half-rename that silently breaks every call site.

The DefaultMember fixture gains a decoy type ahead of the indexer so the
parse-tree search has to reject a non-matching type definition before reaching
the right one.

Brings the F# sidecar package to 94.00% against its unchanged 95% threshold
(94% effective), so the .NET coverage gate passes on all three packages.
… engine

Adds the paths the .NET coverage gate still could not see:

- Record fields and union cases each carry their own XML doc signature kind, so
  both must resolve to a cross-language identity. Without it a C# rename of
  either silently skips the F# side.
- A read/write indexer reaches its property through the setter as well as the
  getter, so renaming one must still rewrite the member and record its metadata.
- DefaultMember metadata naming its member through a [<Literal>] constant cannot
  be rewritten in place -- editing the attribute would mean editing a constant
  that may be shared -- so the rename must refuse rather than leave the metadata
  pointing at the old name.

Also carries the accessor-stub cases for the get/set, getter-only and setter-only
shapes of an interface implementation, which pick the insertion point by
comparing accessor ranges rather than taking the member's range. Those found a
real gap: the generator still offers a property that a `with get () = ... and
set v = ...` member already implements, which would not compile if accepted.
The tests assert what is correct today and the gap is tracked separately.

F# sidecar package 94.17% locally; 983 sidecar tests pass and the gate exits 0
on all three packages. Note the local figure reads high against CI: coverage
counts the untaken arm of `OperatingSystem.IsWindows()` as missed, so Linux
measures roughly three lines lower than Windows for the same commit.
…ation baseline

The VS Code full suite failed twice in a row on this branch with "Error
diagnostic baseline never stabilized", the only failure among 767 tests.

It is not a diagnostics regression. This branch rewrote the test, and the
rewrite contradicts itself against what main asserted:

  main:   waitForErrorsCleared(uri, 120_000)          -- expects zero errors
  branch: waitForStableErrorBaseline(uri, 120_000, 18) -- expects eighteen
          assert.strictEqual(baseline.length, 18)

FluentValidation is pinned at tag 12.1.1, a released library. A correctly
resolved IValidator.cs reports no errors at all, so the count never reaches the
required eighteen, waitForStableErrorBaseline can never return, and the wait
burns its full timeout. Eighteen looks like a figure observed against a clone
that had not finished restoring; it encodes how much of the solution the server
had resolved at that moment, not a property of the source.

The baseline is now whatever the server settles on. Nothing else is relaxed --
the round trip is still asserted end to end, and more strictly than main ever
did: the injected error must be CS0029 from source sharplsp-csharp, on the
inserted line, naming 'int' and 'string', with a sane range; undo must advance
the version and restore the source byte for byte; and the diagnostics must
return to exactly the captured baseline via waitForErrorBaseline. main only
checked that errors cleared.

Two supporting fixes:

waitForStableErrorBaseline now reports what it observed when it gives up --
the minimum it wanted, the timeout, and the diagnostics it actually settled on.
The old message could not distinguish "too slow" from "asked for a count this
file will never produce", which is exactly the confusion that cost this
investigation two full CI runs.

The test's own budget was 180s while performing four sequential waits of 120s
each. Under load mocha would have killed it before any inner deadline fired,
reporting an opaque timeout rather than the stage that stalled. Raised to 600s
so the inner deadlines are the ones that speak. Closes #207.
@MelbourneDeveloper
MelbourneDeveloper marked this pull request as ready for review August 4, 2026 02:03
@MelbourneDeveloper
MelbourneDeveloper merged commit a687afb into main Aug 4, 2026
26 checks passed
@MelbourneDeveloper
MelbourneDeveloper deleted the cleanup branch August 4, 2026 02:04
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.

1 participant