Description
Separate defect from the CAOT-0002 identity collision, and fixing identity does not fix this. Source.RunOnce walks every file in one call and appends every new record from every changed file into one slice before returning (internal/source/source.go:278 and :321), and cmd/codingagent2otel/main.go calls it unchunked. On a first sweep every file starts at offset 0, so tailCompleteLines reads each file whole and copies a []byte per line. Against the live tree that reached a 23.7 GiB peak and the run had to be stopped.
Nothing in internal/source or internal/config expresses a record, byte or batch bound. The wave-1 resume boundary said to re-run the sweep ‘with a bounded memory ceiling’ as though one existed; it does not, and must be built.
Acceptance Criteria
- #1 A full sweep across every namespace completes below a named memory ceiling, measured from the running process rather than asserted
- #2 RunOnce no longer accumulates every changed file’s records into one unbounded slice before returning
- #3 The bound is configuration with a documented default in config.example.yaml, not a constant inside the walker
- #4 A bounded batch that stops early leaves the checkpoint at the last fully exported record, and a restart resumes exactly there with no gap and no repeat
- #5 A test over a synthesised corpus larger than the batch bound proves every record is emitted exactly once across the batches
Definition of Done
- #1 just check passes: fmt-check, lint, build, test-short, probe-ci, dashboard-check and docs-links all clean