Skip to content

fix(discover): rewrite dotnet restore, not just build - #2142

Merged
KuSh merged 5 commits into
rtk-ai:developfrom
maxmilian:fix/discover-dotnet-rewrite-subcommands
Oct 20, 2026
Merged

KuSh merged 5 commits into
rtk-ai:developfrom
maxmilian:fix/discover-dotnet-rewrite-subcommands

Conversation

@maxmilian

@maxmilian maxmilian commented May 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Root cause

The dotnet rewrite rule in src/discover/rules.rs used pattern: r"^dotnet\s+build\b", covering only build, while DotnetCommands::Restore already dispatches to a real handler.

Fix

Narrow change to the rule: ^dotnet\s+(build|restore)\b.

Tests

  • test_rewrite_dotnet_subcommands: build and restore rewrite to rtk dotnet <sub> (trailing args kept); dotnet test and dotnet format rewrite to None; dotnet publish / dotnet run / dotnet builder are left alone. Re-adding test or format to the alternation turns it red (checked both).
  • On the merge with develop 7bff768c: cargo test discover 683 passed, cargo fmt --check clean. cargo clippy --all-targets -- -D warnings is clean on the touched files; locally it stops on a duplicated attribute in src/llm_proxy.rs, which this PR does not touch (develop as-is).

Manual verification

dotnet build            -> rtk dotnet build
dotnet restore          -> rtk dotnet restore
dotnet restore --force  -> rtk dotnet restore --force
dotnet test             -> (not rewritten)
dotnet format           -> (not rewritten)
dotnet publish          -> (not rewritten)
dotnet builder          -> (not rewritten)

Docs

Added a dotnet restore row to the .NET table in docs/guide/resources/what-rtk-covers.md (develop has since dropped the percentage column, so the row matches the new two-column format).

@maxmilian
maxmilian force-pushed the fix/discover-dotnet-rewrite-subcommands branch from b67f390 to c702065 Compare May 28, 2026 15:47
@maxmilian

Copy link
Copy Markdown
Contributor Author

Ran a fresh-context independent review (skeptical, diff + issue only). Verdict: no blockers. Two points addressed / noted:

  • Hardened the test (pushed): added a trailing-args case (dotnet test --filter Category=Unit → preserved) and a word-boundary negative (dotnet builder → not rewritten), confirming \b stops at the subcommand.
  • Kept the capturing group (build|test|restore|format) to stay consistent with the other multi-subcommand rules in rules.rs (git/gh/cargo/ruff/go), which capture for subcmd_savings lookup — and it leaves room for the follow-up below.

Follow-up (intentionally out of scope here): the rule's flat savings_pct: 70.0 now applies to all four subcommands. dotnet test likely compresses closer to ~90% (cf. cargo test/go test), so rtk discover will slightly undercount its savings. I left this out of a pure routing fix because I don't have reliable compression figures for restore/format and didn't want to guess. Happy to file a separate PR adding subcmd_savings overrides if maintainers want the report accuracy.

Comment thread src/discover/registry.rs Resolved
@maxmilian

Copy link
Copy Markdown
Contributor Author

Friendly ping on this one — #1830 is still open and picked up a +1 from a heavy user (reported dotnet test running 1208× over 30 days at ~0% compression), and the PR already has an approval. Mergeable. Any chance of a review slot?

`rtk dotnet test`, `rtk dotnet restore`, and `rtk dotnet format` proxies
already exist and route to dedicated handlers, but the rewrite rule only
matched `dotnet build`, so the Claude Code hook silently passed the other
three through unfiltered. Extend the rule's subcommand set; the output
filters already handle all four — this is purely a routing fix.

Fixes rtk-ai#1830
…t comment

Addresses a non-blocking review nitpick: the "(issue rtk-ai#1830 - only build was
covered before)" parenthetical is history the comment does not need. Keep the
part that explains why all four subcommands must route, drop the rest.
@maxmilian
maxmilian force-pushed the fix/discover-dotnet-rewrite-subcommands branch from 24ac995 to e3a36cd Compare August 30, 2026 02:13
@maxmilian

