feat(zdr): give every provider ZDR attestation an explicit expiry - #1916
feat(zdr): give every provider ZDR attestation an explicit expiry#1916seonghobae wants to merge 5 commits into
Conversation
The five entries in PROVIDER_ZDR_SCOPE each carried an as_of date and nothing else, so a frozen citation aged silently: it kept reading as authoritative long after anyone last opened the source. A provider data policy is a living document — NVIDIA can repeal the Section 3.3(iv) training carve-out and OpenRouter can change what its ZDR feed covers, and neither event edits this file. Add a required valid_until to ProviderZdrScope, set on all five entries to as_of plus a 90-day quarterly re-read window, so no future entry can be added without one. Expose the staleness as data through attestation_is_current() and expired_provider_names(), both taking the date as an argument rather than reading the clock. is_zdr_model() gains an optional today. Supplied, an expired attestation grants nothing — the same conservative stance the module already takes toward a policy it cannot ascertain. Omitted, the decision is unchanged, so no existing caller changes behaviour and this cannot become a dated time bomb in the org-wide review path. Wiring a caller to pass today is deliberately left to its own reviewed change. Every new test pins fixed dates instead of date.today(), so the tests themselves cannot age into failure — the mistake tests/test_nim_benchmark.py had to be repaired for in #1073. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
|
Warning Review limit reachedNext included review available in 36 minutes. View limit detailsLimit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Review configuration: ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (2)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
CI status note — standing down on the two red checks on head
Not re-running it manually: a re-run dispatches again and enlarges the queue that is causing the failure ( Generated by Claude Code |
Rebinds workflow_sha so the required review runs pick up #1939's round-robin catalog fill; the previous head's Strix and Noema runs failed on the single-upstream gateway stall that #1939 removes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
|
CI note and push: head Two new red checks on the previous head, both the single-upstream gateway stall class and neither in this diff: Local gate on Generated by Claude Code |
|
CI note on head Nothing in this diff ( Generated by Claude Code |
|
CI note on head This is the longest walk of the night: 63 minutes of a held runner, Action: not re-running while the pool reads like this (the catalog rule this session recorded); the single sanctioned re-run stays gated on #1938's queued attempt 2 or folds into the next base-merge push, which also binds the artifact-producing workflow. Owner-level tracking: contextual-orchestrator#1045. Generated by Claude Code |
|
CI note on head
That is a third shape next to the 429 and the held-open 502: the gateway itself returning 500s in bulk while every ready route is a deepseek-v4 key under contention. Standing down on this check; the single sanctioned re-run for this PR is not being spent while #1938's attempt 2 has just failed after 50 minutes on the same pool. Owner-level tracking: contextual-orchestrator#1045 and #1948. Generated by Claude Code |
Binds the sidecar pin bump to contextual-orchestrator@414f2297 (contextual-orchestrator#1081's retry-stacking fix, .github efb8926) and the #1943/#1944/#1945 workflows to this head's required runs; the previous head's Noema/Strix runs failed on the stalled-route loop that fix removes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
|
CI note and push: head Merges Local gate on Generated by Claude Code |
|
CI note on head Generated by Claude Code |
|
CI note on head
So this scan did more work than any earlier one on this pool and still could not finish, because every timed-out stream request re-selected the same silent first-ranked route: the tool-bearing passthrough class co#1082 fixes (bare Generated by Claude Code |
… timeouts, 0 circuit records, 126 min) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
|
CI note and push: head Merges The five red checks on the previous head were all attributed and none was this diff's: Gate on the pushed tree: 2936 passed, 1 skipped, 21 subtests; coverage 100 % (13,192 statements / 5,328 branches, 0 missed); Generated by Claude Code |
|
CI note on head
Nothing to push, no re-run (0 ready routes). Worth recording as the direct before/after this head produced: the same zero-ready outcome on this PR took 555 s of provisioning + 126 min of scanning at 05:08Z on the pre-#1949 launcher, and 123 s total now. The failure is the same; its cost fell by two orders of magnitude, which is what the base merge was for. Generated by Claude Code |
|
Addition to my note 45 minutes ago:
That zero-of-21 adjacency is the discriminator: the tool-bearing passthrough path never records the stalled candidate, so it is re-selected on every retry ( So this head has now shown three of the four known outcomes within an hour: Generated by Claude Code |
…rections Section 0 gains the CI-run counterpart of the stale-checkout rule: a pull_request_target run executes the base branch's scripts as of the run's created_at, not its started_at, and on 2026-09-06 those were routinely 90 minutes apart. #1916's 12:00Z preflight looked like #1957 failing 23 minutes after it merged; the run was created at 10:24Z. Classify by created_at, or by the report's own version marker (postponed_probed_count). Section 3 records what #1957 changed, measured on this repository's own heads (ready 0 -> 1, probed 6 -> 16), and three things the earlier text got wrong or did not have: - caller attempts=1 counts sidecar->gateway calls, not routing. One such attempt carried ~20 provider_attempt lines across four agents, so it is not evidence that failover did not happen. - The ~90 s attempt is now measured: 90.090 s and 90.115 s TimeoutError probes of google/gemma-4-31b-it on both NVIDIA keys. - A third reason the breaker cannot exclude a bad route, stronger than the 30 s reset: _record_success pops the circuit state entirely, so any single success zeroes the count and an alternating route never reaches the threshold. The sandbox split is refined: is_caido_bootstrap_timing_error() inspects only the last attempt, so grepping an artifact for loginAsGuest is not sufficient. Four artifacts from one day show every combination, including #1930's run 34027404208, which carries the line but ends in gateway exhaustion. Classify on the verdict line; the check annotation is generic by design. Section 7 gains the occupancy half of the queue shortage: #1930's strix job held a runner for 351.8 minutes and produced no verdict, which is execution rather than queue wait -- its sibling jobs finished in tenths of a minute. Capping long jobs is a different remedy from adding capacity. Section 9 gains the DISPATCH_OUTCOME/VERDICT_STATE discriminator that separates it from signature 1, plus the 34-of-34-queued measurement. Gate: 2956 passed, 1 skipped, 21 subtests, coverage 100%, interrogate 100%. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
Lane: jan | session:session_01BV96rXhqoR3tYZ9AeAVur4
Why
The five entries in
PROVIDER_ZDR_SCOPEeach carry anas_ofdate and nothing else. Nothing anywhere ever compares that date to anything, so a frozen citation ages silently: it keeps reading as authoritative long after the last time anyone actually opened the source.That matters because these are not measurements, they are readings of living documents.
scripts/ci/zdr_policy.py:99-111spends thirteen lines explaining that NVIDIA's Section 3.3(iv) training carve-out is what makesnvidia_nimaffirmatively not-ZDR, and instructs the reader not to reclassify it "without a superseding, dated NVIDIA document". If NVIDIA published exactly that superseding document tomorrow, this table would not notice, and neither would any agent reading it — theas_ofwould still look reassuringly recent to anyone who did not do the subtraction. The same is true in the dangerous direction foropenrouter, the one entry that grants ZDR.These are the only dated citations in this repository with no expiry of any kind.
What this changes
valid_untilis now a required field onProviderZdrScope— no default, so a future entry cannot be added without one. All five entries are set toas_of + 90 days, recorded asATTESTATION_REVIEW_WINDOW_DAYS. Ninety days is a quarterly re-read cadence for a published ToS or data-policy page; deliberately longer than the monthly window used for measured cost evidence, because these track legal text that changes on the provider's schedule rather than a price that drifts continuously.attestation_is_current(provider_name, today)andexpired_provider_names(today)— pure reporting functions. Both take the date as an argument rather than reading the clock, so callers and tests stay deterministic.is_zdr_model(..., today=None)— whentodayis supplied, an attestation past itsvalid_untilgrants nothing. That is not a new policy: the module docstring already states that any provider whose guarantee "cannot be attested from a machine-readable, dated source is treated as NOT ZDR", and a citation nobody has re-read for a quarter is precisely such a source.What this deliberately does not do
It does not become a dated time bomb in the org-wide review path.
todaydefaults toNone, which preserves the current decision exactly, so no existing caller changes behaviour when these dates lapse in November. Wiring a caller to passtodayflips a switch that can withdraw ZDR routes from the whole review pipeline at a date certain, and a change with that blast radius should be reviewed on its own terms rather than riding in on a data-model change. Until then the expiry is fully observable viaexpired_provider_names().This is the shape the same problem should have taken elsewhere:
contextual_orchestrator/nim_benchmark.pyenforces its window unconditionally, and the resulting wall-clock coupling had to be repaired in ContextualWisdomLab/contextual-orchestrator#1073 by pinning the test dates. Hence the corresponding discipline below.Verification
Every new test pins fixed dates — there is no
date.today()anywhere in them — so the tests cannot age into failure.test_expired_provider_names_reports_only_the_lapsed_entriesasserts against2026-11-26and2999-12-31;test_attestation_is_current_on_and_after_the_expiry_boundaryderives its dates from the entry it is testing rather than hard-coding them, so it stays correct when the dates are next refreshed.test_every_attestation_carries_a_valid_until_after_its_as_ofis the contract that prevents the original defect from returning: it fails if any entry is added withoutvalid_until, or with one that does not equalas_of + ATTESTATION_REVIEW_WINDOW_DAYS.test_is_zdr_model_expiry_cannot_promote_a_non_zdr_providerpins the direction of the fail-closed path — expiry may only ever remove a grant.Test plan
python3 -m pytest tests/test_zdr_policy.py -q→ 33 passed (25 existing + 8 new)coverage run -m pytest tests -q→ 2891 passed, 1 skipped, 21 subtests passedcoverage report→ 100%;scripts/ci/zdr_policy.py45 statements / 8 branches, 0 missinginterrogate→ PASSED (100.0%)test_contextual_orchestrator_review_policy,test_contextual_orchestrator_free_credential_admission,test_contextual_orchestrator_review_sidecar_contract,test_agent_review_runtime_quality_consolidation— pass unchanged; no other file constructsProviderZdrScope, so the new required field breaks no callergit diff --checkcleanorigin/main, not a stale checkoutDeveloper experience
An agent reading the table can now tell at a glance whether a citation is still inside its review window, and
expired_provider_names(today)answers "what needs re-reading" in one call instead of five manual date subtractions. Adding a provider without an expiry now fails a test rather than passing silently.User experience
No runtime behaviour changes in this PR. The path it opens is that a stale ZDR citation can be made to withdraw a routing grant automatically instead of continuing to authorize private-target traffic on an unread policy.
🤖 Generated with Claude Code
https://claude.ai/code/session_01BV96rXhqoR3tYZ9AeAVur4
Generated by Claude Code