diff --git a/workplans/ADHOC-2026-06-01.md b/workplans/ADHOC-2026-06-01.md new file mode 100644 index 0000000..1f83418 --- /dev/null +++ b/workplans/ADHOC-2026-06-01.md @@ -0,0 +1,82 @@ +--- +id: ADHOC-2026-06-01 +type: workplan +title: "Ad hoc — activity-core opportunistic fixes 2026-06-01" +domain: custodian +repo: activity-core +status: ready +owner: custodian +topic_slug: custodian +created: "2026-06-01" +updated: "2026-06-01" +state_hub_workstream_id: "36162ff0-9b47-47c4-8602-56767f9b7a1c" +--- + +# ADHOC-2026-06-01 — activity-core opportunistic fixes + +Captured during the CUST-WP-0045 T06 cutover prep session. The dev worker was +brought up and surfaced an unrelated, pre-existing bug in the state-hub +context resolver that is independent of the daily triage canary. + +## Tasks + +### T01 - Fix repo_sbom_status resolver route and params + +```task +id: ADHOC-2026-06-01-T01 +status: todo +priority: low +state_hub_task_id: "87b56da9-e692-4350-9aff-47080414ec06" +``` + +`src/activity_core/context_resolvers/state_hub.py` resolves +`query: repo_sbom_status` by calling `GET /sbom/status?repo={repo_slug}`, but +State Hub does not expose `/sbom/status` at all. Actual SBOM routes are +`/sbom/`, `/sbom/{repo_slug}`, `/sbom/snapshots/`, `/sbom/snapshots/{id}`, +`/sbom/ingest/`, `/sbom/report/licences/`. + +Compounding bug: the only ActivityDefinition using this query is +`activity-definitions/weekly-sbom-staleness.md`, which passes +`params: { repos: all }`. The resolver reads `params.get("repo_slug", "")`, +so the lookup URL collapses to `/sbom/status?repo=` regardless of the +ActivityDefinition value. + +Symptom: every Monday at 09:00 Europe/Berlin (and on worker startup after a +missed Monday tick), the `weekly-sbom-staleness` workflow runs and the +resolver logs `HTTP/1.1 404 Not Found` for `GET /sbom/status?repo=`. The +`_fetch_json` helper swallows the error and returns `{}`, so the workflow +continues but the downstream rule evaluates +`context.repos.sbom_age_days > 30` against an empty dict and never spawns +the intended SBOM rescan tasks. The weekly SBOM staleness check has been +silently no-op for as long as this route mismatch has existed. + +Fix scope: + +1. Decide the contract — single-repo lookup (current parameter shape suggests + this) versus multi-repo bulk lookup (`repos: all` suggests this). +2. Update the resolver to call the actual State Hub route(s): + - single repo: `GET /sbom/{repo_slug}` (or `/sbom/{repo_slug}/status` if a + status-shaped projection is preferred and exists). + - bulk: iterate the State Hub `/repos/` list and call `/sbom/{repo_slug}` + per repo, returning a list bound to `context.repos`. +3. Update `activity-definitions/weekly-sbom-staleness.md` to match: either pass + a real `repo_slug` per definition (multiple definitions, one per repo) or + keep `repos: all` and let the resolver fan out. +4. Update the rule expression to traverse the resulting shape — currently + `context.repos.sbom_age_days` assumes a single object; if the resolver + returns a list, the rule needs `any(repo.sbom_age_days > 30 for repo in + context.repos)` or an equivalent per-repo evaluation. +5. Add a resolver unit test that asserts the resolver hits a route State Hub + actually serves, and an integration test against a fixture State Hub + response so this regression cannot repeat. + +Out of scope for this adhoc: + +- Decoupling SBOM staleness rules from the state hub resolver. +- Rewriting the SBOM ingestion pipeline or `sbom_source` policy. +- Promoting this to a full workplan unless the multi-repo decision turns out + to need design discussion. + +Done when `weekly-sbom-staleness` runs cleanly against a live State Hub on +Monday and either spawns SBOM rescan tasks for stale repos or leaves a clear +"all SBOMs fresh" audit row — not a 404 log line and a silent no-op.