Copy link
Copy Markdown
Contributor Author

@KuSh since you've been folding the duplicates (#1207, #3654, #3300) into #1830 — this PR is the fix for it. It's a one-line change to the dotnet rule in src/discover/rules.rs (build → build|test|restore|format; all four already have rtk dotnet filters) plus a registry test, and @harvzor approved it in June. I re-checked it against current develop (eb225a160): it merges cleanly, the discover tests pass, and rtk rewrite "dotnet test" / "dotnet restore" now route to rtk dotnet while dotnet builder is still left alone. @proxylat also confirmed the bug on 0.50.0 last week. Happy to rebase or reshape it if you'd prefer something different.

@KuSh KuSh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Round 1 — CHANGES REQUESTED

Claim: the dotnet rewrite rule routes dotnet test, dotnet restore and dotnet format to their existing rtk dotnet handlers, not just build.
Scope: accept if narrowed to "the dotnet rewrite rule routes dotnet restore to rtk dotnet restore" (^dotnet\s+(build|restore)\b). test and format are cut: what each handler does differs from the native command an agent types, and fixing that is handler work, not routing. Filed as #4602 (format) and #4603 (test); the MTP part is #1289, evidence added.
Ran: native dotnet against rtk rewrite + the rewritten command, .NET SDK 10.0.400 in Docker, develop f16beca vs this PR merged onto it: 16 test rows (xunit VSTest: fail, pass via --filter, --logger console, --list-tests, -t, --no-build -v q, -v n, --collect, --blame, user --logger trx with and without --results-directory, a compile error after a green run; MSTest on MTP via global.json, with and without the TRX extension: run from the project and with --project, --list-tests), 13 restore rows (ok, explicit project, path target, --force, NU1903 warning, NU1101 failure, no project, bad --source, -v n, /v:n, user -bl:, --help, restore-x), 4 format rows, 36 rewrite spellings (pipes, chains, env/timeout prefixes, builder/testhost/test-x/format.sh boundaries); invariants: exit codes, files written and deleted, under the hook, every decision; restore savings 23–33% on small successful runs, 97% at -v n, failures passed through whole (20% floor, CONTRIBUTING.md)
Pins: 4 decisions (test, restore, format arms, \b on them), 4 mutated, 0 survived — test_rewrite_dotnet_subcommands kills each
Matrix: never — ran this round; pin check: never — ran this round
CI @e3a36cdc0: no run on this head (the fork workflow waited for approval and expired); I will approve the run on your next push. Locally on the merge with develop f16beca: fmt, clippy and 4955 tests green.

Blocks merge (3, frozen at round 1) — all three close by the narrowing above

  1. src/discover/rules.rs:698 — dotnet format becomes a check. rtk dotnet format adds --verify-no-changes unless rtk's own --write is passed. Evidence: on a file with whitespace violations, native dotnet format and dotnet format whitespace exit 0 and reformat the file; through the rewrite both exit 2 and the file is unchanged. The output ends with Run `dotnet format` to apply fixes, and under the hook that hint runs the check again. #4602.
  2. src/discover/rules.rs:698 — rtk's injected TRX reporting breaks MTP runs and --list-tests. Evidence: MSTest on MTP referencing only MSTest.TestAdapter + MSTest.TestFramework: native dotnet test passes, exit 0; through the rewrite exit 5, Unknown option '--report-trx', Zero tests ran. xunit --list-tests / -t: native prints both test names, exit 0; through the rewrite: ok dotnet test: completed (binlog-only mode, counts unavailable, 0 warnings) (unknown), exit 0. MSTest on MTP: native exit 0, Discovered 2 tests; through the rewrite exit 5 ('--report-trx' cannot be enabled when using '--list-tests'), Discovered 0 tests, and 4.6 KB of option help. #1289 (MTP without the extension), #4603 (--list-tests).
  3. src/discover/rules.rs:698 — test artifacts are deleted. rtk adds --results-directory <temp> and deletes that directory afterwards. Evidence: --collect "XPlat Code Coverage": native writes TestResults/<guid>/coverage.cobertura.xml and prints its path under Attachments:; through the rewrite no coverage file is left and the Attachments: line is gone. Same for --logger "trx;LogFileName=r.trx": native keeps TestResults/r.trx, through the rewrite it is gone. Every failing xunit run through the rewrite also cites a Results File: under that deleted directory. #4603.

