91 lines
3.1 KiB
Markdown
91 lines
3.1 KiB
Markdown
|
|
---
|
||
|
|
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
|
||
|
|
---
|
||
|
|
|
||
|
|
# 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
|
||
|
|
```
|
||
|
|
|
||
|
|
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
|
||
|
|
```
|
||
|
|
|
||
|
|
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
|
||
|
|
```
|
||
|
|
|
||
|
|
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
|