Case study #0001

The blueprint comes first, and the world is a layer over it

by Vidal Vasconcelos

How a system begins as one page naming what it holds and what it needs from the world, and how declaring each need as a shape with a default lets the real thing be swapped in by one line, so a feature ships before the world is ready for it.

← Back to the studio

Context

The system the studio took into the lab reads the work a small group of people did over a stretch of time and hands whoever leads them a word for how the stretch went, so that a conversation can start at the interesting part. Before there was a line of it there was a page, and the page was the blueprint.

The first half of the page is the domain, and it is short. There is one kind of thing the system holds, whatever its origin, a thing that happened in the tools people work in, a link somebody pasted, a note written in a conversation. There is a small fixed set of aspects each of those can speak to. There is what it says about that aspect, good, bad, or nothing. There is the stretch since the last conversation, and the checkpoint that closes it. And there is the word the arithmetic makes of a stretch, one of five. The page also makes the first modular cut, in the domain itself, by saying that the formulas are the same everywhere and the variables belong to each group of people who use it.

The second half is what the system needs from the world, the capabilities. It needs a place to keep what happened. It needs a way to hear what the tools people work in have to say, and a way to ask them. It needs a way to send a letter, a way to know who is signed in, and, once the studio had an operator's side of its own, a way for that side to reach in. Each of those is named on the page as a need with a shape, the few things the system will ever ask of it, before anybody has decided what will stand behind it. You could have started from the other end, and most systems do, a screen first and the domain arriving afterwards as the sum of whatever the screens turned out to need. This one is about the pace of feedback between two people, and a screen of numbers would have made it about something else without anybody deciding that it should.

The default writes every letter in full and logs it in place of sending it, so a product runs without a transport and a letter never vanishes without a trace. Sending is an override an app binds over this, since only an app holds the transport.

Decision

The studio writes in TypeScript with Effect, and what Effect gives this way of working is a place to put the second half of the page. A capability is declared as a service, which is a name and a shape. The shape is the handful of operations the rest of the system may ask of it, with the errors each one may fail with written into its type, so a function that needs the postbox says so in its signature and a function that might fail to deliver a letter says that too. Everything downstream depends on the shape and never on the thing behind it. There is no model in the system, and the arithmetic that turns what happened into a word is one of those shapes like any other, a rule the screens import and never reimplement.

Every service carries a default, and the default is the version that lets the system run with nothing bound. The postbox writes every letter in full and logs it in place of sending it. The gateway the operator's side reaches through answers from memory, with a synthetic person it lets in and a synthetic group for them to lead. The sign-in, run with no identity provider behind it, invents that same person. None of these is a stub in the testing sense. They are the system, running on a laptop with no account at any cloud and no key in any file, and they are what somebody sees the first time the operator's screens open in a browser.

The real thing is a layer, and a layer is the piece that says how a shape is satisfied in one deployment. One deployment binds a layer over the postbox that hands the written letter to a mail service, and a layer over the store that speaks to a database, and the operator's deployment binds a layer over the gateway that calls the real system over a binding between two workers, decoded with the same schemas both ends were cut from. Layers compose the way the page composes. The router that answers the operator's screen is provided the session layer and the gateway layer, and the gateway layer is provided the binding, so the wiring reads as the blueprint did, a shape, and under it what stands behind the shape here. Swapping one is a line in that wiring. Locally the operator's screens run on the in-memory gateway under one flag, deployed they run over the binding, and a test hands the postbox a transport that collects letters in a list. The routes are the same code in all three.

Consequences

This is where the quick deliveries come from. Six letters were wired end to end, written, set in the system's own stationery, logged with their subject and text, before a mail service existed on the account, and when the binding arrives it is one layer over a shape nothing else has to learn about. The operator's screens are built, run and shown against the in-memory gateway with nothing running behind them, which is how they run on a laptop every day. The launch door was built as a state on the account and can be walked through with the synthetic person, who arrives already let in, with no identity provider in the room. A feature ships when its shape is satisfied by any layer, and the real layer follows when the world is ready, which is a different order from waiting for the world and then building.

The same shape is what makes building with AI fast without making it loose. An agent writing against a named service has a contract to write against, the shape and its typed errors, and the compiler and the tests hold it to that contract in the same breath as they hold a person. Where AI sits in this system is there, in how it was built, and not in what it does to anybody's stretch of work. And because the domain lives in one package the deployments depend on, and never the reverse, a screen that wanted its own idea of a state would have to invent one, and there is nowhere for it to invent one from.

What we'd do differently

A default that runs anywhere is a default that can hide a missing binding. The complaint that started the letters was that the emails were not being sent, and the honest reading of the code at the time was that there were no emails, no transport and no letter anywhere in it. Now that the letters exist, the risk runs the other way. A letter written and logged looks, from every type in the system, exactly like a letter delivered, because a shape satisfied by a stand-in is satisfied, and that is the price of being able to run without one. The operator's health route now answers degraded when the system behind its gateway does not answer, which is the honest version of a default for that one seam, and the other seams do not have it yet.

The page could hold the shapes and could not hold the constants. Every number in the arithmetic, the size of the nudge a confirmed checkpoint gives the weights, the floor no weight may drop under, how many stretches the learned order may contradict the declared one before the system proposes a re-rank, is marked as a starting point to refine, and none has been refined yet, because refinement needs people using it and the system is still behind its launch door, letting them in a few at a time. The stretches those people will read are kept as they were read, which is the second study, and how a screen is held to drawing every state those readings can be in is the third. A model that came out of use would have had its constants earned. This one has them guessed, and the guess is written down where the earning can replace it.