After narrowing, the test should also say what was cut: dotnet test and dotnet format rewrite to None. Re-adding test to the alternation has to turn it red.

Optional — will not hold merge

  • docs/guide/resources/what-rtk-covers.md has a .NET table with build, test and format; a dotnet restore row would match what the rule now routes.

Filed as follow-ups

  • #4602 rtk dotnet format checks by default, so a rewritten dotnet format stops formatting — cut by the narrowed claim; filed
  • #4603 rtk dotnet test loses --list-tests output and deletes the test artifacts it redirects — cut by the narrowed claim; filed
  • #1289 rtk dotnet test fails on repositories that use the new testing infrastructure — cut by the narrowed claim; absorbed by existing #1289, comment added with the .NET 10 rows
  • #1830 stays open for test and format until those land.

Checked and correct — no need to re-verify

  • dotnet restore through the rewrite: exit code equal to native on all 13 rows; NU1101 and MSB1003 errors and the NU1903 warning kept; a user -bl:user.binlog is written where asked and rtk adds no second one; --help forwarded unchanged; no temp binlog left in /tmp.
  • dotnet restore-x, dotnet test-x and dotnet format.sh do rewrite (the \b boundary admits - and ., as for build on develop), but rtk passes them through to dotnet: output and exit code are identical to native.
  • dotnet builder, dotnet testhost, dotnet tests, dotnet publish, dotnet run, dotnet --info, sudo dotnet …, dotnet restore > log.txt are left alone, as on develop.
  • dotnet is already in SUBCOMMAND_ROUTERS, so the tracking label keeps the subcommand.
  • The thread on the historical aside: fixed in e3a36cd; resolving it.

Your questions

  • "Happy to file a separate PR adding subcmd_savings overrides" → drop for now. With test and format cut, only restore is new, and it measures 23% on a two-line success up to 97% at -v n; the 70% default is inside that range.
  • "Happy to rebase or reshape it if you'd prefer something different" → yes, the narrowing above. No rebase needed: it merges cleanly onto develop f16beca and the suite passes there.

Next

Narrow the pattern to ^dotnet\s+(build|restore)\b and turn the test/format rows of test_rewrite_dotnet_subcommands into negative assertions. After that push and a green CI run, this merges.
Rounds: 1. Threads: 0 open, 1 resolved this round.

Comment thread src/discover/rules.rs Resolved
Comment thread src/discover/rules.rs Resolved
Comment thread src/discover/rules.rs Resolved
`rtk dotnet test` and `rtk dotnet format` change what the native command
does: format turns into a --verify-no-changes check, and test injects TRX
reporting into a temp results directory it deletes afterwards (breaking
MTP runs, --list-tests, and coverage/trx artifacts). Narrow the rule to
`build|restore` until rtk-ai#4602 and rtk-ai#4603 land, and assert that `dotnet test`
and `dotnet format` are not rewritten.

Also list `dotnet restore` in the .NET table of what-rtk-covers.md.
@maxmilian maxmilian changed the title fix(discover): rewrite dotnet test/restore/format, not just build fix(discover): rewrite dotnet restore, not just build Oct 17, 2026
…net-rewrite-subcommands

# Conflicts:
#	docs/guide/resources/what-rtk-covers.md
@maxmilian

Copy link
Copy Markdown
Contributor Author

Thanks @KuSh, that's a thorough round, and the format/test evidence makes the cut clear. Narrowed as asked:

develop had moved since your round (the docs table lost its percentage column), so I merged 7bff768c in and resolved that one row; no other conflicts. cargo test discover passes on the merge (683). Head is dfae8264, ready for the CI run whenever you can approve it.

@KuSh KuSh self-assigned this Oct 20, 2026
The page lists what the hook intercepts. `cargo nextest`, `dotnet test`,
`dotnet format` and `docker compose up` were listed, yet `rtk rewrite`
leaves all four alone. `cargo nextest` and `docker compose up` have no
rule yet (rtk-ai#2046, rtk-ai#1727); `dotnet test` and `dotnet format` stay out of
the `dotnet` rule until their handlers match the native commands
(rtk-ai#4603 and rtk-ai#1289, rtk-ai#4602).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@KuSh KuSh left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Round 2 — APPROVED

Claim: the dotnet rewrite rule routes dotnet restore to rtk dotnet restore, alongside build.
Scope: accept if narrowed to "the dotnet rewrite rule routes dotnet restore to rtk dotnet restore" (round 1, frozen). Narrowed in adf52a8.
Ran: rtk rewrite over 42 spellings, develop 5538d72 against this PR merged onto it (restore with and without args, -v n, /v:n, -bl:, --help, && chains, | pipes, cd … &&, env and timeout prefixes, restore-x, restorer, sudo, > log.txt; every round-1 test and format spelling); invariants: under the hook, every decision. The 13 rtk dotnet restore rows from round 1 (exit codes equal to native, errors and warnings kept, savings 23–97% vs the 20% floor in CONTRIBUTING.md) are reused: nothing the restore path calls has changed on develop since.
Pins: 4 decisions (restore arm, \b, test left out, format left out), 4 mutated, 0 survived — test_rewrite_dotnet_subcommands kills each
Matrix: executed round 1, rewrite rows rerun this round; pin check: executed this round
CI @4416e6f35 (with the fixup): all green; @dfae82640 before it: all green. Locally on the merge with develop 5538d72: fmt, clippy and 5011 tests green.

Blocks merge (0 of 3 frozen at round 1 still open)

All three closed by the narrowing: no spelling of dotnet test or dotnet format is rewritten any more, so the agent's command runs natively.

Filed as follow-ups

  • #4602, #4603 and #1289 carry format and test (filed at round 1).
  • #1830 stays open for them. Note: commit 6396c97 still says Fixes #1830, and merge commits on develop keep it, so merging will close #1830. I will reopen it after merge; no rebase needed for that.
  • #4695 what-rtk-covers.md does not match what the hook rewrites, and nothing checks it — pre-existing, rest of the page beyond the four rows the fixup drops; filed
  • #3770 shadow-warning guard misses the 21 clap commands outside both reserved lists — pre-existing: a trusted user filter for dotnet test makes the hook send it to rtk dotnet test, on develop as here; absorbed by existing #3770, comment added

Checked and correct — no need to re-verify

  • dotnet restore in every spelling above rewrites to rtk dotnet restore … with the arguments kept; dotnet restore && dotnet test rewrites only the restore half; dotnet build && dotnet format only the build half.
  • dotnet restorer, dotnet builder, publish, run, --info, sudo dotnet restore and dotnet restore > log.txt are left alone, as on develop.
  • The what-rtk-covers.md row matches what rtk dotnet restore prints: the restore summary plus errors and warnings.
  • The three round-1 threads: fixed in adf52a8; resolving them.

Next

Fixup 4416e6f pushed, code-reviewed: what-rtk-covers.md no longer lists cargo nextest, dotnet test, dotnet format and docker compose up, none of which the hook rewrites (#2046, #1727; #4603 and #1289, #4602). Docs only. Approving once CI is green on it.
Rounds: 2. Threads: 0 open, 3 resolved this round.

@KuSh
KuSh merged commit 5687d0d into rtk-ai:develop Oct 20, 2026
14 checks passed
@rtk-release-bot rtk-release-bot Bot mentioned this pull request Oct 20, 2026
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