Repository navigation
fix(reporting): classify pending status and owed history as transient, unresolved references as REFERENCE_NOT_FOUND - #1631
Conversation
…, unresolved references as REFERENCE_NOT_FOUND installed_reporting_call projected STATUS_PROJECTION_UNAVAILABLE, HISTORY_UNAVAILABLE and LOOKUP_UNAVAILABLE as terminal. A pending status lifecycle and retained history the seller still owes resolve on the seller side, so they are transient. A reporting reference that does not resolve for the caller answers the standard, nondisclosing REFERENCE_NOT_FOUND (correctable) with a generic message. Fixes #1618 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
c0d65ed to
f868413
Compare
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — clean error-code reclassification fix in the private adcp.reporting._errors module.
Checked:
- Reclassifies three LedgerConflictError codes: STATUS_PROJECTION_UNAVAILABLE / HISTORY_UNAVAILABLE (terminal→transient) and LOOKUP_UNAVAILABLE→REFERENCE_NOT_FOUND/correctable with a nondisclosing generic message.
- Verified against the pinned 3.2.0-beta.9 manifest: REFERENCE_NOT_FOUND is
correctable, so the mapping is spec-correct and follows the existing REVISION_NOT_FOUND precedent. - Uniform-nondisclosure MUST honored — test confirms
obl_secretis scrubbed. - Private module, no public-surface change;
fix:prefix is correct. No semver, forward-compat, codegen, import-layering, or wire-translation rules in play. - Both decisioning and handler paths are tested.
Decision path: no critical/high/medium findings; gated_paths false; high_risk false; no no-auto-approve team match; no prior decision. review_decision is REVIEW_REQUIRED but gated_paths is false, so row 2 does not fire. Falls through to row 9 → approve.
There was a problem hiding this comment.
Ladon verdict: Approve
Approve.
Reclassifies three reporting ledger codes in installed_reporting_call: STATUS_PROJECTION_UNAVAILABLE and HISTORY_UNAVAILABLE move terminal→transient (routed through _REPORTING_TRANSIENT), and LOOKUP_UNAVAILABLE maps to the nondisclosing REFERENCE_NOT_FOUND/correctable with a generic message that drops the buyer-supplied reference (verified no obl_secret leak). Raise-site audit confirms all buyer-reachable sites are seller-owed, retry-succeeds state. No public signature change, no enum/recovery-value break, no DR-0032/0033 pathway applies. Tests cover both decisioning paths × all three codes with redaction asserts.
No critical/high/medium findings. gated_paths is false and high_risk is false, so rows 2–5 do not apply. No no-auto-approve team match (row 7 n/a). Prior decision was approve (row 6 n/a). Fewer than three medium findings (row 8 n/a). Falls through to row 9 → approve. Note: review_decision is REVIEW_REQUIRED, but since gated_paths is false, row 2's gate does not fire.
Fixes #1618
What changed
installed_reporting_callused to project threeLedgerConflictErrorcodes as terminal. They now map as follows (src/adcp/reporting/_errors.py):STATUS_PROJECTION_UNAVAILABLESTATUS_PROJECTION_UNAVAILABLE/ transientHISTORY_UNAVAILABLEHISTORY_UNAVAILABLE/ transientLOOKUP_UNAVAILABLEREFERENCE_NOT_FOUND/ correctable, generic messageReporting reference not foundWhy each was chosen
retry_afterfor these, so none is set.HISTORY_UNAVAILABLE. Every raise site a buyer can reach is retained evidence the seller still owes inside the retention window. That evidence is either not yet materialized ("materialization dependencies are unavailable", "receipt revision is unavailable") or awaiting operator repair ("revision history requires repair", "reconciliation history is inconsistent"). This is the same situation as fix(reporting): answer unreadable exact revision reads with SERVICE_UNAVAILABLE #1471, where rows that fail their binding answerSERVICE_UNAVAILABLE/ transient. Terminal would tell a buyer to stop sending a correct request. The permanent "history older than retention" meaning of this code is theget_reporting_statusissue code, which carries its ownaction_requiredseverity. It is never raised as an error.LOOKUP_UNAVAILABLE. These are buyer-supplied reporting references that don't resolve for the caller. AdCP 3.2'sREFERENCE_NOT_FOUNDsays: "Typed parameters that lack a dedicated standard code MUST also use REFERENCE_NOT_FOUND rather than minting a custom *_NOT_FOUND code". Its uniform-response rule requires a generic message, so the projection now rewrites the message too. This follows fix(reporting): answer unreadable exact revision reads with SERVICE_UNAVAILABLE #1471, which made revision lookupsREFERENCE_NOT_FOUND, and the existingREVISION_NOT_FOUNDmapping.Other codes in the table
I went through every
LedgerConflictErrorcode that can reachinstalled_reporting_call. Cursor and input codes are already correctable. The other unlisted codes are producer-side writes, adopter composition faults (REPORTING_CONFIGURATION_UNADMITTED,UNAUTHORIZED) or integrity failures, and terminal remains correct for them. I left out one code because its meaning is mixed:REPORTING_RECORD_UNAVAILABLEis used both for unresolved receipt targets and for stale boundaries, and it only reaches buyers through per-item receipt results. Those per-item results (sync_reporting_status/sync_reporting_receiptsfailedentries) carry norecoverytoday. That gap is separate from this table.Store-level callers still see the original
LedgerConflictErrorcodes. Only the buyer projection changes.Tests
tests/test_reporting_installed_errors.py: the issue's reproduction on both the decisioning and handler paths, plus updated extension-code expectations.make lint,make typecheck-allandmake testpass locally except one pre-existing failure,tests/integration/test_a2a_context_id.py::test_two_calls_share_server_assigned_context_id. It fails only inside the full serial suite (Unknown skill: create_media_buy), and it fails the same way on cleanorigin/main.🤖 Generated with Claude Code