Status
Accepted (2026-08-23) for ACTIVITY-WP-0035.
Context
The Event Bridge principle says activity-core answers when, what, and where and does not execute domain work. Production nevertheless contains three useful operations whose complete outcome is a small scheduled maintenance action:
- ingest at most three Repo Manager-selected immutable sources into SBOM Nexus;
- prune Forgejo package versions under live-image protection; and
- invoke the fixed CNPG Option A backup tool for an explicit target list.
Historically the latter two ran through a generic shell context resolver. That made a mutating subprocess look like a read and left extension policy to convention. Removing the operations would recreate bespoke cron; accepting arbitrary shell would make activity-core a general executor.
Decision
1. Bounded operations are a narrow implementation exception
The governing when/what/where responsibility does not gain a general “how.” A bounded operation is allowed only when the operation itself is the declared automation outcome and all admission requirements below are code-reviewable.
The initial allowlist is exactly:
sbom_nexus_ingestforgejo_package_prunecnpg_option_a_backup
Adding an operation requires updating the code-owned registry, this ADR (or a successor), tests, credential route, and evidence contract. A string in a definition cannot register an operation.
2. Admission is fail closed during file sync
Each registry entry declares:
- source type and query;
- whether mutation intent is
applyordry_runand that it is explicit; - fixed or maximum target bounds;
- canonical implementation and allowed configuration;
- idempotency and Temporal retry semantics;
- maximum execution timeout;
- credential owner/route; and
- mandatory non-secret evidence mode.
Unknown shell queries are refused unless separately registered as read-only. Known operation queries with missing, malformed, or over-limit safety fields are refused before database projection or Temporal schedule reconciliation.
3. Context resolution is read-only
The workflow first resolves and freezes context. Mutations then run in an explicit bounded-operation stage and merge only normalized outcomes into the snapshot before evidence and rule/instruction evaluation.
SBOM selection remains a read in the context phase; its fixed selection is the input to the operation stage. Package prune and backup have no discovery read inside activity-core and bind a pending marker until their operation completes.
4. Retry behavior is operation-specific
- SBOM ingest uses stable per-run/per-repository idempotency keys and heartbeat checkpoints, so Activity retries resume the frozen batch.
- Forgejo prune and CNPG backup have no activity-core-verifiable remote idempotency receipt. Their operation activity therefore has one Temporal attempt; a failure remains visible for operator reconciliation rather than risking an automatic second mutation.
This does not preclude future safe retries after the platform tools expose a durable operation receipt.
5. Evidence is mandatory and bounded
Every operation must produce an allowlisted summary through a configured report/evidence sink. Raw subprocess output, tokens, provider payloads, archive URLs, kubeconfigs, and credential material are not evidence.
Rejected alternatives
- Keep mutating shell resolvers. Rejected because resolution should be a replayable read and the generic dispatcher hides mutation admission.
- Generic command activity. Rejected because command text/path from a definition is remote code execution by configuration.
- Move every operation to a rein. Rejected for these fixed platform operations; it adds an agent execution constellation without judgement or repository work. Operations that exceed this ADR's bounds do belong there.
- Remove all local operations. Rejected because it recreates scattered cron and loses Temporal/evidence guarantees for established maintenance.
Consequences
- Definition parsing gains a central operation-policy validator.
- The workflow gains an explicit operation stage.
- The generic
shellresolver becomes read-only. - Existing definitions migrate without widening targets or permissions.
- The registry is intentionally small and architectural review is required to expand it.