Skip to content

fix: fail the run when an archive is refused or will not open - #634

Open
Nitjsefnie wants to merge 1 commit into
AgoraDMV:developfrom
Nitjsefnie-OSC:issue-325
Open

fix: fail the run when an archive is refused or will not open#634
Nitjsefnie wants to merge 1 commit into
AgoraDMV:developfrom
Nitjsefnie-OSC:issue-325

Conversation

@Nitjsefnie

Copy link
Copy Markdown
Contributor

Related issue

Closes #325

Also filed while doing this work, not fixed here:

What does this change?

An archive refused by an extraction ceiling, or one that will not open, is no longer dropped from the corpus in silence — the run now completes every archive and then exits nonzero.

Option 2 from the issue, not option 1. The batch still runs to completion, so every archive that did extract still reaches the index; the failure is reported afterwards. Option 3 was considered and rejected on evidence: the download path already .part-stages and calls _verify_archive_complete, so "a corrupt ZIP is expected debris to skip" does not hold in this repo.

The reviewable decision is that extract_archives now raises ArchivesNotExtracted after the loop rather than returning a shorter list. extract_archives has exactly one production caller, so this costs no external contract, and a raise is the one shape a caller cannot accidentally ignore — which is the whole of #325. It reuses the existing CongressNotAvailablemainsys.exit(1) mechanism (tools/fetch_bills.py:833-837) to carry the policy from f180c36, where the CSV path exits nonzero on skipped rows.

Both ceilings are covered, not only the newer one: the member-count ceiling at tools/fetch_bill_archives.py:265 and the byte ceiling at :269, with a test for each.

How to test

The behaviour is pinned by tests/test_fetch_bill_archives_run_status.py, which builds ZIPs in tmp_path — no network, no fixtures.

Each test asserts both halves, and that is deliberate: asserting only the nonzero exit would also pass an implementation that aborts on the first failure and throws away the rest of the batch, which is the cost the issue names for option 1.

Run it both ways, as the checklist asks:

  • Against the unfixed code, five assertions fail (lines 96, 110, 124, 137, 177) — assertion failures, not errors.
  • Reverting only the exit-code propagation reds the five status assertions while the resilience assertions stay green.
  • Making it abort on the first failure instead reds five resilience assertions while the status assertion stays green.

That second pair is what shows the tests distinguish "report after completing the batch" from "abort on first failure", rather than merely detecting that something changed.

I have not ticked "ran the CI gates locally": the full suite was run on a GitHub runner rather than on my machine, across all 25 jobs, and locally I ran only the touched test files. Two pre-existing entrypoint tests fail before this change with AttributeError rather than an assertion; they are not part of the evidence above.

Checklist

  • Linked the issue above (Closes #...)
  • Ran the CI gates locally and they pass (see What CI checks) — see the note in How to test: run on a runner, not locally
  • New or changed behavior has tests
  • For a bug fix: the test fails without the fix, and I ran it both ways to check
  • Disclosed AI assistance below

AI assistance

Generated by Claude Opus 5 (brief, implementation, review, testing)

`extract_archive` refuses an oversized expansion (AgoraDMV#279) and a too-large member
count (AgoraDMV#306) by raising, and both comments describe that as failing loud. The
caller undid it: `extract_archives` logged `Failed <archive>` and continued, the
parse phase found no folder and indexed zero bills for that congress and bill
type -- a status line indistinguishable from one that legitimately had nothing
new -- and the process exited 0. An unattended run reported success over a corpus
missing every bill the archive held, which is the outcome both ceilings exist to
prevent (AgoraDMV#325).

Counted and reported at the end, rather than propagated on the spot, because the
broad `except` buys batch resilience worth keeping: one bad archive must not cost
the healthy ones. That is the direction this repository already took for a
skipped CSV row in `fetch_bills.py download-all`, which completes every remaining
row and then exits 1.

- `extract_archives` attempts every archive and then raises
  `ArchivesNotExtracted`, naming all of them. It covers both ceilings and an
  archive that will not open at all: the corpus is missing those bills either
  way, and the likeliest real failure is the one a ceiling-only rule would miss.
- `fetch_bill_archives` holds that failure across phase 3 and re-raises it after,
  so everything that did extract still reaches the index.
- A `main` maps it to exit 1 with a one-liner instead of a traceback: the fault
  is in the data or in a ceiling, not in this script.

An archive skipped because its folder already exists is not a failure -- that is
the cache working, and counting it would make every re-run of a healthy corpus
exit nonzero.

The new tests are two-sided throughout: asserting only the status would be
satisfied by aborting the batch on the first refusal, so each one pins that the
healthy archives still extract, and the end-to-end case pins that they still
reach the index.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A refused archive is dropped from the corpus without failing the run

1 participant