Summary
The report phase completes, self-reports success, generates all per-finding disclosure documents — and writes report/SUMMARY_REPORT.md as a zero-byte file. Nothing in the returned status or error list indicates the primary human-readable deliverable is missing.
Evidence
report.report.json from the run:
{ "step": "report", "status": "success",
"summary": { "formats_generated": ["summary_path", "disclosures_dir"] },
"outputs": { "summary_path": ".../report/SUMMARY_REPORT.md" },
"errors": [] }
summary_path appears in both formats_generated and outputs; errors is empty. On disk the file is 0 bytes. The sibling disclosures_dir was populated correctly (413 documents), so only the summary failed.
Why it matters
This is a silent success: the tool asserts it produced an artifact it did not produce. It is the same failure class as the recent hardening series (#178–#196) and the two silent consistency-override false negatives closed in #195 — a step reporting success while its output is absent or empty. A consumer that trusts status never discovers the report is missing, and in a pipeline the empty file propagates downstream as if valid.
Suggested fix
stat the file after writing and fail the step when it is absent or zero-length; only append a path to formats_generated once verified non-empty. A test asserting os.path.getsize(summary_path) > 0 on a fixture scan would catch regressions.
Observed on one full-pipeline run at production scale: a private TypeScript monorepo (Angular front end, NestJS back end), 1,351 analysis units from 866 source files, run with --verify and no --limit, ~6.5 hours wall clock. The engine was invoked directly (python -m openant scan …, Python 3.13); the Go CLI was not built, so none of this involves the Go↔Python envelope. Stage 1 detection and Stage 2 verification ran on Claude Opus 5; application context, enhancement and reporting on Claude Sonnet 5 — all seven phases routed through OpenRouter (anthropic/claude-opus-5, anthropic/claude-sonnet-5) via a locally-added openrouter provider adapter, on a build based on upstream 2ed78f6. Cost figures are expressed as proportions of the run total; absolute amounts are omitted deliberately, as is the identity of the scanned repository.
Summary
The report phase completes, self-reports success, generates all per-finding disclosure documents — and writes report/SUMMARY_REPORT.md as a zero-byte file. Nothing in the returned status or error list indicates the primary human-readable deliverable is missing.
Evidence
report.report.json from the run:
{ "step": "report", "status": "success",
"summary": { "formats_generated": ["summary_path", "disclosures_dir"] },
"outputs": { "summary_path": ".../report/SUMMARY_REPORT.md" },
"errors": [] }
summary_path appears in both formats_generated and outputs; errors is empty. On disk the file is 0 bytes. The sibling disclosures_dir was populated correctly (413 documents), so only the summary failed.
Why it matters
This is a silent success: the tool asserts it produced an artifact it did not produce. It is the same failure class as the recent hardening series (#178–#196) and the two silent consistency-override false negatives closed in #195 — a step reporting success while its output is absent or empty. A consumer that trusts status never discovers the report is missing, and in a pipeline the empty file propagates downstream as if valid.
Suggested fix
stat the file after writing and fail the step when it is absent or zero-length; only append a path to formats_generated once verified non-empty. A test asserting os.path.getsize(summary_path) > 0 on a fixture scan would catch regressions.
Observed on one full-pipeline run at production scale: a private TypeScript monorepo (Angular front end, NestJS back end), 1,351 analysis units from 866 source files, run with --verify and no --limit, ~6.5 hours wall clock. The engine was invoked directly (python -m openant scan …, Python 3.13); the Go CLI was not built, so none of this involves the Go↔Python envelope. Stage 1 detection and Stage 2 verification ran on Claude Opus 5; application context, enhancement and reporting on Claude Sonnet 5 — all seven phases routed through OpenRouter (anthropic/claude-opus-5, anthropic/claude-sonnet-5) via a locally-added openrouter provider adapter, on a build based on upstream 2ed78f6. Cost figures are expressed as proportions of the run total; absolute amounts are omitted deliberately, as is the identity of the scanned repository.