--- id: ACTIVITY-WP-0033 type: workplan title: "Bound SBOM catch-up across Temporal retries" domain: infotech repo: activity-core status: finished owner: codex topic_slug: infotech created: "2026-08-22" updated: "2026-08-22" related: - ACTIVITY-WP-0030 - CUST-WP-0062 - SBOM-WP-0002 state_hub_workstream_id: "6f106471-010d-5039-9779-d3d630693827" --- # Bound SBOM catch-up across Temporal retries ## Goal Preserve ACTIVITY-WP-0030's oldest-N bound when Temporal retries an activity or an SBOM Nexus response is ambiguous. Activity Core can independently guarantee that one workflow fire retains one fixed set of at most N distinct repository targets. Exact once-only snapshot creation remains a Nexus-side idempotency follow-up. ## Separate selection from mutation ```task id: ACTIVITY-WP-0033-T01 status: done priority: high state_hub_task_id: "c6cd06d6-6cde-50a3-8b66-e930b228579d" ``` Keep `resolve_context` and the `sbom-nexus / catch_up` resolver read-only even when the definition declares `apply: true`. Compute the deterministic run id before context resolution, then pass the already-truncated selection to a dedicated Temporal activity. Retries must reuse that same selection rather than querying the next batch. ## Resume bounded outcomes safely ```task id: ACTIVITY-WP-0033-T02 status: done priority: high state_hub_task_id: "b85a95c4-ce57-5bcd-ae7c-50e5defcd0f1" ``` Heartbeat completed per-repository outcomes so an ordinary activity retry does not repeat acknowledged targets. Send a stable per-run/per-repository `Idempotency-Key` for forward compatibility with Nexus enforcement. Never turn an HTTP timeout, transport error, or malformed success response into a second synthetic skip: the result is ambiguous and must fail visibly against the same fixed target set. ## Verification and handoff ```task id: ACTIVITY-WP-0033-T03 status: done priority: medium state_hub_task_id: "bc16f4af-48dd-513a-9fa8-78f322cbdaef" ``` Cover read-only selection, fixed-target retry, heartbeat resume, duplicate target collapse, stable request identity, and ambiguous-response behavior. Update the runbook and hand the remaining exactly-once enforcement requirement to SBOM Nexus without claiming it is solved locally. Completed 2026-08-22. `resolve_context` now only selects and normalises a deduplicated oldest-N set. `RunActivityWorkflow` records that selection before calling the registered `apply_sbom_catchup` activity, protected by Temporal patch marker `activity-wp-0033-sbom-retry-boundary`. The apply activity resumes terminal outcomes from heartbeat details and sends a deterministic UUID operation key for each workflow-run/repository pair. Ambiguous HTTP and contract failures remain failures against the same fixed target instead of creating `ingest-error` skip snapshots. Verification: 27 focused SBOM tests and 417 repository tests passed; the one live NATS-to-Temporal bridge test was deselected because it requires the local integration stack. Python compilation and `git diff --check` also passed. ## Acceptance - [x] Context resolution performs no SBOM mutation - [x] One workflow fire retains at most N distinct targets across retries - [x] Heartbeat replay skips outcomes already acknowledged by the activity - [x] Ambiguous ingest responses do not create synthetic skip snapshots - [x] Stable operation identity is sent for future Nexus enforcement - [x] Focused and repository-wide Activity Core verification pass