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.