Amend A9 with state-change log conventions #4

Merged
dongar merged 1 commits from logging-conventions-a9 into main 2026-09-05 21:10:20 +00:00
+34
View File
@@ -283,6 +283,40 @@ Requirements:
Requirements: structured logs to journald / external log stack, **not** kept Requirements: structured logs to journald / external log stack, **not** kept
in-container. Every gate crossing, tool call, and escalation is logged. in-container. Every gate crossing, tool call, and escalation is logged.
**State-change log conventions.** Every durable mutation of agent state emits
exactly one structured log event, so problems can be diagnosed after the fact
by replaying the operational trail:
- **Emission is owned by the state store.** The log line is written by the same
code path that performs the durable write, immediately after the commit
returns — a state-change line exists iff the change hit disk. Callers supply
the *cause*; no other layer logs durable mutations, so the trail cannot drift
from what was persisted.
- **Format: one JSON object per line**, with a fixed envelope on every event:
- `ts` — UTC ISO-8601 timestamp
- `agent` — `nisse-dev` | `nisse-ops`
- `event` — dotted type from the taxonomy below
- `task_id` — correlation ID for the enclosing unit of work, minted when the
unit starts (`use <project>`, milestone start, ticket pickup) and threaded
through every event it causes; `null` only outside any unit (e.g. boot).
- `cause` — what triggered the mutation: operator command, approval
(`rev-N` + channel), escalation trigger, reconciliation verdict, or crash
recovery.
- **Event taxonomy** (extended as components are built; names are never reused
or renamed):
| Event | Event-specific fields |
|---|---|
| `state.transition` | `from`, `to`, `project` |
| `intent.begin` / `intent.commit` / `intent.abort` | `intent_id`, `kind` |
| `gate.open` / `gate.approve` / `gate.reject` | `gate`, `rev`, `channel` |
| `boot.reconcile` | `action`, per-intent verdicts |
| `schema.migrate` | `from_version`, `to_version` |
- **Logs are diagnostic, never load-bearing.** Nothing reads logs back to
derive state — the state store (A2) is the sole source of truth, the same
rule that keeps Matrix room history (A1) non-authoritative.
### A10. Canonical Transcript Schema ### A10. Canonical Transcript Schema
The durable record is a **canonical event log** in SQLite, not a provider-shaped The durable record is a **canonical event log** in SQLite, not a provider-shaped