fix(#696): git-delta scoping + file manifest for validation evidence#697
Conversation
…ll worktree Validation was loading the entire merged codebase (47+ files, 211k tokens) for each agent completion check. As parallel agents merged their work the token cost grew unboundedly, eventually exceeding the model context limit and blocking agent completions. Fix: at task assignment time, snapshot `git rev-parse HEAD` into `TaskAssignment.baseline_commit`. At validation time, `WorkAnalyzer` runs `git diff <baseline>..HEAD --name-only` in the agent's worktree to get only the files that agent changed, then passes them as an allowlist to `_discover_source_files`. Falls back to the full-scan path when git is unavailable or the baseline is missing. Measured reduction: 122k tokens → ~3k tokens per validation call (~25×). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
|
Claude finished @lwgray's task —— View job PR Review: fix(#696): scope validation evidence to agent git deltaThis PR effectively addresses a critical performance issue where validation was loading entire merged codebases instead of just the files changed by individual agents. Here's my detailed review: ✅ Code Quality & Best PracticesExcellent adherence to coding standards:
Well-structured implementation:
✅ Potential Bugs & IssuesRobust error handling throughout:
Edge cases well-covered:
✅ Performance ConsiderationsSignificant performance improvement:
Efficient implementation:
✅ Security ConsiderationsSecure subprocess usage: # Good: Fixed command arguments, no shell injection risk
subprocess.run(["git", "rev-parse", "HEAD"], ...)
subprocess.run(["git", "diff", f"{baseline}..HEAD", "--name-only"], ...)Proper path handling:
Safe fallback behavior:
✅ Test CoverageComprehensive test suite (208 lines added): Core functionality tests:
Edge case coverage:
Integration coverage:
Missing test considerations:
🎯 Architecture & DesignExcellent design decisions:
Smart implementation details:
📝 Minor Suggestions
🎉 SummaryThis is a high-quality, production-ready fix that directly addresses the core issue: Problem: Token explosion in parallel agent validation (122K+ tokens → model failures) The implementation is secure, well-tested, and maintains backward compatibility. The fallback behavior ensures system reliability even when git operations fail. Recommendation: ✅ Approve and merge |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3794d9bd42
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| f"Git delta for agent {agent_id}: {len(files)} files changed " | ||
| f"since {baseline_commit[:8]}" | ||
| ) | ||
| return files if files else None |
There was a problem hiding this comment.
Preserve successful empty git deltas
When git diff succeeds but reports no changed files (for example, the agent has no committed source changes), this converts the empty delta to None, which gather_evidence treats as “fall back to full worktree scan.” That makes validation inspect unrelated files from the merged worktree instead of producing the existing no-source-files failure for this agent, defeating the new per-agent scoping and potentially accepting an empty completion based on other work. Return the empty list for a successful empty delta so _discover_source_files(..., allowed_files=[]) yields no evidence.
Useful? React with 👍 / 👎.
| abs_p = project_path / rel | ||
| if abs_p.exists(): | ||
| delta_pairs.append((abs_p, abs_p)) |
There was a problem hiding this comment.
Resolve delta paths before reading
In git-delta mode the path from git diff --name-only is joined to project_path and later passed to stat()/read_text() without the resolve-and-is_relative_to guard used by the full scan. If a changed file is a source-named symlink such as leak.py pointing outside the repo, validation follows it and sends external file content to the LLM prompt. Resolve each delta path and skip anything outside project_path before reading it.
Useful? React with 👍 / 👎.
…ng-file reports The git-delta approach (scoped source file content) caused the LLM to report packaging files like pyproject.toml as missing because .toml is excluded from SOURCE_EXTENSIONS. The files existed but were invisible. Fix: collect a full file manifest (names only, no content reads) from the agent's worktree via os.walk and inject it into the validation prompt before the source file content. The LLM can now verify file existence from the manifest even when a file's extension is excluded from the content scan. The prompt instructs the LLM: files in the manifest exist; only report a file as missing if it appears in neither the manifest nor the source files section. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
|
Claude finished @lwgray's task —— View job PR Review: fix(#696): scope validation evidence to agent git deltaReview Tasks:
This PR effectively addresses a critical performance issue where validation was loading entire merged codebases instead of just the files changed by individual agents. Here's my detailed review: ✅ Code Quality & Best PracticesExcellent adherence to coding standards:
Well-structured implementation:
|
…nk guard Two P2 review findings on PR #697's validation git-delta scoping: - _get_git_delta_files: a successful-but-empty git diff now returns [] instead of None, so an agent that committed nothing surfaces the "no source files" failure instead of falling back to a full merged- worktree scan (the exact #696 mis-scoping this PR removes). - _discover_source_files: resolve each delta path and skip anything outside project_root, preventing a source-named symlink (leak.py -> external secret) from leaking external file content into the prompt. Adds 4 regression tests. Full work_analyzer module (54) + mypy + pre-commit clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
What is this fixing?
Marcus is a multi-agent software development system where AI agents work in parallel, each coding a task and submitting it for validation. Validation checks whether the agent's code satisfies acceptance criteria by loading code files and sending them to an AI model for review.
This PR fixes a critical bug where the validator loaded the entire merged codebase (all files from all agents) instead of only the files the current agent changed. Unchecked, this caused token counts to explode, exceeding model context limits and blocking agents from completing tasks.
Why (User-Visible Problem)
In a recent run, agent `1_25` finished a task. By the time validation ran, 5 other agents had merged their work. The validator loaded all 47 files — 211,000 tokens — and hit the model's token limit. The agent was blocked. The task stayed stuck in `IN_PROGRESS` forever.
Across the last 5 projects, `validate_work` cost $0.97 — more than the planning cost for some projects. The largest single call was 122,985 input tokens to check one agent's 2-file change.
What Changed (Two-Part Fix)
Part 1 — Git-delta scoping (token explosion fix)
`src/core/models.py`
`src/marcus_mcp/tools/task.py`
`src/ai/validation/work_analyzer.py`
Part 2 — File manifest (false "missing file" fix)
The delta approach exposed a second problem: files like `pyproject.toml` and `Makefile` are excluded from `SOURCE_EXTENSIONS` (only `.py`, `.js` etc. are read for content). With only 3 stub `.py` files in the prompt, the LLM correctly reported "pyproject.toml is missing" — but the citation verifier requires `file:line` citations and dropped the report. Validation incorrectly passed.
Fix: collect a full file manifest (filenames only, zero content reads) from the worktree and inject it into the validation prompt:
The LLM can now verify existence of `pyproject.toml` from the manifest even though its content is not loaded. It only flags a file as missing if it appears in neither the manifest nor the source files section.
`src/ai/validation/validation_models.py`
`src/ai/validation/work_analyzer.py`
Fallback behaviour is fully preserved: if git fails, if no baseline exists, or if `allowed_files` is `None`, the original full-worktree scan runs unchanged.
Token Impact
Test Plan
pytest tests/unit/ai/validation/test_work_analyzer.py::TestGitDeltaEvidence— 7 tests: delta scoping, fallback on missing baseline, fallback on git failure, allowed_files allowlist, empty allowlist, missing-file tolerancepytest tests/unit/ai/validation/test_work_analyzer.py::TestFileManifest— 5 tests: manifest includes all extensions (.toml, Makefile, .yml), excludes EXCLUDE_DIRS, populates WorkEvidence, prompt contains manifest section, manifest appears before source file contentpytest -m unit— 2325 passed, 0 failures, no regressionsmypy src/ai/validation/work_analyzer.py src/ai/validation/validation_models.py src/marcus_mcp/tools/task.py src/core/models.py— cleanRelated
df7d0aea🤖 Generated with Claude Code