[rush-daemon] Invalidate warm operations whose declared outputs were deleted or changed - #6069
Open
Sean Larkin (TheLarkInn) wants to merge 4 commits into
Open
Sean Larkin (TheLarkInn) wants to merge 4 commits into
Sean Larkin (TheLarkInn) wants to merge 4 commits into
Conversation
…deleted or changed Fixes #6058 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…skip detection Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
A cleanup failure can permanently discard fingerprint state before the operation is invalidated.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
What changed in this PR
Adds output-folder fingerprinting so warm rushd builds invalidate operations whose declared outputs changed or disappeared.
Changes:
- Tracks output-folder identity and modification time.
- Invalidates and reruns/restores affected operations.
- Adds integration tests, documentation, and change metadata.
| File | Description |
|---|---|
libraries/rush-daemon/src/OperationOutputFingerprints.ts |
Implements output fingerprint tracking and legacy-state cleanup. |
libraries/rush-daemon/src/ProductionDaemonRequestResolver.ts |
Incorporates output changes into invalidation mapping. |
libraries/rush-daemon/src/test/ProductionDaemonRequestResolver.test.ts |
Tests cache and no-cache restoration behavior. |
libraries/rush-daemon/README.md |
Documents output invalidation behavior and limitations. |
common/changes/@rushstack/rush-daemon/output-invalidation_2026-09-23.json |
Records the patch change. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
…eeds Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Mo Jazayeri (mojaza)
approved these changes
Sep 24, 2026
…output-invalidation # Conflicts: # libraries/rush-daemon/src/ProductionDaemonRequestResolver.ts
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Summary
A warm
rushdgraph decided "up to date" by comparing input state hashes only. Afterrm -rf <project>/lib,git clean -xdforheft clean, the nextrush-client build(even--to <project>) exited 0 with 0 operations and left the outputs missing. Nativerush buildwith the build cache restores them.Root cause
Build outputs are git-ignored, so they are not part of any operation state hash. The warm skip in
PhasedOperationPlugin(shouldEnableOperation) compares a retained successful record's hashes.WorkspaceEngineComponentFactoryonly invalidates the operations thatProductionDaemonRequestResolver.getChangedOperationsmaps, and that function compares own-state hashes. Nothing noticed that outputs had disappeared.Fix
OperationOutputFingerprints(rush-daemon):SuccessorFromCacheresult, it records a cheap fingerprint of the operation's declaredoutputFolderNames: onestatper folder, capturing existence, inode and mtime.ProductionDaemonRequestResolver's invalidation mapper now returns the hash-changed operations plus the retained operations whose output fingerprint is missing or changed.SKIPPEDwhile its outputs are still gone. The tracker therefore removes that operation'spackage-deps_<id>.jsonlegacy skip record, which forces execution. The legacy skip plugin deletes the same record before it executes an operation.What the fingerprint detects: deletion or recreation of an output folder, and adding, removing or renaming its direct children (this covers
rm -rf lib,rm -rf lib/*,git clean,heft cleanand new emitted files). It does not detect in-place edits of nested output files. Operations withoutoutputFolderNamesare not covered, which matches the build cache.Tests
New tests in
ProductionDaemonRequestResolver.test.ts, against the real native engine:rm -rf a/libfollowed by--only c, which is still not scheduled. Then--to bre-executes onlyaand restoresa/lib;bdoes not run. A stray file added toc/libre-runs onlyc. A final no-op build is not scheduled, and the graph identity is unchanged.rm -rf a/lib→--to breports exactly one non-skipped result,a (compile)FROM CACHE. No script executions,libis restored, and the next build is not scheduled.Linux validation (WSL Ubuntu-24.04)
rush build --to @rushstack/rush-daemon && rush test --only @rushstack/rush-daemonpassed.heft testreports 365 passed, 0 failed (366 total). The targetedProductionDaemonRequestResolversuite has 31/31 passing.mkws-synth --projects 12workspaces (build cache on), onelabinvocation, script$LAB/fixes/output-invalidation-repro.sh. "Before" is the unfixed toolchainrush-client; "after" isapps/rush-cli-client/bin/rush-clientfrom this branch.rm -rf packages/p03/lib→buildbuild --to p03againecho stray > p05/lib/stray.txt→buildbuildKnown unrelated CI failures
The Ubuntu jobs currently fail in
PhasedRequestBatching.testandDaemonRequestWirePhased.testwithThe summary cannot be prepared until after close() is called(fromPhasedRequestSummary.ts).mainfails the same way since #6068; the fix is in #6095. Once #6095 merges, this branch will be updated frommainand CI re-run.Optional follow-ups
Fixes #6058
This came out of the automated rushd Linux performance and behavior analysis ("Rushd Hive", board #103/#117; prototype by agent A01).