Facts as First-Class Citizens

Post 2 · Phase 1 — Facts

Most programming languages start with data structures.

We define classes, structs, records — and then write functions that manipulate them.

This works well for computation. But when we try to model a real-world domain, something subtle breaks down.

The Shape of a Domain

Consider a simple statement:

Alice owns a car.

In most programming languages, this becomes something like a field on an object, a row in a database, or a key-value relationship.

But these representations hide something important: the fact itself is not first-class.

It is encoded indirectly — as a mutable field, as a database entry, as an implicit assumption in code.

And because of that, we lose clarity, composability, and the ability to reason about the domain directly.

A Different Starting Point

Approaches like Object-Role Modeling (ORM2) take a different view.

Instead of starting with objects and attributes, they start with facts:

Facts are explicit, structured, and close to how we naturally describe systems.

This makes them easier to validate with domain experts, reason about, and evolve over time.

From Modeling to Programs

Spine takes inspiration from this perspective, but explores a different direction.

What happens if facts are not just part of a model, but part of a program?

In Spine, facts are not just documentation or schema. They are elements that can be declared, composed, constrained, and used directly in defining system behavior.

The Asset System

To make this concrete, we will use a simple running example throughout these posts: the Asset System.

At its core, it describes relationships between agents and assets.

We might start with facts like:

These are not yet actions or computations. They are simply statements about what can be true in the system.

Facts Before State

In many systems, we would model ownership as a field:

asset.owner = agent

But this introduces several issues: ownership becomes tied to a specific representation, constraints are implicit, and changes are modeled as mutations.

In a fact-based approach, we instead express:

Owns(Agent, Asset)

This may seem like a small shift, but it has important consequences:

Constraints as Part of the Model

Once facts are explicit, constraints become natural.

For example:

These are not comments or external validations. They are part of the system itself. They define what it means for a state of the system to be valid.

Composability of Facts

Because facts are first-class, they can be combined and extended.

We might later introduce:

These can relate to existing facts: ownership may imply control, delegation may depend on ownership.

The important point is: we are building a network of relationships, not a hierarchy of objects.

Toward Behavior

So far, we have only described structure: what exists, what relationships can hold, what constraints apply.

But systems do not stand still. They evolve.

Ownership can change. Assets can move. Permissions can be granted or revoked.

In the next step, we will introduce rules that describe how facts can change — and how valid states of the system transition into other valid states.

A Subtle Shift

At first glance, treating facts as first-class elements may seem like a small change.

In practice, it shifts the perspective from manipulating data structures to describing systems in terms of what is true about them.

This shift will allow us to define behavior in terms of constraints, make effects explicit, and eventually reason about entire systems.

Looking Ahead

In the next post, we will extend the Asset System with simple rules: how ownership can be transferred, and what must hold before and after such a change.

This will move us from describing a system to describing how it evolves.

And as we do so, the role of facts will become even more central: they are not just data — they are the foundation on which everything else is built.

← Previous: Programming Reality Next: A Small Spine Program →