feat(runtime): enforce governed mutation boundaries

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a06ba0-10aa-7ea0-b20a-4f3fac39efe9
This commit is contained in:
tegwick 2026-09-04 11:25:07 +02:00
parent e3c6124e22
commit 20e6f381f6
28 changed files with 1068 additions and 154 deletions

View file

@ -37,8 +37,8 @@
| Task intake | `intake.py` + `taskspec.py` | issue-core GET/PATCH poll+claim; JSON task-file for local dev | NATS when activity-core migrates |
| Persona | `persona.py` | `kaizen-agentic schedule prepare` (ADR-005) | unchanged, plus phase-memory profile hook |
| Session | `adapter.py` | `AgenticClaudeCodeAdapter` (cwd-pinned, profile allow-list) | + hosted adapters |
| Orchestration | `runner.py` | profile/budget → session → commit → metrics → hub | activity-core intake |
| Metrics | `metrics.py` | ADR-004 `.kaizen/metrics` write per run | correlate with Helix fleet metrics |
| Orchestration | `runner.py` | profile/budget → transaction → session → grant acceptance → metrics → hub | activity-core intake |
| Metrics | `metrics.py` | compatibility `.kaizen/metrics`; durable external ledger for granted runs | kaizen-owned projection |
| Mail lane | `mailscan.py` | deterministic credentialed pre-step outside the session | pattern generalizes to other credentialed pre-steps |
| Hub reporting | `hub.py` | REST progress event + task close + token event | unchanged |
@ -71,7 +71,7 @@ non-interactive AppRole. See binky-control
- **Regulation:** manifest declares, harness enforces. flex-auth gates
apply at credential acquisition; ops-warden catalogs every lane; each
instance runs under a named hub identity (`agt-…`).
- **Evolution:** the harness emits `.kaizen/metrics` per run so the
- **Evolution:** the harness emits kaizen-compatible metrics per run so the
kaizen optimization loop covers both blueprints and the harness itself.
Harness releases are versioned; instances pin majors; blueprint
conformance tests run before rollout.

36
docs/external-metrics.md Normal file
View file

@ -0,0 +1,36 @@
# Durable external metrics
Repository-granted runs must not dirty a checkout after acceptance. Their
kaizen-compatible execution record and summary are therefore written beneath:
```text
$REIN_AHARNESS_STATE_DIR/execution-metrics/<repository-id>/<agent-id>/
```
When the explicit state variable is absent, the runtime uses
`$XDG_STATE_HOME/rein-aharness` or `~/.local/state/rein-aharness`. Repository
and agent directory names are SHA-256-derived identifiers rather than caller
text. Directories are mode `0700`; records and lock files are mode `0600`.
Each directory contains:
- `executions.jsonl`: append-only kaizen `ExecutionRecord` values;
- `summary.json`: regenerated aggregate metrics; and
- `projection.json`: repository id/name, agent name, and intended consuming
path `.kaizen/metrics/<agent>`.
Writes serialize on a process-safe lock. The execution record is flushed and
`fsync`ed before the summary and projection descriptors are atomically replaced
and directory metadata is `fsync`ed. Replaying the same transaction identity
regenerates the derived files without adding a duplicate ledger record. Failure
to persist this evidence makes a granted run unsuccessful; granted execution
cannot opt out with `--no-metrics`.
Projection is a separate repository mutation. This harness does not copy these
files back automatically, because doing so would invalidate the accepted clean
post-state. A future kaizen-owned projection lane may consume
`projection.json`, copy `executions.jsonl` and `summary.json` to the declared
target, and commit them under its own explicit repository grant. Until that
lane exists, the external files are the durable source of truth for granted
runs. Grant-absent compatibility runs continue to write repository-local
metrics directly.

View file

