Summary
depsanalysis.RunAgentPass has two callers, and the chunk / scope-edges / fail-atomically / dedupe loop around it is now duplicated between them:
cmd/itervox/deps_analyzer_service.go — the daemon's async POST /api/v1/deps/analyze path
cmd/itervox/init_deps_analysis.go — the one-shot itervox init / itervox deps analyze path
Why this is worth tracking rather than shrugging at
This exact duplication already caused a bug. When chunking was added (#43), only the daemon path got it. The CLI path kept sending the entire backlog and the entire tracker-edge list in one unbounded turn — the headline defect the work existed to fix — and it survived a full task-level review because nothing connected the two call sites. It was caught only by a cross-cutting review that went looking for other callers.
The two copies have already drifted, though so far only in observability:
|
daemon path |
CLI path |
clamp / ChunkIssues / ScopeTrackerEdges / ctx.Err() gate / fail-atomically / DedupeInferredEdges |
✅ |
✅ identical |
LogDir |
agentLogDir/deps-analyzer |
"" |
| per-chunk failure log |
WARN with profile + chunk + total |
none |
| run-start log (issues / edges / chunks) |
present |
absent |
| blind-spot logger |
s.logger (component=deps_analyzer) |
slog.Default() (no component) |
| empty backlog |
implicit (ChunkIssues → nil → empty sidecar) |
explicit early return |
The semantic core is in sync. The instrumentation is not, which means a CLI-path chunk failure is materially harder to diagnose than a daemon-path one.
Current mitigation
Both files now carry a bidirectional comment naming the other by path and stating they must stay in sync — added specifically because the original follow-up note lived in a git-ignored scratch directory and would have disappeared at merge.
That is a speed bump, not a fix.
Proposed
Extract a shared helper, roughly:
func RunChunkedAgentPass(
ctx context.Context,
input AgentPassInput, // Issues/TrackerEdges filled per chunk by the helper
issues []AnalyzerIssue,
trackerEdges []TrackerEdge,
chunkSize int,
onChunkDone func(done, total int),
) ([]InferredEdge, error)
The two sites genuinely differ — one has a JobManager and a progress callback, one has neither — which is why this was not done inline at the time. onChunkDone is the seam that absorbs that difference.
If a third caller of RunAgentPass appears before this extraction, extract first rather than adding a third copy.
Summary
depsanalysis.RunAgentPasshas two callers, and the chunk / scope-edges / fail-atomically / dedupe loop around it is now duplicated between them:cmd/itervox/deps_analyzer_service.go— the daemon's asyncPOST /api/v1/deps/analyzepathcmd/itervox/init_deps_analysis.go— the one-shotitervox init/itervox deps analyzepathWhy this is worth tracking rather than shrugging at
This exact duplication already caused a bug. When chunking was added (#43), only the daemon path got it. The CLI path kept sending the entire backlog and the entire tracker-edge list in one unbounded turn — the headline defect the work existed to fix — and it survived a full task-level review because nothing connected the two call sites. It was caught only by a cross-cutting review that went looking for other callers.
The two copies have already drifted, though so far only in observability:
ChunkIssues/ScopeTrackerEdges/ctx.Err()gate / fail-atomically /DedupeInferredEdgesLogDiragentLogDir/deps-analyzer""s.logger(component=deps_analyzer)slog.Default()(no component)ChunkIssues→ nil → empty sidecar)The semantic core is in sync. The instrumentation is not, which means a CLI-path chunk failure is materially harder to diagnose than a daemon-path one.
Current mitigation
Both files now carry a bidirectional comment naming the other by path and stating they must stay in sync — added specifically because the original follow-up note lived in a git-ignored scratch directory and would have disappeared at merge.
That is a speed bump, not a fix.
Proposed
Extract a shared helper, roughly:
The two sites genuinely differ — one has a
JobManagerand a progress callback, one has neither — which is why this was not done inline at the time.onChunkDoneis the seam that absorbs that difference.If a third caller of
RunAgentPassappears before this extraction, extract first rather than adding a third copy.