Bulk PDF durable capture: merge acceptance and remaining activation gates¶
PR #3094 adds the disabled-by-default capture and ordinary terminal-cleanup slice on top of the authority contract in #3042. Its usable boundary is an immutable, correctly bound object: capture survives duplicate events, publication consults Project Management, terminal cleanup retains the exact version until its retention deadline, and acknowledgement retires the hold through a durable outbox. Publication pause permits cleanup to continue.
Acceptance for this slice:
- An exact-binding duplicate preserves the capture; conflicting binding data poisons it.
- An expired lease can be recovered without replacing a newer durable state from a stale index read.
- A terminal object is never published to the agent. A retriable claim remains held.
- Cleanup uses the exact bucket/key/version and preserves the first retention deadline.
- Capture retirement and hold-retirement outbox creation are one conditional transaction; the outbox is deleted only after its acknowledgement is recorded.
- Each inventory invocation reads one bounded version page and checkpoints only after all its captures succeed. Overlapping invocations cannot overwrite a newer checkpoint. Due cleanup and outbox work run before inventory, so an inventory outage cannot starve them.
- Missing/malformed metadata and metadata naming another environment remain non-publishable under the configured environment's reserved-object boundary.
- The reconciler requests the scopes issued by Identity, and its role permits the configured failure-queue send. Existing chart defaults render no new durable resources.
Validation includes notifier unit and LocalStack integration tests, chart unit tests, chart-change detection, and the PR's current-commit CI/reviews. The PR description records the final counts.
Ordered follow-ups owned by #3168¶
- Complete rejected-object cleanup and quarantine adoption. The current slice retains unresolved or ambiguous objects without publishing or deleting them. Add trusted resolver adoption, cleanup-only authority, full-binding conditional unowned deletion after snapshotted retention, and durable quarantine-fence acknowledgement before changing custody. Accept only with zero/one/multiple binding, active-claim, response-loss and crash-recovery tests. This must precede activation that removes reserved-object lifecycle expiry.
- Complete tombstone replay/queue/inventory retirement. Tombstones have no TTL and remain retained. Purge must require the replay deadline, authoritative inventory, and empty visible and in-flight failure-queue proof. Test delayed redrive, stale evidence and overlapping workers; no age-only deletion is allowed. This depends on the rejected-object custody flow.
- Schedule and validate receipt-drain reconciliation. The PM consumer exists, but a bounded producer must discover eligible retained receipts and schedule it. Prove history pruning, outbox absence and receipt expiry together before purge; test failures and idempotent replay. This depends on the hold-retirement and tombstone contracts.
- Complete quarantine transfer, preview provisioning and the separately approved rollout evidence in ADR-015. These are later slices, not properties established by merging #3094.
Activation gates owned outside this chart¶
- Setup-role IAM grant (blocking).
durableCapture.reconciler.setupRoleAuthorizedisfalseby default and gates the reconciler'slambda add-permission(Sync hook) andlambda update-function-configuration(PostSync hook). Both hook Jobs run as the externalsyrf-ack-setup-jobrole, whose Lambda mutation scope is the exact ingress function ARNs (technical plan,syrf-ack-setup-job). Infrastructure must add the exact reconciler function ARN to that role before the flag is flipped; until then the reconciler stays unconfigured and its EventBridge rule staysDISABLED, and the chart issues no call that would fail the sync. - Secret provisioning for
durableCapture.reconciler.clientSecretName, and the Identity client whose scopes the reconciler requests, are separate prerequisites of the same activation window.
Where the durable workflow is documented¶
The cross-service workflow this slice introduces — durable S3 capture, the DynamoDB capture ledger,
scheduled reconciliation, retention cleanup and the hold-retirement outbox — is documented for future
agents in .claude/rules/pdf-agent.md (Bulk PDF / notifier
section) and .claude/rules/s3-notifier.md. The root
CLAUDE.md is deliberately an index and points at those rule files; do not restate the workflow
there.
Environment status¶
Merging this code does not establish ARRNC, storage, broker or cloud readiness. The schedule remains disabled in the chart; production capture is rejected. The activation receipt required by #3042 must be recorded by an operator during a fresh, complete zero-inventory proof window; the chart values, proof counters and authority-before-upload ordering are in Activate the Bulk PDF notifier authority. Infrastructure apply, secret provisioning, staging cutover, preview admission and production promotion retain their existing explicit gates. Do not remove expiry or activate durable takeover based on this merge alone.