@ -1,15 +1,16 @@
# Legacy profile-absent runtime inventory
Status: preparatory inventory for `HARNESS-WP-0003-T04`
Status: active migration inventory for `REINAH-WP-0003-T04`
Captured: 2026-08-23
Captured: 2026-08-23; compatibility guard added 2026-09-04
Runtime behavior source: rein-aharness `6e0e23c`
Initial inventory source: rein-aharness `6e0e23c`; guard behavior updated in
the implementation recorded by this workplan.
This inventory records the tenant-specific execution paths selected when an
Activity Core `ops_run` has no `harness_profile_ref`. It is deliberately
read-only preparation: T04 remains `wait` until ADR-002 is accepted, and this
document neither enables a definition nor changes a production route.
Activity Core `ops_run` has no `harness_profile_ref`. It began as read-only
preparation; after ADR-002 acceptance it also records the dated compatibility
guard. This document does not itself enable a definition.
The definition state below is the committed file state in Activity Core,
freedom-intelligence, and binky-control. Live schedule projection, timer state,
@ -24,12 +25,15 @@ id, title, hint, labels, source id, and target repo.
None of the four committed definitions below declares `harness_profile_ref` or
`approach_hint`; their current route therefore depends on labels and substring
matching. A present profile ref bypasses this table and must never fall back to
it.
matching. Dispatch now additionally requires an explicit, non-expired ISO date
in `AGENT_HARNESS_LEGACY_APPROACHES_UNTIL`. Missing, malformed, or expired
values fail terminally before target resolution or executor invocation. A
present profile ref bypasses both this table and the compatibility flag and
must never fall back to either.
| Selector | Tenant coupling | Direct executor |
|---|---|---|
| `fi-research-brief` | FI labels, names, output schema, completion event, literal result repo, default push | `fi_research_brief.run_fi_research_brief` |
| `fi-research-brief` | FI labels, names, output schema, completion event, literal result repo | `fi_research_brief.run_fi_research_brief` |
| `brief-daily` | Binky labels, files, prompt/output schema, completion event, literal result repo | `brief_daily.run_brief_daily` |
| `brief-weekly` | Binky labels, milestone/RISK-005 semantics, completion event, literal result repo | `brief_weekly.run_brief_weekly` |
| `mail-scan+triage` | Binky labels, mailbox config/path, OpenBao path, report/log schema and events | `mailscan.run_mail_scan` then `mail_triage.run_mail_triage` |
@ -38,9 +42,10 @@ it.
An unmatched route fails terminally. Most matched executor failures set
`reopen=true`; an unexpected exception also reopens. Activity Core applies its
attempt limit, but the harness currently has no shared repository transaction
identity with which to distinguish a safe retry from a repeat after partial
mutation.
attempt limit. The harness now records a repository transaction identity, but
Activity Core does not yet carry an accepted repository grant or reconcile a
response-lost terminal close, so a retry after ambiguous completion remains a
T03 gate.
## Scheduled definitions
@ -55,13 +60,13 @@ mutation.
| Model/credential lane | HTTP `LLM_CONNECT_URL`; model from `FI_RESEARCH_BRIEF_MODEL`, then Binky-named `BRIEF_DAILY_MODEL` / `MAIL_TRIAGE_MODEL`; provider credential remains behind llm-connect |
| Output | `briefs/YYYY/MM/YYYY-MM-DD.md`; model JSON is rendered deterministically |
| Repository mutation | Stages only the brief path and creates one local commit |
| Publication | **Pushes `origin HEAD` by default** unless `FI_RESEARCH_BRIEF_PUSH` is false; push failure is swallowed and the run remains successful |
| Publication | Local commit only. The former `FI_RESEARCH_BRIEF_PUSH` path was removed 2026-09-04; publication requires a separate owner/grant. |
| Completion | Best-effort State Hub `fi_daily_brief` with path/date/candidate count; `fi_brief_status` uses it to clear due state |
| Failure/retry | Normal generation/commit failure reopens; an existing daily path succeeds idempotently |
| Current rollback material | Disable/pause the Activity Core definition. FI documents a disabled 07:35 host timer as break-glass, but its installer still enables that timer and must not be invoked casually |
Migration must remove the implicit push. Publication, if still needed, becomes
a separately named and granted capability with remote-ref and result evidence.
Publication, if still needed, must become a separately named and granted
capability with remote-ref and result evidence.
The Binky-named fallback model environment variables must not survive in an FI
owned declaration.
@ -148,15 +153,17 @@ a repository transaction or remote-ref check.
2. **Tenant code in the shared runtime:** prompts, output schemas, file paths,
event types, FI publication, Binky risk logic, mailbox paths, and
credential lanes require edits to rein-aharness.
3. **No shared repository transaction:** dirty baselines, partial writes,
unexpected commits/paths, lease loss, and retries after mutation are not
bounded. T02/T03 remain prerequisites for any retained direct executor.
3. **Queue acceptance is incomplete:** T02 now bounds dirty baselines,
transaction identity, and lease-loss cancellation, and local granted tasks
have T03 acceptance. Activity Core still lacks authoritative grant carriage
and terminal-close reconciliation for queued execution.
4. **Required evidence is best-effort:** Hub delivery failure does not fail or
reconcile a run even though the due resolvers depend on those events.
5. **Completion meanings diverge:** mailbox scan and triage have different
events, while the Activity definition describes one intake task.
6. **Publication is implicit in FI:** default push plus swallowed failure cannot
meet an explicit grant/evidence contract.
6. **FI publication is now separated:** the compatibility executor is
local-commit-only; any future publish lane still needs an explicit owner,
grant, and evidence contract.
7. **Mutable sibling/runtime dependencies:** mail scan defaults to a sibling
email-connect checkout, and model selection depends on process environment
rather than a versioned execution declaration.
@ -169,8 +176,9 @@ a repository transaction or remote-ref check.
This sequence is preparatory and does not choose a profile or capability owner
before ADR-002 acknowledgement.
1. Land T02/T03 repository transaction, lease-loss, acceptance, and evidence
reconciliation for any compatibility executor that remains callable.
1. Carry T02's transaction/lease evidence and T03's repository grant through
Activity Core, then activate reconciled close evidence for any compatibility
executor that remains callable.
2. For each scheduled definition, obtain an owner-approved declaration of the
exact input schema, allowed paths, model route, credential route, completion
event, commit policy, publication policy, and rollback.
@ -184,6 +192,6 @@ before ADR-002 acknowledgement.
5. Enable the replacement, verify the due resolver and durable evidence, then
remove that definition from substring routing.
6. After all four definitions migrate, enable
`ACTIVITY_CORE_REQUIRE_HARNESS_PROFILE=true` for governed execution, delete
`_DEFINITION_HINTS` and tenant approach rules, and reconcile or retire the
tenant host timers.
`ACTIVITY_CORE_REQUIRE_HARNESS_PROFILE=true` for governed execution, remove
`AGENT_HARNESS_LEGACY_APPROACHES_UNTIL`, delete `_DEFINITION_HINTS` and
tenant approach rules, and reconcile or retire the tenant host timers.

