Repository navigation
fix(reporting-storage): period retirement resolves the period's open issue occurrences (#3648 follow-up) - #3662
Merged
Merged
Conversation
…issue occurrences (#3648) retireExpiredPeriods deleted the obligation and statements but left already- escalated mismatch occurrences open in the issue-event outbox forever: never resolved for the observer and never prunable. Resolve them in the retirement transaction with settleIssueObligationOn; pending events stay deliverable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hrough retireExpiredPeriods (#3648) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Ladon verdict: Approve
Approve — clean bugfix with no blocking or medium findings.
Checked:
retireExpiredPeriodsnow callssettleIssueObligationOninside the phase-3 transaction (postgres.ts:2293), deliberately placed afterDELETE FROM adcp_reporting_obligationsso the obligation is gone,conflictsis empty, and every OPEN occurrence resolves. TheOPENfilter prevents double-resolve.- The outbox table (
adcp_reporting_issue_events) has no FK references and is never deleted at retirement; the only obligation-delete site is this one. - Test (reporting-issue-events-pg.test.js, +92) drives the real retirement path and includes a control proving undelivered outbox rows survive — covers the new branch.
- Changeset present and correctly typed
patchfor the two experimental packages (bugfix, not breaking per REPORTING-STABILITY policy); SDK change is TSDoc-only, so changeset-vs-wire-impact is satisfied.
Decision table: no critical/high findings (row 1 n/a); gated_paths false (row 2 n/a); high_risk false, no deletions/modifications triggers (rows 3-5 n/a); no prior decision (row 6 n/a); no no-auto-approve team match (row 7 n/a); zero medium findings (row 8 n/a). Falls through to row 9 → approve. Note: review_decision is REVIEW_REQUIRED but gated_paths is false, so no gate applies.
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.
Summary
Follow-up to #3654 (#3648): period retirement now resolves the retired period's open issue occurrences.
retireExpiredPeriodsdeleted a period's obligation and consumer statements, but it left the period'sCONSUMER_STATUS_MISMATCHoccurrences open in the issue-event outbox, and after that nothing could reach them:So an occurrence that had opened and escalated, and whose events were delivered, stayed open forever. The issue observer never got a
resolved, and the rows were never pruned. The reviewer of #3654 reproduced this through the realretireExpiredPeriods: after retirement, with delivery backdated past 7 days, the sweep recorded 0 events and prune deleted 0 rows.Fix
retireExpiredPeriodscalls the existingsettleIssueObligationOn. With the obligation gone nothing conflicts any more, so every open occurrence of that obligation getsresolved, recorded in the same transaction.opened, the newresolved) still go out in order.resolvedevent carriesissue: null, and it has noprincipalbecause the obligation is gone, as documented in feat(reporting): issueObserver — notify the seller when a reporting issue opens, escalates or resolves (#3648) #3654.ReportingIssueEventStoreV1now states the contract for custom stores: a store that deletes an obligation resolves the obligation's open occurrences in the same transaction. The guide explains retirement.memoryStorage()has no retirement path and never deletes an obligation.Python
Python has the same gap. Its period retirement (
_delete_records) never touchesreporting_issue_lifecycle, and its settle retires an occurrence only through a current statement, which retirement deletes. Combined with adcontextprotocol/adcp-client-python#1885, a retired period's occurrence re-escalates every retention period, forever. I filed it as adcontextprotocol/adcp-client-python#1886 and cross-linked it from #1885.Tests
packages/reporting-storage/test/reporting-issue-events-pg.test.js, newperiod retirementcase (25/25), driven through the realstore.retireExpiredPeriods:opened/escalatedgets exactly one undeliveredresolvedin the retirement.issue: nulland noprincipal, and prune then deletes the whole occurrence (3 rows).openedsurvives retirement and is delivered before itsresolved.reliable-reporting-core-maintenance-pg12/12,reporting-row-retention-pg9/9,reporting-host-reads-pg17/17,reporting-bigquery-sink-pg80/80.typecheck,typecheck:reporting-storage,lint:boundariesandformat:checkare clean.Changeset
@adcp/reporting-storagepatch and@adcp/sdkpatch (the store-contract TSDoc). No migration.🤖 Generated with Claude Code