Isolate and atomically publish farm artifacts per concurrent run
Severity: high | Confidence: 0.96 | Effort: L
Where:
- plugins/ca/tools/farm.ts:1751-1765
- plugins/ca/tools/farm.ts:1885-1891
- plugins/ca/tools/farm.ts:1900-1909
- plugins/ca/tools/farm.ts:1930-1966
Evidence: Each invocation mints runId but still truncates the shared ${reportDir}/farm-results.jsonl with writeFile(resultsStream, ""), appends all runs to that same path, and directly overwrites the same farm-report.json, farm-report.md, and diffs/<task>.patch names. There is no run-scoped directory, file lock, compare-and-swap, temp-file rename, or serialization across farm processes.
Impact: Two farm invocations using the same repository can erase each other's streaming receipts and final authoritative reports. A crash during any direct report write can also leave truncated JSON/Markdown, destroying restart evidence exactly when the report is needed for recovery and audit.
Recommendation: Make runId an ownership boundary: write streams, diffs, and final reports under a unique run directory; publish any stable latest pointer/index with a lock and same-directory temp-file plus fsync/replace. Never truncate a shared stream at startup. If shared aggregation is required, use a locked append protocol and retain immutable per-run sources.
Acceptance criteria:
- Two intentionally interleaved farm processes preserve complete independently parseable streams, diffs, JSON reports, and Markdown reports for both run IDs.
- Killing a farm process during each report-write boundary leaves either the prior complete artifact or the new complete artifact, never truncated JSON.
- Restart logic can enumerate and attribute every settled task to its run without relying on last-writer-wins files.
- Tests exercise concurrent start, concurrent task settlement, and concurrent finalization against the same repository.
Isolate and atomically publish farm artifacts per concurrent run
Severity: high | Confidence: 0.96 | Effort: L
Where:
Evidence: Each invocation mints
runIdbut still truncates the shared${reportDir}/farm-results.jsonlwithwriteFile(resultsStream, ""), appends all runs to that same path, and directly overwrites the samefarm-report.json,farm-report.md, anddiffs/<task>.patchnames. There is no run-scoped directory, file lock, compare-and-swap, temp-file rename, or serialization across farm processes.Impact: Two farm invocations using the same repository can erase each other's streaming receipts and final authoritative reports. A crash during any direct report write can also leave truncated JSON/Markdown, destroying restart evidence exactly when the report is needed for recovery and audit.
Recommendation: Make
runIdan ownership boundary: write streams, diffs, and final reports under a unique run directory; publish any stable latest pointer/index with a lock and same-directory temp-file plus fsync/replace. Never truncate a shared stream at startup. If shared aggregation is required, use a locked append protocol and retain immutable per-run sources.Acceptance criteria: