Skip to content

fix(annotator): validate CourtListener result elements before use (#237)#244

Merged
williamzujkowski merged 1 commit into
mainfrom
fix/annotator-malformed-result-237
Jun 30, 2026
Merged

fix(annotator): validate CourtListener result elements before use (#237)#244
williamzujkowski merged 1 commit into
mainfrom
fix/annotator-malformed-result-237

Conversation

@williamzujkowski

Copy link
Copy Markdown
Collaborator

Summary

isSearchResponse only checked Array.isArray(results) — individual elements were cast straight to CourtListenerResult without field validation. The CourtListener search API is untrusted, so a result element missing or mistyping a field (no snippet, a non-array citation, a numeric court) made annotateSection throw on result.citation[0] / mapCourt(...) / truncation. Because annotateSection returns a Result<>, that throw escaped as a rejected promise — invisible to a caller checking result.ok, and able to abort a whole annotation batch on one bad element.

Fix

  • Add isCourtListenerResult that type-checks every field (caseName, citation: string[], court, dateFiled, snippet, absolute_url).
  • searchByStatute now drops malformed elements (logging the dropped count) and returns only well-formed results, so callers never see a partial object. The envelope-only check is renamed hasResultsArray.

Graceful degradation: a malformed element is skipped rather than tanking the section.

Tests

client.test.ts (new): validator unit tests (missing/mistyped fields rejected) + searchByStatute filtering malformed elements via a real client with stubbed fetch.

Annotator package: lint, typecheck, and 110 tests green locally.

Closes #237

isSearchResponse only checked Array.isArray(results); element fields were never
validated and cast straight to CourtListenerResult. A result missing or
mistyping a field (no snippet, non-array citation, numeric court) made
annotateSection throw on result.citation[0] / mapCourt(...) / truncation —
escaping its Result<> contract as a rejected promise that a caller checking
result.ok never sees, and that a single bad element could use to abort a batch.

Add isCourtListenerResult to type-check every field and have searchByStatute
drop malformed elements (logging the count), so callers only ever receive
well-formed results. Replaces the envelope-only check with hasResultsArray.

Adds client.test.ts covering the validator and the drop-malformed behaviour
(real client + stubbed fetch).

Closes #237

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@williamzujkowski williamzujkowski requested a review from a team as a code owner June 30, 2026 01:36
@williamzujkowski williamzujkowski merged commit b9dbaa2 into main Jun 30, 2026
3 checks passed
@williamzujkowski williamzujkowski deleted the fix/annotator-malformed-result-237 branch June 30, 2026 01:51
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.

bug(annotator): malformed CourtListener result throws instead of returning err(), violating Result<> contract

1 participant