All writing

Agents do not see reality. They see data products.

Build an evidence pipeline that turns raw events into typed, traceable facts before an agent can retrieve or reason over them.

An agent never observes a business process directly. It receives a representation assembled from events, database records, derived metrics, and tool responses. If that representation loses time boundaries, provenance, or definitions, the model can produce a fluent answer about the wrong reality.

The remedy is to treat agent evidence as a data product with an explicit contract. Raw events remain useful for reconstruction, but the agent reads a smaller artifact whose meaning, freshness, and origin are defined before inference begins.

Separate observations from evidence

This section defines the boundary between captured activity and facts an agent may cite. The distinction prevents ingestion details from leaking into prompts and makes each transformation independently testable.

A minimal contract can make that boundary concrete:

export type RawEvent = {
  subjectId: string;
  occurredAt: string;
  receivedAt: string;
  source: string;
  payload: unknown;
};

export type EvidenceValue = string | number | boolean | null;

export type EvidenceRecord = {
  subjectId: string;
  window: { start: string; end: string };
  facts: Record<string, EvidenceValue>;
  provenance: {
    sourceKinds: string[];
    firstEventAt: string;
    lastEventAt: string;
    eventCount: number;
    transformationVersion: string;
  };
  generatedAt: string;
};

RawEvent.payload is deliberately unknown. Ingestion has confirmed that an event arrived, not that every field inside it is trustworthy or meaningful. EvidenceRecord.facts is narrower because downstream code must know which claims are safe to expose.

The window belongs in the record rather than in surrounding request metadata. A value such as activeMinutes: 42 is not interpretable without knowing which interval produced it.

Compile evidence through named stages

This section builds a transformation path that makes validation, normalization, aggregation, and policy evaluation separate operations. A single large query may be faster to write, but named stages make semantic drift harder to hide.

The first stage decides whether an observation is structurally usable. The second converts source-specific values into domain terms. The third applies a declared time window and aggregation definition. The last packages the result with provenance and a transformation version. Each stage should have one semantic responsibility, even if several run inside the same job.

Those boundaries answer operational questions that a monolithic query obscures. A malformed timestamp can be rejected without changing the aggregation rule. A new source can receive its own normalization without changing what a metric means. A definition change can receive a new version without pretending historical evidence was produced under the new rule.

The model belongs after these stages. It may interpret whether a supported pattern is noteworthy, but it should not repair malformed time data, choose an aggregation window, or invent a replacement definition when evidence is missing.

Expose evidence through a narrow tool

This section prevents the agent from querying storage structures directly. The retrieval boundary should accept domain inputs such as a subject and time window, then return either a complete evidence record or an explicit unavailable state.

That boundary is intentionally narrower than a general query interface. It prevents the model from learning table names, joining records opportunistically, or selecting whichever source happens to return data. Storage can change without changing the meaning presented to the agent.

Returning unavailable is safer than returning zeros. Zero is a factual value; unavailable means the pipeline cannot establish the fact. Useful reasons include an unprocessed window, incompatible definition version, or source delay. The agent can then explain the limitation instead of converting missing evidence into a claim.

Test semantics rather than rows

Pipeline tests should assert the meaning of an artifact, not merely that a record exists. Fix the requested window, include observations immediately inside and outside its boundaries, and verify that malformed input cannot influence the aggregate. Then check that the artifact reports the exact source coverage and definition version used.

Missing-data cases deserve separate tests. No observations, delayed ingestion, and rejected observations are different states even when none produces a metric. A contract that preserves those distinctions gives the agent less room to improvise.

The most valuable integration test feeds the same synthetic observations through both the materialized and live paths. Their evidence records should agree on values, windows, and definitions. That test catches semantic drift between implementations without coupling the article—or the architecture—to a particular repository layout.

The agent now receives a bounded statement of fact instead of an accidental projection of storage. Provenance makes the answer inspectable, while the transformation version makes historical behavior explainable after the pipeline changes.