Amend A9 with state-change log conventions (issue #3)
CI / checks (push) Successful in 7s
CI / checks (pull_request) Successful in 7s

Every durable mutation emits one JSON-lines event, emitted by the
state store itself immediately after the commit returns, with a fixed
envelope (ts, agent, event, task_id correlation ID, cause) and a
dotted event taxonomy covering transitions, intents, gates, boot
reconciliation, and migrations. Logs stay diagnostic-only, never
load-bearing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
dongarandClaude Fable 5 committed 2026-09-05 19:29:27 +00:00
1 parent 99a8c7b3a2
commit 41e103c35d
1 file changed
+34
+34
View File
@@ -283,6 +283,40 @@ Requirements:
Requirements: structured logs to journald / external log stack, **not** kept
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
The durable record is a **canonical event log** in SQLite, not a provider-shaped