Files
Edward Cheng-I Wu c5284f629b feat(citation): arXiv resolver + verification cache (#182 Delta 1+2 data layer) (#313)
The data-layer slice of #182 v3.11 (scope anchored in #299). Token-rendering
and policy layers (finalizer matrix, formatter allowlist, citation_existence
gate) are deferred to a later batch.

Delta 1 (arXiv resolver):
- scripts/arxiv_client.py: ArxivClient mirroring the crossref/openalex clients
  but parsing Atom XML, keyed by arXiv ID, with fixed ~3s pacing. arxiv_id_lookup
  + title_search + ArxivUnavailable degradation contract.
- deep-research/references/arxiv_api_protocol.md: the API protocol doc.
- literature_corpus_entry.schema.json: optional contamination_signals.arxiv_unmatched
  boolean + manual-entry not-rule extended to forbid it (anyOf now 4 lookups).
- contamination_signals.py: resolve_arxiv_unmatched + build_signals_object arxiv
  extension (signal computation only).

Delta 2 (persistent verification cache):
- scripts/verification_cache.py: SQLite WAL cache keyed by
  (citation_key, resolver_name, query_form), 90-day TTL, get/put/invalidate.
- cache= param threaded through all four resolver wrappers via a shared
  _cached_verdict helper; cache=None is byte-equivalent to prior behavior.
  query_form keys the whole attempt (id+title) to avoid caching a title-hit
  verdict under a bare-id key. Degradation is never cached; a malformed cached
  payload is treated as a miss. Manual entries never touch the cache.
- scripts/ars_cache_invalidate.py + commands/ars-cache-invalidate.md.

Tests: arxiv client (incl. version-suffix / URL fall-through / empty-title /
XML degradation edge cases), cache round-trip + TTL + WAL, resolver cache
integration (hit/miss/degradation/manual/malformed-payload), schema validation
+ not-rule. Full suite: 1981 passed, 3 skipped. Existing client/migration tests
unchanged (byte-equivalence proof).

[skip-closes-check] This is a data-layer slice; it does NOT complete or close
#182 — the gate/policy deliverables remain.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 12:07:19 +08:00

41 lines
1.3 KiB
Python

#!/usr/bin/env python3
"""/ars-cache-invalidate CLI — drop cached verification entries for a citation.
Backs the `/ars-cache-invalidate <citation_key>` slash command (Delta 2,
deliverable 6). Removes every cached resolver entry (all resolvers, all query
forms) for the named citation_key so the next pipeline run re-verifies it live.
Idempotent: invalidating a citation with no cached rows succeeds as a no-op.
Spec: docs/design/2026-05-21-v3.10-182-promote-citation-gate-spec.md §2 Delta 2.
"""
from __future__ import annotations
import argparse
import sys
try:
from verification_cache import VerificationCache
except ImportError:
from scripts.verification_cache import VerificationCache
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(
prog="ars-cache-invalidate",
description="Drop cached verification entries for a citation_key.",
)
parser.add_argument(
"citation_key",
help="The citation_key whose cached resolver entries to invalidate.",
)
args = parser.parse_args(argv)
cache = VerificationCache()
cache.invalidate(args.citation_key)
print(f"[ars-cache-invalidate] cleared cache for '{args.citation_key}'")
return 0
if __name__ == "__main__":
sys.exit(main())