Here's a question that should terrify you: When AI generates code, how do you know what it actually did?
You don't. Not really. You read the code (maybe), run it (probably), and hope nothing breaks (definitely). AI coding assistants have become remarkably good at generating plausible-looking code. They've also become remarkably good at generating plausible-looking bugs, security vulnerabilities, and architectural disasters that won't surface until 3 AM on a Sunday.
The problem isn't the AI. The problem is that AI-generated code is fundamentally unobservable. It exists. It runs. But you can't systematically verify what it's doing, track how it behaves over time, or build feedback loops that make the AI better.
We built something to fix this. And it starts with a deceptively simple idea.
The Core Insight
Every meaningful state change in any system can be expressed as:
domain.entity.action:version
Plus typed fields for context.
That's it. Four semantic components. One format. Universal applicability.
Look at a real example:
auth.user.login:1
payments.order.charged:2
ai.generation.completed:1
auth.user.login:1 is instantly understandable. No lookup table needed. No magic numbers. No "what does event type 47 mean again?" moments at 3 AM.
Why This Structure?
We didn't invent this pattern out of thin air. It emerged from studying how engineers actually think about systems. And it turns out there are exactly four questions that matter:
1. What domain are we in?
The top-level grouping. auth, payments, shipping, ai. This lets you slice your entire system by business function with a single query.
2. What thing is involved?
The entity. user, order, package, model. The noun that something happened to.
3. What happened?
The action. login, charged, delivered, trained. The verb that describes the state change.
4. Which schema version?
The version. :1, :2, :3. Because schemas evolve, and old events need to remain parseable.
This structure isn't just for humans. It teaches AI models your domain. They learn that auth contains user and session, that things can be created, failed, completed. The format itself becomes training signal.
Hierarchical Queries: The Superpower You Didn't Know You Needed
The dot notation isn't cosmetic. It's functional. Watch this:
-- All auth events
WHERE event_id LIKE 'auth.%'
-- Everything about orders, across all domains
WHERE event_id LIKE '%.order.%'
-- All failures across the entire system
WHERE event_id LIKE '%.failed:%'
Three queries. Three different cross-sections of your entire system. No joins. No complex lookups. Just pattern matching on strings.
This matters because AI-generated systems are complicated. They have dozens of components, hundreds of state transitions, thousands of potential failure modes. You need to be able to slice and dice all of that with simple, predictable queries.
The Hard Questions
Here's where things get interesting. We spent months asking: Can this model everything? Not just the easy stuff—the weird edge cases from complex event processing, quantum physics, and consciousness research.
We investigated seven categories of potentially unmodelable phenomena. Here's what we found:
| Challenge | Modelable? | Approach |
|---|---|---|
| Composite/Complex Events | Yes | Causality chains in fields |
| Non-Events (Absence) | Yes | Generated threshold events |
| Continuous Streams | Yes | Emit at semantic boundaries |
| Spatiotemporal Events | Yes | Spatial relations as fields |
| Quantum Observer Effect | Yes | Measurement IS the action |
| Recursive/Meta Events | Yes | Events about events |
| Subjective Experience | No* | Outside all observability |
*The asterisk matters. Qualia—what it's like to experience something—can't be modeled by any telemetry system. Not ours. Not anyone's. This isn't a limitation of EventIDs. It's a limitation of third-person description itself.
Example: The Car Crash Problem
Consider a complex composite event: A car tire blows out. The car leaves the road. It hits a tree. The driver is thrown from the vehicle. No single sensor detected "occupant thrown in accident"—it's inferred from multiple events combined.
How do you model this?
vehicle.occupant.thrown-in-accident:1
caused_by: [vehicle.tire.blowout, vehicle.motion.stopped, vehicle.driver.left-seat]
inference: composite
The EventID names the pattern. The fields capture causality. The system can now query for all composite events, all events caused by tire failures, all events involving driver displacement.
Example: The Non-Event
"User did NOT log in for 30 days" is meaningful. But nothing happened. How do you emit an event for something that didn't occur?
auth.user.inactive:1
last_seen: timestamp
threshold_days: 30
Absence becomes a generated event when a threshold is crossed. The system doesn't wait for something to happen—it actively monitors for meaningful non-occurrences.
Why This Changes Everything for AI
That's the problem today. And here's the solution:
+-------------------+
| Event Catalog | → The contract / source of truth
| (syntax.ai) |
+-------------------+
|
↓
+-------------------+ +-------------------+
| AI Code Gen |---->| Running System |
+-------------------+ +-------------------+
↑ |
| ↓
| +-------------------+
| | Event Stream |
| +-------------------+
| |
+-----------------------+
Feedback Loop
Here's what this enables:
- AI generates code that emits well-defined events. Not logs. Not printf debugging. Structured, typed, versioned events that match a catalog.
- Events are queryable and verifiable. "Show me all auth failures in the last hour" is a SQL query, not a grep through gigabytes of logs.
- Feedback loops become possible. "Event
auth.user.login:1fired 10x more than expected" is actionable intelligence for both humans and AI. - AI can reason about its own output in structured terms. This is the crucial part. When the AI's output is observable, it can learn from its mistakes.
The event catalog becomes:
- Spec for AI to generate against
- Contract that code must fulfill
- Observable output to verify correctness
- Training signal to improve generation
The Catalog DSL
You define events in a domain-specific language that compiles to EventIDs:
domain auth {
entity user {
event login:1 {
user_id: uuid
ip: ip_addr
method: string
}
event logout:1 {
user_id: uuid
reason?: string
}
}
entity session {
event expired:1 {
session_id: uuid
user_id: uuid
}
}
}
This compiles to: auth.user.login:1, auth.user.logout:1, auth.session.expired:1
The DSL does three things:
- Makes event definitions readable and maintainable
- Generates type-safe emitters for your language (Rust, TypeScript, Python, Go)
- Creates the schema for your event store (Postgres, ClickHouse, etc.)
The Postgres Schema
Events go into a simple table with computed columns that let you query by any component:
CREATE TABLE event_catalog (
event_id TEXT PRIMARY KEY,
domain TEXT GENERATED ALWAYS AS (split_part(event_id, '.', 1)) STORED,
entity TEXT GENERATED ALWAYS AS (split_part(event_id, '.', 2)) STORED,
action TEXT GENERATED ALWAYS AS (split_part(split_part(event_id, '.', 3), ':', 1)) STORED,
version INT GENERATED ALWAYS AS (split_part(event_id, ':', 2)::int) STORED,
description TEXT,
fields JSONB,
created_at TIMESTAMP DEFAULT now()
);
CREATE INDEX idx_domain ON event_catalog(domain);
CREATE INDEX idx_entity ON event_catalog(entity);
CREATE INDEX idx_action ON event_catalog(action);
The computed columns mean you never have to manually extract components. The indexes mean queries are fast even with millions of events. The JSONB fields column means schema evolution is trivial.
The Rust Implementation
Type safety matters. Here's the core type:
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct EventId {
pub domain: String,
pub entity: String,
pub action: String,
pub version: u8,
}
impl Display for EventId {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, "{}.{}.{}:{}", self.domain, self.entity, self.action, self.version)
}
}
From this, we generate macros that provide compile-time validation:
emit!(auth.user.login:1, {
user_id: user.id,
ip: request.ip(),
method: "oauth"
});
If auth.user.login:1 isn't in your catalog, this fails at compile time. If you forget a required field, compile error. If you pass the wrong type, compile error.
The AI can generate code that emits events. The type system ensures those events are valid. The feedback loop closes.
The Claim
Any meaningful, observable state change in any system can be expressed as domain.entity.action:version plus typed fields.
The only exception is first-person subjective experience, which is outside the domain of any observability system.
This is a strong claim. We've tested it against quantum physics, consciousness research, complex event processing systems, and edge cases from every domain we could think of. So far, it holds.
What's Next
We're building this in the open. Here's the roadmap:
- Lock down the catalog format — The DSL shown above
- Build the Rust macro — Type-safe event emitters
- Build the collector — Events → Postgres
- Build the query CLI —
syntax query --event auth.user.login:1 --last 1h - Demo the AI loop — Prompt → Generate → Run → Query → Improve
The spec is available now at /event-model/specification.html. It's dual-purpose: readable by humans, parseable by AI. The format teaches the AI what we want while documenting it for everyone else.
This Is the New Standard
For decades, we've treated observability as an afterthought. Something you add after the code is written. Something that varies from system to system, team to team, company to company.
AI changes the equation. When code is generated at scale, observability can't be an afterthought. It has to be built in from the start. It has to be standardized. It has to be universal.
domain.entity.action:version is that standard.
This article was written with AI assistance. We believe in transparency: AI helped draft, edit, and refine this content. The ideas, research, and technical decisions are human-driven, but the words were shaped collaboratively. That's the future we're building toward—humans and AI working together, with clear observability into what each contributes.
syntax.ai — The universal event model for AI-generated code.
EventIDs are the typed, queryable, verifiable syntax that makes AI-generated systems observable and improvable.
Built with conviction. Ship it.