Skip to content

Lesson 15 — Normalize events without lying ​

Outcome ​

Create a small normalized AgentEvent vocabulary with mandatory RawRef and Fact/Claim provenance.

Why this comes now ​

The UI and domain cannot understand every provider's native event names. Normalization gives Forge one language, but normalization must not erase uncertainty or invent conclusions.

Understand ​

A normalized event is a projection over retained raw evidence. Observed tool/process/file results are Facts. Agent-authored intent/conclusions are Claims. Unknown complete messages remain recoverable; unknown types that Forge would act on must fail closed. High-frequency token deltas do not automatically deserve permanent normalized rows.

Build the real project ​

  1. Define a deliberately small AgentEvent set needed by the fake: assistant message completed, tool call lifecycle, file/action fact, provider result, error, optional intent claim.
  2. Require EvidenceKind and RawRef.
  3. Persist/query normalized events.
  4. Implement adapter-to-canonical mapping for fake events.
  5. Add unknown-message diagnostic behavior.
  6. Keep live partial text as a separate transient path or clearly mark it non-historical.

Completion gate ​

Compile/tests make it difficult or impossible to create a normalized event without provenance and RawRef. Unknown action/control event does not get guessed into a known command.

Pitfalls to avoid ​

Do not create 100 canonical event types by mirroring one provider. Do not label an agent statement as an observed Fact. Do not persist every text chunk forever.

References ​

Sculptor structured integration: https://github.com/imbue-ai/sculptor/blob/main/docs/help/integrated_harnesses.md ; T3 architecture: https://github.com/pingdotgg/t3code/blob/main/docs/internals/overview.md

Checkpoint ​

M5 is complete when raw and normalized histories have clearly different responsibilities.

Forge is local-first. The docs are part of the product engineering system.