Add a second axis to every RFC — its class (feature, bug-fix,
simplification, architecture, process, testing) — encoded in the path
as docs/rfc/{lifecycle}/{class}/file.md. The folder is the label, so
the closed set is enforced by structure rather than a parsed field.
Two new doc-sync gates back it:
- verify-rfc-classification: every RFC sits in a valid class folder and
the README index lists it under the matching lifecycle→class heading.
- verify-doc-refs: every docs/*.md path cited in a packages|examples TS
comment resolves — closes a drift class verify-md-links can't see, and
catches the four comment refs this reorg moved.
The README gains a Classification section explaining the taxonomy and
per-class index sub-sections. A self-referential process RFC records why
the scheme is path-encoded and gated.
3.3 KiB
RFC: Fold trace-only session facts into load-bearing events
Status: proposed
Problem
The session event vocabulary includes first-class events that are not part of replayable conversation history and have little or no production consumption. usage is already present as a model stream chunk before the loop also appends a separate usage event. error duplicates the turn/end { kind: 'error', message, code } reason for loop failures; ACP settlement reads the turn-end reason, ACP rendering ignores the error event, and deriveMessages() skips it.
These events make the canonical transcript look more useful as telemetry than it currently is. They add event variants, invariants, tests, snapshots, and persistence cases, but they are not load-bearing as separate records. The facts they carry can still be useful: token usage should remain available for accounting, and an error's step number should not silently disappear. The simplification is to fold those facts into nearby events consumers already must understand, not to record less information.
Proposal
Remove standalone trace-only events only where their information can be preserved without a parallel record:
- Fold successful-step usage into the matching
assistant/message, e.g.assistant/message { turn, step, content, usage? }, so the assembled model output and its accounting travel together. - For a failed or aborted step that has usage but no
assistant/message, carry the usage on the terminal turn reason or another load-bearing failure record in the same turn. The implementing design must prove no usage chunk that is currently persisted becomes unrepresented. - Fold the step number from the standalone
errorevent intoturn/end.reasonforkind: 'error', e.g.{ kind: 'error', step, message, code? }.turn/endis the durable turn outcome ACP and resume already consume. - Keep
agent/errorand logging for live diagnostics; do not add a second session-log error record afterturn/end.
If analytics become real, add a projection helper or a dedicated telemetry store with its own retention policy. The user conversation log should contain what is needed to render, resume, audit, and account for the interaction without requiring consumers to reconcile duplicate trace rows.
Acceptance criteria
SessionEventMapdrops standaloneusageanderroronly after their fields are represented on load-bearing session events.- The loop no longer appends a separate
usageevent for a usage chunk. - The loop records durable failures through
turn/end { kind: 'error', step, message, code? }or an equivalent no-information-loss shape and reports live diagnostics throughagent/error. - ACP snapshots and persistence tests stop asserting trace-only lines.
- Documentation explains exactly where token usage and operational errors are observed.
- The session format version and recorded fixtures are refreshed; non-current stored logs are rejected per the pre-release format policy.
What we give up
A consumer can no longer filter the canonical log for standalone usage or step-level error rows. It must read those facts from the assistant/failure events that carry them. That is a reasonable simplification only if the implementing PR proves the same facts remain present; otherwise the standalone events should stay.