Skip to content

Fuse 5.7.0

Latest

Choose a tag to compare

@github-actions github-actions released this 29 Oct 23:42
699c7cc

Compared with 5.6.0. Check and test answers use new output shapes, and the engine does more work in the background and keeps new state files. fuse check accepts directories and patterns, a launcher can register an external writer as a session, and the stop hook checks only the stopping session's files. fuse test reruns the tests that failed last time and runs them first. fuse build gains --changed and --warnings, and fuse status is new.

Update with dotnet tool update -g Fuse. The hook settings fuse init writes are unchanged, so you do not need to run it again. Run fuse init --instructions again to refresh the Fuse section in AGENTS.md. The first command after updating restarts the engine for the new protocol, and no request fails. A script that parses fuse check or fuse test output must accept the new group headers and the tree stamp at the end of the summary.

Added

  • Every command takes --help and -h, which print that command's usage to standard output and exit 0, running nothing. fuse hook --help prints its usage to standard error and exits 0 without reading stdin. A command refuses an unknown option with exit 2 and its usage. For fuse build and fuse test, the command refuses only a near miss of a Fuse option (fuse: '<token>' is not a fuse build option; did you mean '<option>'? for builds, and the same form for tests), and passes every other token to dotnet unchanged. Commands shows each usage.
  • fuse build and fuse check take --max-errors <n>, --all-errors and --json. The default answer shows 20 errors; --max-errors takes 1 to 100000, and --all-errors shows every error. --json prints one JSON object per error, with the text summary as the last line. Each object holds file, line, column, code and message, leaving out line and column for a general error; a check adds cause and generated when present, and a locked build error adds lockedBy. A JSON summary never names a file. A capped build summary ends with ; all N in <state>/last-build-results.txt. That file holds every error and warning, and in JSON mode the errors are also in last-build-results.json. A failed build with no parseable error prints the output tail before the summary, as text mode does. The fuse_check tool takes max_errors (1 to 100000, default 20). Commands shows the check forms and the build forms.
  • fuse test --failed reruns the tests that failed in the last recorded run. fuse test refuses --failed with --all or any other argument, exiting 2 and running nothing. It also refuses a rerun with nothing recorded to rerun: fuse: no test run is recorded yet; run fuse test first and fuse: the last test run was from dotnet test arguments, so its failures cannot be rerun; run fuse test exit 2. When the last recorded run had no failures, fuse: the last test run had no failures exits 0. A rerun prints reran N test(s) that failed last time in M test project(s), names each dropped project with ; left out X, which is not a test project in this repository, and says when the rerun widened past the failures. When none of the recorded tests still exists, it prints fuse: none of the N test(s) that failed last time ran; they may have been renamed or removed and exits 1. After --, every token goes to dotnet test unchanged, even --all and --failed. The fuse_test tool takes failed, and refuses it together with all. The record is last-test-results.json, beside last-test-results.txt in the state directory, holding the last run's per-test verdicts and durations for at most 20,000 tests. A corrupt file counts as no record. Commands shows the forms (#125).
  • fuse build --warnings lists the build's warnings after its errors, at most 20 of them, each indented. The summary counts the rest as ... N more warning(s) in <state>/last-build-results.txt, and the file holds every warning under ## warnings. A warning that is also an error prints once, as an error, and the warning count in the summary stays MSBuild's. fuse check has no --warnings: the check refuses it, since warnings come from the build. Commands shows the form.
  • fuse build --changed builds only the projects that own files changed since HEAD and their dependents. Fuse reduces the set to the highest projects, and each dotnet build gets the same extra arguments. It first prints which projects it builds (fuse: building M project(s) for N changed file(s) (tree H): names), then one build (<name>) summary per project, and F of M project(s) failed when several build. With no C# changes it builds nothing and prints fuse: no C# changes since HEAD; nothing to build (tree <hash>). When the selection cannot be trusted, because project files changed or no project owns the changes, it says so and builds the whole solution instead. Commands shows the form.
  • fuse status shows the engine and the changed files: whether an engine runs and its memory, how many files differ from HEAD with their tree stamp and HEAD, and the large-tree limits. It never starts an engine. Past a short wait it reads the tree from git instead. fuse status --json prints one object with engine, pid, memoryMB, changedFiles, head, tree, reloadAt and wholeProjectAt. It exits 0 in a repository and 2 outside one. Commands shows both forms.
  • fuse session begin <name> --paths <pattern> [<pattern>...] registers an external writer a launcher starts as a session for its path patterns, so a judge's stop leaves that writer's half-written errors to it. It prints fuse: session <name> registered for N path pattern(s); files under them count as that session's until fuse session end <name> or 4 hours pass. Beginning the name again replaces its patterns and restarts the 4 hours. fuse session end <name> prints fuse: session <name> ended; its files now count as no session's, and refuses an unknown name with fuse: no registered session named <name> and exit 2. A name holds 1 to 64 letters, digits, -, _ or .. A pattern is repository-relative, with ** as a whole segment and * and ? inside a segment, at most 256 characters and 32 patterns per session, with 64 sessions live at once. Registrations live in registered-sessions.tsv in the state directory and survive an engine restart. fuse uninit deletes them, but fuse stop keeps them. A plain fuse check still reports every error. Commands shows both forms, and Subagents and parallel agents explains external writers (#129).
  • fuse check takes directories and glob patterns as well as files. Any existing directory or argument with * or ? makes the whole call scoped. You can mix files, directories and patterns. An error summary adds ; checked <paths> and what it reaches, and a clean answer reads fuse: no errors introduced in <paths> and what it reaches (N file(s) checked). The check refuses a spec that matches no changed C# source, as well as a scope expanding past 2000 source files, each with exit 2 and running nothing. The fuse_check tool stays files-only. Commands shows the forms (#127).
  • fuse test leaves out test projects that need a container runtime when none answers. A project is container-gated when any of its package references is Testcontainers or starts with Testcontainers.. Fuse probes docker info then podman info, 2 seconds each, and caches the answer for 5 minutes per engine process. The summary names tests in container-gated projects as ; skipped N test(s) in P1, P2 (no container runtime). When no test can run, Fuse starts no process and prints fuse: no test ran: N test(s) selected in P need a container runtime, and none is running; start Docker or Podman and run fuse test again, exiting 1. A run that passes arguments to dotnet test runs without that check. Commands shows the lines, and Limits covers which projects are container-gated.
  • When the pre-shell hook rewrites an agent's dotnet test or dotnet build, the rewritten command prints a notice on standard error first: fuse: dotnet test routed to fuse test (tests affected by your changes; fuse test --all runs every test) and fuse: dotnet build routed to fuse build (first 20 errors; fuse build --all-errors for every error). A command you type yourself prints none. Connect your agent explains the rewrite.
  • When a build error says a file is locked (MSB3021, MSB3026 or MSB3027), an indented line follows the error, naming the file and the process that holds it (locked: <file> is held by <name> (pid <n>); stop that process, then run the build again), or dotnet build-server shutdown when the holder is a build server. In JSON mode Fuse leaves the line out and carries the holder in lockedBy. Commands shows the line, and Troubleshooting covers the fix.
  • fuse check names the changed files in other languages that it does not check. The summary ends with ; N non-C# file(s) changed, which Fuse does not check: <paths>, naming the first 5 and counting the rest, on clean and error answers alike. With named files it covers the whole tree's delta, not the named scope. The post-edit hook never shows it, and the stop hook shows it only when it already blocks. Commands shows the line, and Limits covers what a check does not see.
  • The evals gain a scale suite and a stale suite. scale measures one cold check of 1,500 changed files in 6,000 over 30 projects plus one test project on a generated fixture, resizable with --projects, --files and --changed. The result's factor extrapolates full-scale numbers; never quote them as measured. stale breaks one file through the post-edit hook, fixes it, and checks whether the stop hook delivers a stale error. The selection suite takes --failed-rounds for fix-and-rerun rounds with fuse test --failed, and the result files record kept answers, reused errors, result-file completeness and member-walk scope. Evals describes the suites and fields.

Changed

  • Check errors that share a cause print under one header naming it once: changed: <declaration> (N error(s)), or (N error(s), first M shown) when the cap cuts the group. Member error lines keep their shape at column 0, and last-check-results.txt stays flat with every error. A script that reads check output line by line must accept the header lines. How it works explains the groups (#126).
  • Test failures that share their message's first line print under one header: N failure(s) with the same first message line: ..., with the first line cut at 160 characters in the header only. Members keep their full FAILED detail, and past 10 failures in detail the rest are names under also failed (N):. last-test-results.txt stays flat and full. Commands shows the form (#126).
  • On the command line, when the last run recorded 1 to 100 failures inside a VSTest method selection, those tests run first as their own stage, and their failures print before the rest runs; the final summary counts each test once. Platform runs, whole-project runs, selections with no recorded failure, and projects whose recorded failure is a theory row run unchanged in one stage. The MCP answer arrives once with the full text. How it works explains the stages (#115).
  • A stop answer for a session checks only its own files and what they reach: it binds the files the session wrote alone or together with another session, and files no session wrote, then attributes as before. N error(s) from other sessions' edits left out now counts only in-reach errors from other sessions. fuse check, the MCP check, and a stop whose harness names no session are unchanged. How it works and Subagents and parallel agents explain the scope (#104).
  • When a check binds whole projects, the summary names the projects and the changed files that forced it: checked whole projects: Lib because Lib/Calc.cs (removed: ...); App because ..., at most 3 projects and 2 files per project, sorted, with ; and N more in the engine log past that. The check: line in engine.log holds the full list after whole projects:. The summary names a dependent that owns no candidate with its forcing files and no per-cause lines. Commands shows the form (#128).
  • An edit whose declarations compile to the same code as HEAD's selects no tests: a local rename or var against the explicit type seeds nothing. Anything Fuse cannot read counts as changed. When every changed declaration compiled to the same code, fuse test runs nothing and prints fuse: no test is affected by the changes (out of T); the changes compile to the same code as HEAD; fuse test --all runs everything. Partial drops are engine-log only. How it works explains the comparison (#109).
  • Member-level selection now applies when at most 100 test classes are reachable, up from 40. Each plan logs its walk statistics and the level it selected. How it works explains the walks (#80).
  • A run without MSBuild emits a dependent again only when a project it depends on changed its declarations; otherwise the copy keeps its image. engine.log names each skipped dependent. How it works explains the runs (#74).
  • The first fuse check after an engine restart reuses HEAD's finished baseline results from the state directory instead of binding HEAD again, keyed by the commit and the inputs the result depends on. There is no output change. engine.log gains baseline: <n> stored result(s) read for HEAD <12 hex>; <m> computed per check that reads the store. How it works explains the store (#96).
  • After HEAD moves, the engine warms the baseline compilation-wide analyzer results in the background between requests. There is no output change. engine.log gains baseline warm: <project> compilation-wide analyzers done in <ms> ms and baseline warm: skipped, HEAD moved again. How it works explains the warming (#99).
  • The background load of dependents also builds their compilations, so the next check reuses them. There is no output change. engine.log gains preloaded <project> compilation in <ms> ms per project. How it works explains the preload (#67).
  • fuse build and fuse check summaries end with ; tree <12 hex> over N changed file(s), naming the tree the command ended on; last-check-results.txt and last-build-results.txt headers carry the same stamp. Hook and MCP answers carry no stamp. Commands shows the stamp.
  • On large uncommitted trees Fuse bounds 2 costs. Past 500 changed files a check skips hashing for a kept answer and answers fresh. Past 2000 touched paths the next sync re-evaluates the projects and resets the set. The check: line in engine.log gains per-session file counts. Limits covers the bounds, and Troubleshooting the log lines.
  • fuse init prints the version that registered the hooks: fuse: hooks registered by Fuse <version>; ..., or fuse: MCP server registered in .vscode/mcp.json by Fuse <version>; .... When you rerun it after an upgrade, it prints the new version even when every file is unchanged. The --instructions section gains the container pre-flight bullet and the C# scope bullet. Run fuse init --instructions again to get them. Connect your agent shows the section.

Fixed

  • Before the hook returns a background post-edit answer with errors, a second check against the current tree confirms it. When the tree no longer reports the errors, the hook exits 0 silent instead of delivering an already-fixed error. The hook logs deliveries and drops in hook.log. The hook wait now covers at most 2 checks: the first answer plus one confirmation. How it works explains the confirmation.
  • When a reached project is missing from the engine's views after one recovery rebuild, the check ends unanswered with fuse: could not load <project>: the check reached <name> but the engine's view does not hold it (the projects the view holds are named in engine.log) and exit 2, instead of answering without that project's errors. Hooks stay silent on it. engine.log gains a check coverage: line naming which reached projects each view held. Troubleshooting explains the line (#82).
  • A scoped check refuses a file spec that is not a C# source of a project, even when mixed with checkable specs, with "<spec>" in the check matches no changed C# source file of a project in this repository. Without the refusal the mixed case would silently check only the other specs. Commands and Messages cover the refusal.
  • When fuse test passes the command through to dotnet test, a positional directory stays positional on VSTest, which refuses --project. Only on Microsoft.Testing.Platform does Fuse spell a first argument naming a project, solution or directory as --project or --solution. In 5.6.0 the spelling applied on VSTest too. Commands describes when arguments pass through (#122).
  • For a Microsoft.Testing.Platform project with a .NET Framework target in a repository without the global.json opt-in, fuse test runs the project through dotnet test, which starts each target correctly. A .NET Framework target builds an assembly with no runtimeconfig.json, which dotnet exec cannot start. In 5.6.0 every target started directly, so the project produced no results. Commands describes when a run goes through dotnet test.
  • In a repository without the global.json opt-in, a Microsoft.Testing.Platform project whose built target exits without printing results now runs through dotnet test. This covers an NUnit or MSTest project that references the platform without being a test application that runs itself. In 5.6.0 such a target counted as a pass with no tests, and another project's results could hide that. When a platform project goes through dotnet test after Fuse built it, dotnet test no longer builds it again. Commands describes when a run goes through dotnet test.
  • A Microsoft.Testing.Platform project that Fuse runs through dotnet test in a repository without the global.json opt-in now gets the project positionally and reports to TRX, reading the filter from the run settings. Fuse leaves a framework's own filter arguments out, so an xUnit v3 or TUnit project runs whole. In 5.6.0 the fallback passed --project, which only the platform's dotnet test accepts, so VSTest's refused it and the project produced no results. Commands describes when a run goes through dotnet test.

Documentation

  • Commands documents every new flag, command and output form. How it works explains grouping, container gating, the stop scope and same-code selection. Limits covers the new bounds and the files a check does not see. Troubleshooting adds the new engine-log lines, the locked-file holder and the missing container runtime. Messages covers the new refusals. Evals documents the scale and stale suites, the failed rounds and the new result fields. Connect your agent and Subagents and parallel agents cover the refreshed instructions and external writers.
  • The evals measure Polly in place of the .NET Community Toolkit: a layered library whose 6 xUnit v3 test projects run on Microsoft.Testing.Platform. Its first results ship with this release, and Benchmarks quotes them. Evals lists the pinned repositories.