Skip to content

Integrate PRs #73–#77 with cross-PR regression fixes - #78

Merged
JordanCoin merged 12 commits into
mainfrom
claude/open-prs-merge-review-e6z0ep
Sep 26, 2026
Merged

JordanCoin merged 12 commits into
mainfrom
claude/open-prs-merge-review-e6z0ep

Conversation

@JordanCoin

Copy link
Copy Markdown
Owner

Merges all five open PRs together and fixes the defects that only appear when they are combined. Each PR was green on its own, but all five touch records_search in cli.py and none had ever been tested against the others.

Closes #73, closes #74, closes #75, closes #76, closes #77.

Conflicts resolved

Defects found by reviewing the integrated result

crossref.py (from #76)

  • A failing source raised, which discarded every hit the checker had already collected. One unreadable ICIJ CSV erased real matches from the files that did open. _SourceCheckError now carries partial hits, _check_icij keeps reading the remaining files, and the loop merges those hits while still marking the source ERRORED. Failure stays visible; evidence stops disappearing.
  • Every remote checker fails through result.error, which was wrapped in a bare RuntimeError — so a 503, a DNS failure and a schema change all reported ERRORED(RuntimeError), while opensanctions (a different code path) reported the real kind in the same run. The adapter's own failure kind now comes through. Only the leading exception name travels: the detail can echo the looked-up entity name via the URL, and these statuses land in a report the user may share.
  • An ICIJ directory containing no CSVs reported status checked — a clean bill of health after reading zero bytes. A failed or nested extraction now reports NoICIJData.

cli.py (from #73 and #75)

  • records search --raw on an adapter error printed [] and exited 0, so a script could not tell an API failure from "no results". The error goes to stderr with exit 1, leaving stdout parseable JSON.
  • The adapter-crash handler still wrote its message to stdout via rprint, contradicting the pipe-safety comment two lines above it. It goes to stderr now.
  • The "0 results is not proof that no filing exists" caveat only fired with --type, so the broader untyped SEC search — where EDGAR full-text coverage gaps bite hardest — kept the flat "No results found".

sec_edgar.py (from #77)

  • The archive-shard walk fired every request back to back. For a long-lived filer that is 20+ unpaced hits on data.sec.gov, which is the burst SEC's fair-access policy cuts off. Requests are now paced, and shards SEC dates entirely before --since are skipped rather than fetched and discarded.
  • _filing_entity was annotated RecordEntity | None but never returns None, leaving its caller dereferencing an Optional.

Verification

  • ruff check and ruff format --check clean on openfoia/ and tests/.
  • 318 passed, 20 skipped. Every fix above has a regression test.
  • tests/test_security_metadata.py has 2 failures in the dev container (pyo3/_cffi_backend), reproduced on unmodified main — environmental, and green in GitHub CI on all five source PRs.
  • mypy gains 2 errors, both the untyped-decorator/no-untyped-def pattern the other 48 CLI commands already have. Not a CI gate (continue-on-error).

Not addressed

records search sends the query to a third party with no warning and no confirmation — no --tor, no prompt. #77's new records filings does warn and confirm; #74 documents the gap in the README rather than closing it. That is a Principle 1 gap, but closing it changes CLI behavior for existing scripts, so it is left as a separate decision.

🤖 Generated with Claude Code

https://claude.ai/code/session_016LaGpHLuSRHzGARb38X7YS


Generated by Claude Code

JordanCoin and others added 12 commits August 12, 2026 22:25
Resolved add/add conflict in tests/test_records_cli.py by keeping both
regression tests (raw-JSON output from #73, help-text coverage from #74).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016LaGpHLuSRHzGARb38X7YS
Two integration fixes on top of the merged PRs:

- crossref: #76 made a failing source raise, which discarded every hit the
  checker had already collected. One unreadable ICIJ CSV therefore erased
  real matches found in the files that did open. _SourceCheckError now
  carries partial hits, _check_icij keeps reading the remaining files, and
  the crossref loop merges those hits while still marking the source
  ERRORED. Failure stays visible; evidence stops disappearing.

- records search --raw: an adapter error printed '[]' and exited 0, so a
  script could not tell an API failure from 'no results'. The error now
  goes to stderr with exit 1, leaving stdout parseable JSON (#73) and
  honouring the 'no results != API error' rule alongside #75.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016LaGpHLuSRHzGARb38X7YS
Follow-ups found by reviewing the five PRs together rather than one at a
time:

- crossref: every remote checker fails through result.error, which #76
  wrapped in a bare RuntimeError -- so a 503, a DNS failure and a schema
  change all reported ERRORED(RuntimeError) while opensanctions, which
  takes a different path, showed the real kind. The adapter's own failure
  kind is now carried through, and only the leading exception name: the
  detail can echo the looked-up entity name through a URL, and these
  statuses land in a report the user may share.

- crossref: an ICIJ directory containing no CSVs reported status 'checked'
  -- a clean bill of health after reading nothing. A failed or nested
  extraction now reports NoICIJData instead.

- records search --raw: the adapter-crash handler still wrote its message
  to stdout through rprint, contradicting the pipe-safety #73 added two
  lines above. It goes to stderr now.

- records search: the 'a 0 is not proof no filing exists' caveat from #75
  only fired with --type, so the broader untyped SEC search -- where EDGAR
  full-text coverage gaps bite hardest -- kept the flat 'No results found'.

- sec filings: the shard walk fired every archive request back to back,
  which for a long-lived filer is the burst SEC's fair-access policy cuts
  off. Requests are paced, and shards SEC dates entirely before --since
  are skipped rather than fetched and discarded.

- sec filings: _filing_entity was annotated Optional but never returns
  None, leaving its caller dereferencing an Optional.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016LaGpHLuSRHzGARb38X7YS
Copilot AI lite review requested due to automatic review settings September 26, 2026 04:53

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@JordanCoin
JordanCoin merged commit be8ea07 into main Sep 26, 2026
5 checks passed
JordanCoin pushed a commit that referenced this pull request Sep 26, 2026
Bump version to 4.2.0 and add the changelog entry for PRs #73-#78:
records filings (SEC filing history), per-source cross-reference
statuses, honest failure reporting in crossref and records search --raw,
and the full nine-source records search docs.

Minor bump: records filings is a new command; nothing is removed or
changed incompatibly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016LaGpHLuSRHzGARb38X7YS
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.

3 participants