Skip to content

Report step returns status: success while writing SUMMARY_REPORT.md as 0 bytes #209

Description

@NahumKorda

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions