activity-core/docs/adr/adr-006-glas-profile-execution.md
tegwick 26934e25b9
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Build and Publish Container Image / build-and-push (push) Successful in 21s
Enforce bounded operation guardrails
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a028de-e2c8-7732-8521-46a7fc5db82f
2026-08-23 12:31:13 +02:00

142 lines
5.9 KiB
Markdown

---
id: ACT-ADR-006
type: architecture-decision-record
title: "Profile-driven execution selection over the ops_run pull queue"
status: accepted
owner: activity-core
revision: "accepted-1"
last_reviewed: "2026-08-21"
review_interval: 6m
decided_by: Bernd Worsch
date: "2026-08-21"
scope: cross-repo
affects:
- activity-core
- glas-harness
- rein-aharness
- sand-boxer
tags:
- architecture
- activity-core
- ops-run
- glas-harness
- execution
supersedes_notes: >
Extends ACT-ADR-005. Does not change the ops_run claim/lease plane; it
changes what a queued run says about how it should execute.
---
# ACT-ADR-006: Profile-driven execution selection over the ops_run pull queue
## Status
**Accepted** (2026-08-21). Hub decision `147beec6-7fe7-4837-8e3a-4264a240379d`
("Glas contract 1.0 makes execution constellation selection explicit").
## Context
ACT-ADR-005 gave internal scheduled automation a claimable `ops_run` plane.
What an ops_run said about *how* to execute was `approach_hint` — free text,
interpreted by the claiming executor at claim time.
That binding is too late. Live failure, railiance01 2026-08-17:
```
state=failed attempt=1 claim_owner=rein-aharness@railiance01
title=Run SBOM rescan for binect-js
failure=no approach matched labels/definition;
labels=['sbom','security','automated']
```
The run was claimed and leased, *then* died because nothing could execute it.
A claim was consumed to discover the request was unroutable.
`glas-harness` GLAS-WP-0004 closed contract 1.0 and proved it by running one
bounded task through two different reins (`rein-aharness`, `rein-openweights`)
via an explicit `harness_profile_ref`, with real commits and verified sandbox
destruction. Meanwhile every activity-core claim in the week to 2026-08-21 was
`rein-aharness@railiance01` — a coupling that is now avoidable rather than
inherent.
Two shapes were considered: keep the pull queue and carry the profile as
payload, or have activity-core call the Glas gateway directly. glas-harness,
which owns the contract, advised the first for the initial migration.
## Decision
### 1. The queue stays; the payload changes
activity-core continues to insert `ops_run(open)` and executors continue to
claim under lease. Scheduling topology does not change. What changes is that a
queued run carries an exact **versioned `harness_profile_ref`** plus the
correlation / assignment / role / duty / goal / resource-envelope references.
The claiming executor passes that request into Glas, which resolves or refuses
it **before sandbox creation**.
This changes the execution contract without simultaneously changing the
scheduling topology — one variable at a time. A direct activity-core → Glas
call may be evaluated later, independently, if pull delivery stops meeting
operational needs.
### 2. `harness_profile_ref` is authoritative; `approach_hint` is legacy
The two coexist with **distinct semantics**, not as fallbacks for one another:
- `harness_profile_ref` is the authoritative execution-constellation selector.
- `approach_hint` remains only a legacy activity/definition-matching hint while
producers and consumers migrate.
`approach_hint` must **not** override, synthesize, or fall back from an absent
or invalid `harness_profile_ref` on governed execution. A missing profile is an
error, never an invitation to guess from a hint. Once inventory shows no caller
depends on `approach_hint` for runtime selection, that use is deprecated.
### 3. activity-core does not mirror the profile catalog
The catalog in glas-harness is authoritative. activity-core must not maintain
an independent list, which would drift and produce a second, disagreeing
opinion about what is executable.
Consequence, accepted knowingly: Glas exposes deterministic validation through
its package and CLI but **no network validation service** today, so
activity-core cannot remotely validate a profile ref at emission time. We
therefore validate only what is local and structural — that a ref is present
and well-formed for governed execution — and rely on the **execution-side Glas
resolver as the mandatory fail-closed check**.
This is weaker than refusing at emission, and deliberately so: an unreachable
or absent validation service must never downgrade into "emit anything". If
emit-time remote validation is later required, it needs a separately scoped
Glas API and its own decision — not a mirrored catalogue here.
Even unvalidated at emit, this is strictly better than the 2026-08-17 failure:
refusal happens deterministically before sandbox creation rather than after a
claim and lease were consumed.
### 4. activity-core does not become an executor
We emit an authorized, profile-named request and record normalized evidence.
We do not select reins, provision sandboxes, acquire credentials, or run any
inner agentic loop. Glas owns profile resolution and the outer loop; the rein
owns its inner loop; `sand-boxer` owns isolation. This is SCOPE drift risk #1
("convenience execution") and this ADR does not relax it.
The attribution references we carry (`assignment_ref`, `role_ref`, `duty_ref`,
`goal_refs`, `resource_envelope_refs`) are **passed through**, not authored
here. Their vocabulary belongs to `info-tech-canon`; activity-core must not
invent org roles (ACTIVITY-WP-0029 responsibility map).
ACT-ADR-007's bounded-operation exception does not alter this decision. A
code-registered fixed maintenance operation is not a Glas/rein execution
constellation, and the exception cannot be used to run an agent loop or execute
an `ops_run` inside activity-core.
## Consequences
- `ops_runs` grows `harness_profile_ref` and the attribution refs; the emission
path, queue projection, and run artefacts carry them.
- Definitions declare a profile; rules pass it through.
- Unroutable requests fail before sandbox creation instead of at claim time.
- activity-core is no longer coupled to one rein in practice.
- Emit-time validation remains a known gap, owned by a future Glas API.
- Implementation: **ACTIVITY-WP-0032**.