--- id: ADR-002 title: Governed execution is a responsibility chain, not a single enforcement point status: accepted date: "2026-08-23" accepted: "2026-08-29" workplan_task: REINAH-WP-0003-T01 --- # ADR-002 — Governed execution responsibility chain ## Status Accepted 2026-08-29 by operator Bernd Worsch. This is the implementation contract for `REINAH-WP-0003`. It amends the slogan wording in `INTENT.md` and ADR-001 on the same date; it does not replace ADR-001's instance/runtime split or the prohibition on tenant-held credentials and tenant-specific runtime wiring. The proposed text required sibling-owner acknowledgement before acceptance. Glas had already approved the boundary; Activity Core had deployed the queue and lease behavior it asked to see in writing. The operator accepted the substance without waiting for remaining exact-revision acknowledgements from Activity Core, sand-boxer, and llm-connect. Those recordings remain welcome; they are no longer a gate. Sibling objection still changes the matrix. ## Context ADR-001 and `INTENT.md` describe rein-aharness as the only credential holder and the only policy enforcement point for an agent session. That was a useful boundary against putting credentials or tool wiring in consuming repositories, but it is not an accurate description of the current governed chain: - Activity Core owns the claimable `ops_run`, its worker lease, and the pinned execution selector. - Glas resolves the selector to a versioned rein, model, tool, sandbox, and limit constellation, rejects blocked profiles before sandbox creation, and coordinates the outer lifecycle. - sand-boxer owns placement, filesystem/network isolation declared by its profile and extension, reachability, TTL, and teardown. - the selected rein owns its inner agent loop, backend-specific tool-policy enforcement, and session credential acquisition/injection. - OpenBao is credential custody; ops-warden catalogs credential lanes and access routes; flex-auth or the relevant authorization owner gates release. - llm-connect supplies provider-neutral model primitives and usage/error normalization. It neither stores credentials nor chooses organizational policy. At the first proposed revision of this decision, the Activity Core worker API authenticated a shared caller class while `worker_id` was request-supplied and not principal-bound. Activity Core subsequently deployed `ACTIVITY-WP-0036` at revisions `f0a897e` and `3cd5250`: `ACTIVITY_CORE_WORKER_TOKEN` is now bound to configured `ACTIVITY_CORE_WORKER_ID=rein-aharness@railiance01`; mismatched body identity and operator/SSO mutation credentials are rejected; and heartbeat, completion, and failure row-lock and reject missing, equal-to-expiry, or expired leases. The rollout has automated and live spoof-refusal evidence; a natural late-heartbeat/close production observation remains pending because no claimed row existed and no unrelated run was manufactured for the proof. Calling the rein the only enforcement point obscures these fail-closed boundaries. Calling it the only credential holder obscures custody and release authority. Conversely, moving provider or tenant credentials into Glas would violate accepted Glas ADR-002, which keeps credential resolution rein-local. The current code also has two coexistence routes. A profile-absent `ops_run` selects tenant-specific code in `approaches.py`, and issue-core/direct task-file entry points can invoke the older runtime. Neither route may become an implicit fallback from a refused profiled request. ## Decision ### 1. Strategic route The production target for unattended agentic repository mutation is: ```text Activity Core ops_run + lease -> rein-aharness queue adapter (Activity-Core-bound configured worker_id) -> Glas pinned execution profile -> sand-boxer isolated venue -> selected rein and model/provider adapter -> rein-aharness repository acceptance -> Activity Core close + durable evidence projections ``` Every production request must name a version-pinned `harness_profile_ref`. Selection is exact: no component may substitute a different profile, rein, model, tool profile, sandbox profile, credential route, or repository after emission. Catalog enablement is not runtime readiness. A Glas profile marked `blocked` must refuse before sandbox creation. An `unverified` profile is permitted only for an explicitly bounded and labelled proof; it is not a production-ready route. There is currently no committed `ready` Glas profile for rein-aharness. ### 2. Compatibility routes The following posture applies while `HARNESS-WP-0003-T04` migrates existing definitions: | Route | Supported posture | Retirement condition | |---|---|---| | Profile-absent Activity Core row | Compatibility-only for the enumerated existing FI/Binky definitions; no new tenant or approach | Each definition has a versioned profile and tenant-owned blueprint/manifest, then `ACTIVITY_CORE_REQUIRE_HARNESS_PROFILE=true` | | issue-core | External-ticket compatibility only; never the scheduled automation claim authority | All intentional external-ticket consumers use a separately owned typed adapter or are removed | | Direct task-file/CLI | Attended development and bounded smoke use; not an unattended production scheduling path | Retained only as a guarded operator/development surface after the T02/T03 repository transaction and acceptance checks are shared | A present profile reference is authoritative. Resolution refusal, sandbox failure, session failure, or teardown failure must never consult `approach_hint`, issue-core, a direct host checkout, or a legacy executor. ### 3. Responsibility and evidence matrix The owners below are authoritative for their boundary. Passing a reference or recording evidence does not transfer that authority. | Concern | Authority / enforcement | Required evidence at the handoff | |---|---|---| | Schedule and task definition | Activity Core definition owner | definition id, trigger/idempotency key, target repo, bounded task, pinned profile, allowlisted organizational refs | | Queue caller, identity, and lease | Activity Core binds the approved worker token to configured `worker_id`, rejects body/principal mismatch and non-worker mutation credentials, and rejects heartbeat/completion/failure at or after lease expiry; rein-aharness claims, heartbeats, and closes with that configured identity | caller/principal class, binding contract/version, configured and accepted worker id, ops_run id, claim owner, attempt, lease/heartbeat outcome, final queue state | | Governed actor identity | Channel/rein adapter maps this runtime to `agt`; Glas and sand-boxer validate the governed actor enum | actor plus request/run correlation; queue `worker_id` remains separate | | Organizational authority | Workforce/leadership owners upstream of Activity Core | allowlisted assignment, role, duty, goal, and resource-envelope refs; refs are attribution, not authorization | | Execution constellation | Glas profile catalog and resolver | exact profile/rein/model/tool/sandbox revisions, readiness state, resolution outcome | | Inner tool policy | Glas selects the named profile; the selected rein implements and enforces backend-specific tool mediation | selected tool profile, supported visibility level, refusal/tool summary without raw content | | Filesystem and network isolation | sand-boxer profile and extension | sandbox id, extension/profile, placement/reachability mode, declared isolation/egress posture, lifecycle and teardown outcome | | Model route and inference | Glas selects the approved model route; the rein invokes it through its backend adapter; llm-connect/provider owns portable inference mechanics | provider/model identifiers, bounded usage and normalized error; no provider body or prompt | | Credential custody and authorization | OpenBao stores values; ops-warden catalogs lanes; flex-auth or the relevant authorization owner gates release | non-secret credential-route refs, authorization decision/ref, acquisition and revocation/expiry outcome | | Credential acquisition and injection | Selected rein, following its declared credential routes; sandbox extensions separately own any provisioning credentials they require | value-free route id, injection target/lifetime, cleanup result; never a credential value | | Repository grant | Consuming repo manifest/blueprint and the emitted task/profile define the allowed repository and paths | canonical repo identity, baseline, declared path/publish grant | | Repository transaction and acceptance | rein-aharness | transaction id, lease status, baseline and accepted commits, changed paths, clean post-state, remote-ref outcome | | Sandbox execution evidence | Glas normalizes rein and sand-boxer lifecycle facts | compact `ExecutionEvidence`, including outcome/failure stage and teardown; no prompts/tool/provider bodies | | Queue result | Activity Core allowlists and stores the completion/failure envelope; it must independently enforce active ownership and an unexpired lease on heartbeat, completion, and failure mutations | terminal/reopened state, mutation acceptance/refusal reason, lease state at mutation, and normalized execution evidence | | Work history and decisions | State Hub projects progress/decision records; repository workplan files remain work authority | correlation refs and value-safe progress/decision ids | | Instance learning/metrics | Consuming repo and kaizen-agentic own the schema; T03 will choose an atomic commit or durable external projection | run/transaction correlation and reconciled projection state | The phrase “only credential holder” is therefore narrowed to: **among tenant repositories, blueprints, and scheduling records, only the selected rein may receive session credential material, and it holds that material only for the bounded session.** It does not displace the secret custodian, authorization gate, sandbox provisioning credential owner, or provider. The phrase “only policy enforcement point” is superseded by: **rein-aharness is the repository-transaction and rein-local tool-policy enforcement point within a chained grant; it must not weaken or duplicate the authorities at queue, profile, credential, sandbox, and provider boundaries.** Operator or SSO authentication is not worker mutation identity. It may cross that boundary only through an explicit, separately authorized and audited break-glass contract that records the operator principal, reason, scope, and expiry; ordinary worker calls must not inherit operator authority. ### 4. Failure classification | Failure | Current required disposition | Why | |---|---|---| | Malformed profile at definition/emission | Terminal definition error; emit no run | A retry cannot repair invalid authority data | | Unknown, disabled, incompatible, unsafe, or operationally blocked profile | Terminal claimed-run refusal; no sandbox and no fallback | Exact selection is the security boundary | | Invalid actor or incomplete/ambiguous reachability | Terminal refusal/failure; no host-checkout fallback | Actor and execution venue are governed inputs | | Sandbox create, session start/execution/end, credential acquisition, or teardown failure | Terminal profiled attempt with normalized stage evidence; no legacy fallback | Re-running may duplicate effects; a new run may be emitted after repair or explicit policy | | Claim/list transport error before ownership | Retry after the configured full polling interval | No repository work has begun | | Heartbeat rejection or confirmed lease loss | Activity Core rejects heartbeat/completion/failure at or after lease expiry; rein-aharness stops dispatch, refuses repository acceptance, cleans up, and leaves reconciliation evidence | Both queue-side mutation rejection and executor-side cancellation are required; neither boundary can substitute for the other | | Legacy executor failure | Reopen only when the typed executor explicitly marks it retryable and Activity Core attempts remain; unmatched routes are terminal | Preserves current bounded coexistence without making all errors retryable | | Required close/evidence API outage after repository mutation | Reconcile the same transaction; do not rerun or create another workload commit | Completion delivery is uncertain, not the workload outcome; T03 implements the outbox/reconciler | | Optional State Hub telemetry outage | Continue only when the event is explicitly labelled best-effort and required evidence remains durable elsewhere | Observability must not masquerade as acceptance authority | Retries after any possible repository mutation must key on the original ops run and transaction identity. A producer may create a new run after a terminal failure only through its normal idempotency and attempt policy; the harness does not reopen profiled failures itself. ## Consequences - `INTENT.md` and ADR-001 require a small wording amendment when this decision is accepted; their prohibition on tenant-held credentials and tenant-specific runtime wiring remains unchanged. - T02 must make Activity Core lease loss observable inside execution and bind a repository lock/transaction to the claimed run. - Activity Core deployed the required worker-principal/`worker_id` binding and fail-closed expired-lease mutation semantics under `ACTIVITY-WP-0036`. A natural late-heartbeat/close observation remains integration evidence for a future real claimed row, not a reason to manufacture unrelated work. - T03 must make repository acceptance and required result delivery reconcilable. Best-effort Hub telemetry is not sufficient completion proof. - T04 may migrate, but may not expand, the profile-absent compatibility table. - T05 readiness must verify the complete selected chain rather than merely catalog validation or host package installation. - T06 may use only a `ready` profile for the positive production proof. An `unverified` remote route remains a labelled proof path, not completion evidence for production readiness. ## Required acknowledgements Before changing this ADR to `accepted`, record owner acknowledgements for: - Activity Core: queue/lease/result and retry semantics; - Glas: exact selection, readiness, outer lifecycle, and rein-local credential resolution; - sand-boxer: isolation/reachability/teardown ownership; and - llm-connect: provider abstraction without credential or policy authority. Any owner objection changes the matrix before acceptance; silence is not approval. Acknowledgements received: - Glas — message `006fa46f-9419-4f61-90ff-0c3b6bc294c1`: exact selection, readiness, outer lifecycle/evidence, rein-local credential resolution, and no-fallback semantics approved with no edits. Message `9638537b-e3c3-414d-a2d7-8beab61a4e1f` reconfirms that approval against exact revision `c230f336980a9202f4d8488e81b99e8b7fb2e927` and digest `a821b29e1ed52ac57826bafe27b13e653bec761334ebde08d6bbc49d247de90b`. Reviews requiring follow-up: - Activity Core — message `428abb02-75dc-450d-a7f6-56fc715409ab`: strategic route and no-fallback posture confirmed, but acknowledgement withheld until the shared-caller/current-state limitation, principal-to-`worker_id` target, Activity-Core-side expired-lease rejection, and explicit break-glass boundary were recorded. Message `900801f4-0641-4e87-90e6-0279b6c892a6` reports those boundaries deployed at revisions `f0a897e` and `3cd5250`, with 468 tests, live spoof-refusal evidence, and no manufactured late-close run. Those facts are incorporated in this revision for final Activity Core acknowledgement. Pending as recording only, not a gate: revised Activity Core acknowledgement of this accepted text, sand-boxer, and llm-connect. Operator acceptance: Bernd Worsch, 2026-08-29, session decision to accept ADR-002 as written and proceed with T02 wiring.