Repository navigation
fix(runtime): accept the logical node directory generated tests are mandated to use - #362
Merged
Merged
Conversation
…andated to use `strategy_attempt_test_dir` (`packages/prompts/src/render.ts:763`) renders `<workspace>/test/foundry/<LOGICAL node id>/` and every strategy prompt tells the agent to keep its generated test there. `materializeGeneratedTestCompanion` searched `test[s]/foundry/<CONCRETE node id>/` instead, so on any node the topology expands the one directory the prompt named was never visited and an obedient agent's test failed the contract as `generated test file is missing`. The production topology expands every `strategies` node three ways (group `loops: 3`), giving concrete ids like `externalized-state-accounting-0`; 57 of the 65 nodes that declare `ultrafuzz/generated-tests@1` are affected. The retry reset one screen above already keyed on the logical id, so the workflow cleared one directory and read from another. Both ids are now accepted, deduplicated, logical first. The retry reset clears every accepted directory, or the previous attempt's sources would survive in whichever one it skipped and be republished as this attempt's work. Scope note: the smoke topology pins `strategy_loops: 1`, so its concrete and logical ids coincide and this does NOT explain the two Foundry-only smoke failures on #348; that residual is analysed in a comment on the issue. Refs #348, #327. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
3 tasks
aviggiano
pushed a commit
that referenced
this pull request
Aug 7, 2026
Brings B1 (#363 threat-model artifact retention) and B2 (#365 expansion observability) onto the release branch, plus #362 and the rest of main. workflow-sync.ts: kept #188's accumulating findingsCount AND #350's refreshVerifiedArtifactDigest re-seal — orthogonal, and dropping the latter would have silently reverted the #348 fix on this branch. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
Relates to #348 and #327. This fixes a real defect in the code path #348 points at, and it does NOT explain the two Foundry-only smoke failures. Both claims are load-bearing; the second is stated in the commit message too so it cannot be lost.
The defect
strategy_attempt_test_dir(packages/prompts/src/render.ts:763) rendersand every strategy prompt instructs the agent to keep its generated test there.
materializeGeneratedTestCompanion(workflow.tsx) searchedconcreteNodeIdisattempt.attemptId, which equals the logical id only when the topology does not expand the node. The production topology'sstrategiesgroup carriesloops: 3, soconcreteIdsForyieldsexternalized-state-accounting-0/-1/-2. On those nodes the one directory the prompt named was never searched,existingCandidateswas empty, and the companion failed closed withartifact-contract failure: generated test file is missing ….The workflow already disagreed with itself:
resetTaskArtifactsForRetryclearstest/foundry/<logicalNodeId>. It cleared one directory and read from another.Measured on the expanded topologies (
expandTopology): 65 nodes declareultrafuzz/generated-tests@1in production; 57 of them have a concrete id that differs from their logical id. In the smoke topology (strategy_loops: 1) all 4 coincide.The fix
generatedTestNodeIds(task)returns[logicalNodeId, concreteNodeId]deduplicated, logical first. The candidate list maps over it (also deduplicated, so aloops: 1node does not gain a redundant candidate and cannot trip the existinggenerated test sources conflictcheck against itself). The retry reset iterates the same list, because clearing only one accepted directory would let the previous attempt's source survive in the other and be republished as this attempt's work.Contract behaviour is otherwise unchanged: a test that reached none of the accepted directories still fails closed, and the byte-identity, symlink, hard-link and copy-mismatch guards are untouched.
Verified by execution
pnpm -r build→ 0pnpm -r test→ 0pnpm -w format:check→ 0pnpm -w lint→ 0git checkout origin/main -- packages/runtime/src/templates/smithers/workflows/workflow.tsx, the new behavioural test fails withartifact-contract failure: generated test file is missing generated-tests/Esa.t.sol; restored, it passes.smithers-orchestratorresolved) end to end throughprepareArtifactMirror→materializeGeneratedTestCompanions→verifyArtifactsin a temporary run root. Onorigin/maina node withconcrete=externalized-state-accounting-0andlogical=externalized-state-accountingfails;concrete=logicalpasses. After the fix both pass. That harness was scratch and is not part of this PR; the committed regression uses the repo's existingnew Functionextraction pattern.expandTopologyon both manifests.Inferred, not executed
.t.sol.strategy_attempt_test_dirversus elsewhere. The fix removes a defect that punished agents that did obey; it cannot help one that wrote somewhere else entirely.Tests changed, and why
generated-workflow-verifier.test.ts— two new behavioural tests (mandated logical directory accepted; a test in the conventionaltest/root still rejected) and one new source-shape test pinning the retry reset togeneratedTestNodeIds. The pre-existing source-text assertions for the candidate list and the reset were updated to the new shape.invariant-suite-handoff-durability.test.ts—#212asserted exactly one reset root. Its fixture hasattemptId: "handlers"andlogicalNodeId: "stateful-invariant-handlers", so it now expects both, in the repository's own pluraltests/root, preserving that test's original point.runtime.test.ts— the compiled-source assertions on the emitted workflow.Not addressed
The two Foundry-only smoke failures (
externalized-state-accounting,lifecycle-view-boundaries) are not this. Their lane pinsstrategy_loops: 1. My reproduction of the smoke shape found several distinct ways the companion path fails, all data-dependent on what the agent wrote, all indistinguishable from the published bundle — which carries no message field by design. The full analysis, including what I ruled out and what evidence would settle it, is a comment on #348.🤖 Generated with Claude Code
Greptile Summary
This PR aligns generated-test discovery and retry cleanup with the logical node directory mandated by strategy prompts while retaining compatibility with concrete node directories.
Confidence Score: 5/5
The PR appears safe to merge, with generated-test lookup and retry cleanup consistently covering the prompt-mandated logical directory and the compatible concrete directory.
The shared deduplicated ID helper closes the expanded-topology lookup defect while preserving path containment, byte-identity conflict handling, and fail-closed behavior for missing tests.
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Strategy prompt] --> B[Agent writes generated test] B --> C["test[s]/foundry/logicalNodeId"] B -. backward-compatible path .-> D["test[s]/foundry/concreteNodeId"] C --> E[Generated-test companion lookup] D --> E E --> F{Multiple sources?} F -- No --> G[Validate and publish artifact] F -- Yes, identical --> G F -- Yes, different --> H[Fail artifact contract] I[Retry] --> J[Deduplicated logical and concrete IDs] J --> K[Clear every accepted node directory]Reviews (1): Last reviewed commit: "fix(runtime): accept the logical node di..." | Re-trigger Greptile
Context used: