rein-aharness/docs/close-evidence-outbox.md
tegwick d00ffcb402 feat(runtime): consume governed Activity Core closes
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a06ba0-10aa-7ea0-b20a-4f3fac39efe9
2026-09-04 19:54:07 +02:00

3.4 KiB

Close-evidence outbox

Status: active for profiled Activity Core terminal closes.

The outbox preserves one bounded Activity Core completion or failure intent after repository work. Replaying an outbox entry calls only the queue close adapter; it never dispatches a model, invokes an approach, or repeats repository mutation.

Storage and identity

The default root is:

$REIN_AHARNESS_STATE_DIR/close-outbox/

When that variable is absent, the harness uses $XDG_STATE_HOME/rein-aharness or ~/.local/state/rein-aharness. State lives outside target checkouts. Outbox directories are mode 0700; lock and JSON files are mode 0600.

An entry is keyed by the digest of the bounded Activity Core run_id and repository transaction_id and retains the original worker identity. Re-enqueuing the identical intent returns its existing pending or delivered state. Reusing that identity for a different worker, action, result, error, or reopen decision is a conflict and is refused.

The v1 close intent contains:

  • action: complete or fail;
  • bounded normalized JSON result evidence;
  • a caller-sanitized bounded error and explicit reopen decision for failures;
  • no prompt, provider body, credential, raw tool stream, or workload callback.

Results allow only finite JSON values, bounded depth, collection size, string length, integer range, key length, and a total encoded size of 64 KiB.

Durability and replay

Enqueue and retry-state updates use a same-directory temporary file, file fsync, atomic replace, and directory fsync under a process-safe flock. The retry attempt is durable before the delivery callback begins.

Normal callback return, including Activity Core close_disposition=applied or reconciled, marks the entry delivered and atomically moves it from pending/ to delivered/. An ordinary exception retains it in pending/ with only the exception class and a generic failure marker; exception text is not persisted. Process interrupts propagate; the already-recorded attempt remains pending. Invalid, oversized, or directory/state-mismatched records are moved intact to quarantine/ with a bounded reason sidecar and are never delivered automatically.

Activity Core refusal codes not_found, wrong_owner, expired_lease, state_conflict, evidence_conflict, and terminal_conflict are conclusive, not transient. Such entries move to quarantine rather than retrying forever. An unclassified HTTP failure or transport outage remains pending.

A network timeout may occur after Activity Core accepted a close. The worker replays pending close-only work before it claims another row. Retrying the same intent can repeat the queue request, but cannot repeat repository workload; Activity Core reconciles the exact normalized terminal repeat.

Operator controls

rein-aharness close-outbox status
rein-aharness close-outbox replay
rein-aharness close-outbox replay --limit 10

status and replay return non-zero while pending or quarantined material exists, making them suitable for readiness/recovery checks. Quarantine content and its bounded reason sidecar remain under the private state path for explicit operator inspection; it is never silently deleted or treated as delivered.

Profile-absent compatibility closes are not yet outboxed. Granted rows without an authoritative harness_profile_ref are refused before execution so they cannot cross that weaker path.