Repository navigation
fix(nara): call the v2 catalog API the adapter claims to wrap - #639
Merged
1 commit merged intoNov 8, 2026
Merged
1 commit merged into
1 commit merged into
Conversation
Every NARA search failed. The adapter called `/api/v2/search` with
`rows`/`offset` and read `results[]` — a shape the catalog no longer
serves. That path now returns the catalog's HTML single-page app, so
`r.json()` raised on the first request and the source contributed
nothing to any corpus.
The key was also documented as optional ("works without an API key, set
NARA_API_KEY for higher rate limits") and `is_available()` returned True
unconditionally. Without the header the API serves HTML rather than
JSON, so a keyless install reported NARA as a live source that could
never return a clip. It now gates on NARA_API_KEY like the other
key-backed adapters, and the install text says why.
Corrected against the live API:
- endpoint `/api/v2/search` -> `/api/v2/records/search`
- paging `rows` + `offset` -> `limit` + 1-based `page`
(offset/from/start are silently ignored)
- envelope `results[]` -> `body.hits.hits[]._source.record`
- files `objects[].url` -> `digitalObjects[].objectUrl`
- kind `mimeType` -> extension, with the `objectType` label
("Audio/Visual File (MP4)") as fallback
- filter `type=moving-image` -> `typeOfMaterials`, the catalog's own
facet value, so the video/image split happens server-side
(47,075 hits -> 3,970 for "apollo" video)
- also adds `availableOnline=true`: a record with no digitised file can
never yield a candidate
v2 exposes no dimensions or duration, so width/height/duration stay 0
rather than being invented, and `scopeAndContentNote` is gone — the
description now lives across `generalNotes`, `shotList` and `subjects`,
which `_describe` flattens into the text channel used for ranking.
Result ordering is not stable across identical requests, so consecutive
pages can overlap; noted at the call site rather than papered over.
Verified against the live catalog: video and image searches both return
downloadable public-domain candidates, and `page` tiles results exactly.
Five tests pin the endpoint, the paging params, the kind filter, the
envelope walk and the tag flattening.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QsqAJj445U3Uj9gmDTfXXV
calesthio
approved these changes
Nov 7, 2026
calesthio
left a comment
Collaborator
There was a problem hiding this comment.
Thank you for updating NARA's endpoint and record parsing. Reviewed the complete diff against main 63d1087a and checked the official NARA getting-started/API documentation: /api/v2/records/search, x-api-key, availableOnline and material filters agree with the published interface (https://www.archives.gov/research/catalog/help/api-getting-started ; https://www.archives.gov/research/catalog/help/api). Unknown dimensions/duration remain explicit rather than invented. Validation: adapter suite 40 passed, 3 expected failures for unrelated adapters. No credentials or live media downloads were used; mocked response-envelope coverage is not a live-service guarantee.
calesthio
pushed a commit
to manish511-github/OpenMontage
that referenced
this pull request
Nov 8, 2026
# Conflicts: # tests/tools/test_stock_source_adapters.py
calesthio
pushed a commit
to manish511-github/OpenMontage
that referenced
this pull request
Nov 8, 2026
…c#815 Adapted from PR OpenMontageInc#815 by @serdarucel: retain deterministic shape and PYTHONHASHSEED subprocess coverage with canonical PR OpenMontageInc#597 stable_url_id (16 hexadecimal characters). The cohort preserves the original reviewed heads for OpenMontageInc#594, OpenMontageInc#595, OpenMontageInc#597, OpenMontageInc#639, OpenMontageInc#652, OpenMontageInc#653, OpenMontageInc#779 and OpenMontageInc#857. No audio or Pixabay retry implementations are included.
82d2601
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The bug
Every NARA search fails. The adapter calls
/api/v2/searchwithrows/offsetand readsresults[]— a shape the catalog no longer serves. That path now returns the catalog's HTML single-page app, sor.json()raises on the first request and the source contributes nothing to any corpus.Two things hid it.
search()re-raises transport failures (correctly — that's the #511 contract), so the failure surfaces as a per-source error rather than a wrong result. Andis_available()returnedTrueunconditionally, so NARA counted toward the "configured sources" total on every install while being incapable of returning a clip.The key was documented as optional — "NARA works without an API key. Set NARA_API_KEY in .env for higher rate limits." It isn't: without the
x-api-keyheader the API serves HTML instead of JSON. The adapter now gates onNARA_API_KEYlike the other key-backed sources, and the install text says why.What changed
Corrected against the live API:
/api/v2/search/api/v2/records/searchrows+offsetlimit+ 1-basedpageresults[]body.hits.hits[]._source.recordobjects[].urldigitalObjects[].objectUrlmimeTypeobjectTypelabel as fallbacktype=moving-imagetypeOfMaterials(the catalog's own facet)offset,fromandstartare all silently ignored by v2 — onlypagemoves the window, which is why the old call returned page 1 forever even when it did parse.The kind filter now runs server-side using the catalog's own
typeOfMaterialsfacet value, so we stop over-fetching and discarding:apollogoes from 47,075 hits to 3,970 for video.availableOnline=trueis added too — a record with no digitised file can never yield a candidate.Two honest gaps rather than invented data:
width/height/durationstay0, per theCandidatedocstring ("fields that don't apply default to zero/empty"). Duration filters can only be applied downstream once a file is probed.scopeAndContentNoteno longer exists. The description is spread acrossgeneralNotes(list),shotList(str) andsubjects(list of dicts);_describeflattens them into the text channel used for ranking.One quirk documented at the call site: result ordering is not stable across identical requests — relevance ties reshuffle — so consecutive pages can overlap or skip a record. De-dup on
source_idif you walk several pages.Verification
Against the live catalog with a real key:
page=1/2/3atlimit=3tile a singlelimit=9call exactly. A returned.mp4serves206 video/mp4.Five tests pin the endpoint, the paging params (including that
offsetis not sent), the server-side kind filter, the envelope walk and the tag flattening. The existing suite still passes —40 passed, 3 xfailedintests/tools/test_stock_source_adapters.py, with the pre-existing xfails untouched. The adapter keeps re-raising transport errors, so it stays out of_STILL_SWALLOWS_TRANSPORT_ERRORS.🤖 Generated with Claude Code
https://claude.ai/code/session_01QsqAJj445U3Uj9gmDTfXXV