feat(ops-run): carry harness_profile_ref and attribution refs
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 0s
Build and Publish Container Image / build-and-push (push) Successful in 19s

ACTIVITY-WP-0032-T02 / ACT-ADR-006. ops_runs grows harness_profile_ref (text,
indexed) and execution_refs (jsonb), migration 0008, threaded through the
emission path, queue projection, and run artefacts.

The important part is the enforcement, not the columns. ACT-ADR-006 says
approach_hint must never override, synthesize, or fall back from an absent or
invalid harness_profile_ref — a silent fallback would reintroduce the
claim-time routing failure of 2026-08-17. resolve_execution_selector never
consults the hint: a malformed ref raises even when a hint is present, and
ACTIVITY_CORE_REQUIRE_HARNESS_PROFILE turns an absent ref into an error once
definitions have migrated.

Validation is structural only, since the glas-harness catalogue is
authoritative and must not be mirrored. Requiring the <id>@<version> pin is
worth doing locally: GlasProfiles.resolve matches an unpinned ref against every
version and refuses it as ambiguous, so the pin converts a late failure into an
emission-time error without knowing any profile id.

Migration verified on real PostgreSQL 16: upgrade, downgrade, re-upgrade, and a
legacy-shaped row still inserts and stays claimable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tegwick 2026-08-21 14:14:08 +02:00
parent 1c4b3c592c
commit 5bd0ee5ff9
10 changed files with 428 additions and 7 deletions

View file

@ -26,7 +26,9 @@ workplan task file. Not an issue-core or Forgejo ticket.
| `source_type` | text | rule \| instruction |
| `source_id` | text | Rule id |
| `triggering_event_id` | text | Event or workflow key |
| `approach_hint` | text nullable | Optional from rule |
| `approach_hint` | text nullable | **Legacy** definition-matching hint (ACT-ADR-006) |
| `harness_profile_ref` | text nullable | Authoritative execution selector, pinned `<id>@<version>` |
| `execution_refs` | jsonb | Attribution refs carried through, not authored here |
| `result` | JSONB | Completion metadata |
| `created_at` / `updated_at` | timestamptz | |
@ -134,3 +136,32 @@ completion event (`fi_daily_brief`, etc.).
| Multi-day engineering tasks | Workplan files + State Hub |
| External tracker tickets | issue-core → **Forgejo** (optional projection) |
| Schedule truth | Temporal + activity definitions |
## Execution selection (ACT-ADR-006)
`harness_profile_ref` names an approved, **version-pinned** glas-harness profile
(e.g. `harness.agent-dev-local@1.0.0`). The claiming executor passes the queued
request into Glas, which resolves or refuses it **before sandbox creation**.
`approach_hint` and `harness_profile_ref` coexist with **distinct semantics**:
- `harness_profile_ref` is the authoritative execution-constellation selector.
- `approach_hint` is a legacy definition-matching hint only. It must **never**
override, synthesize, or fall back from an absent or invalid profile ref. A
malformed ref is an error at emission, not an invitation to route on the hint.
activity-core does **not** mirror the glas-harness profile catalogue — it is
authoritative there, and Glas exposes no network validation service. So we
validate structure only (present, no whitespace, `<id>@<version>` pinned). The
pin matters: `GlasProfiles.resolve` treats an unpinned ref as matching every
version and refuses it as ambiguous, so requiring the pin locally converts a
late failure into an emission-time error without knowing any profile id.
A well-formed but *unknown* profile is still caught by the execution-side Glas
resolver rather than at emission. That residual gap is accepted and recorded in
ACT-ADR-006; closing it needs a scoped glas-harness API, not a local catalogue.
`ACTIVITY_CORE_REQUIRE_HARNESS_PROFILE=true` makes a missing profile ref an
error. It stays off during coexistence while definitions adopt refs one at a
time; turn it on once no caller depends on `approach_hint` for routing.