View file

@ -38,6 +38,7 @@ the legacy coexistence path until the migration flag is enabled upstream.
| `AGENT_HARNESS_OPS_LABELS_MODE` | `any` | `any` or `all` |
| `AGENT_HARNESS_OPS_LEASE_SECONDS` | `900` | claim lease |
| `AGENT_HARNESS_CLAIM_INTERVAL` | `30` | empty-queue poll interval |
| `AGENT_HARNESS_LEGACY_APPROACHES_UNTIL` | unset | ISO expiry date required for profile-absent compatibility routing |
| `AGENT_HARNESS_REPO_MAP` | `{}` | JSON slug→checkout path |
| `AGENT_HARNESS_REPO_ROOTS` | `~:~/work` | slug search roots |
@ -48,6 +49,7 @@ export AGENT_HARNESS_REPO_MAP='{
"freedom-intelligence":"/home/tegwick/freedom-intelligence",
"binky-control":"/home/tegwick/binky-control"
}'
export AGENT_HARNESS_LEGACY_APPROACHES_UNTIL=2026-12-31
export ACTIVITY_CORE_URL=http://127.0.0.1:8010 # or ClusterIP via tunnel
export ACTIVITY_CORE_WORKER_TOKEN=… # from actcore-runtime-secret
```

View file

@ -1,6 +1,7 @@
# Repository grant contract
Status: **v1 parsed, validation-ready, not execution-enabled**.
Status: **v1 enabled for local `TaskSpec` files; queued/profiled carriage is
not yet available**.
`repository_grant` is the explicit authority envelope for a bounded local Git
mutation. It is separate from task prose, labels, organizational attribution,
@ -39,20 +40,28 @@ The repository acceptance validator converts the grant into the policy used to
check descendant commits, changed paths, clean post-state, protected Git
metadata, and local remote-tracking refs.
## Current fail-closed posture
## Current execution posture
`TaskSpec.from_file` parses this contract, but `run_task` deliberately refuses
any task that supplies it before adapter dispatch. The Activity Core and
issue-core adapters do not currently populate it. Existing grant-absent direct
and compatibility runs retain their prior behavior while the transaction path
remains production-inert.
`TaskSpec.from_file` parses this contract and `run_task` executes it under the
canonical repository transaction. A successful adapter result is accepted only
when the commit ancestry/count, changed paths, clean post-state, protected Git
metadata, and remote-tracking refs satisfy the exact grant. The result carries
bounded grant, baseline, policy, commit, and path evidence without raw grant
paths, prompts, or provider output.
Execution may be enabled only after:
Granted runs require durable external metrics and refuse `--no-metrics`. Their
metrics are written outside the checkout only after acceptance, so a successful
run remains clean. See [external-metrics.md](external-metrics.md).
Activity Core and issue-core adapters do not populate `repository_grant`.
Queued/profiled runs therefore cannot claim repository acceptance under this
contract. Existing grant-absent direct and compatibility runs retain their
legacy `HEAD`-changed behavior during migration.
Queued/profiled execution may use this contract only after:
1. an authoritative Activity Core/profile field carries the reviewed grant;
2. the lease-bound transaction wraps adapter dispatch and result close;
3. the runner validates the accepted result against this exact grant; and
4. required close evidence durably records the grant, transaction, and accepted
2. required close evidence durably records the grant, transaction, and accepted
result identities.
Task descriptions, labels, `execution_refs`, consuming-repo defaults, and