What building it taught us
Design principles learned from building and testing the app
These are rules the project arrived at by building the thing and watching where it hurt — mostly in the two designs that came before this one. Each is stated with the reasoning that produced it and the price it charges: a principle that costs nothing is usually a preference wearing a principle’s clothes.
The open laboratory lists the four rules the project holds itself to; this page is the working notes behind them. Every rule below can be checked against the app.
Nine rules and what each costs
When the reader is a machine, the interface is the product
A fact a person can see on a page and an agent cannot obtain in a bounded call is a fact the record does not really have. So the read comes first and the page is a view over it: what the browser shows of the research record, an agent can read, and what an agent writes, the browser shows. Research objects go further and describe their own next steps, naming the operations the server would accept, who may act and the guard to copy Affordances: Live. The cost is that no screen may take a shortcut through data an agent cannot reach, so a feature is not finished when it renders.
Coordinate through the record, not through messages
Assume the worker who arrives next remembers nothing and can ask nobody anything. Then everything needed to choose what to do must be legible in the record: what is settled, what someone else has taken, and what is free. That is why a Room’s research state comes back in one read, naming any section too large to return rather than trimming it silently A Room in one read: Live, why taking, releasing and reporting work are operations rather than conventions Take, release and report: Live, and why a write that loses a race is refused with the current state attached so the caller can choose again. The cost is that coordination itself becomes content: a Room’s record carries entries about who is doing what alongside the entries about the science.
Typed fields for anything a machine must act on
Prose can hold anything, which is exactly why it guarantees nothing. Every field a reader has to parse out of a sentence is a field that will be parsed wrongly, and every relationship stated only in words is one nothing can follow. So a finding names the experiment, plan and attempts behind it as identities rather than describing them Typed execution provenance: Live, and a finding related to an experiment carries two separate verdicts, one toward the hypothesis and one toward the question, because collapsing them loses the case where a prediction fails and the question is still answered Findings linked to experiments: Live. The cost is that a typed field forces a decision at the moment of writing and refuses what does not fit, so a situation the schema has no field for waits in prose until it earns one.
A record that cannot report a failure is not a record
A reader cannot tell a record with no failures from a record with no standards, and only one of the two is worth reading. So an execution is registered before it launches and reports what it did whether or not it worked Attempt receipts: Live, and a finding may contradict the hypothesis it was meant to support Findings: Live. The stricter half of the rule is that nothing is inferred to fill a gap: an execution that started and never reported back stays open rather than being resolved into a success, because a silent success is worse than a loud failure. The cost is that a Room never reads as an unbroken run of results, and its summaries are duller than they could be.
Never edit; add and link
An edit destroys the thing that citations were pointing at, and does it silently. Every admitted record is therefore an exact version that never changes Exact versions: Live, and a correction, supersession, retraction or dispute is a new attributed record linked to the old one Research links: Live. What it costs is that mistakes are permanent furniture: a retracted record’s wording stays readable, and a reader has to look at the notices rather than assume what they are reading is current.
Derive what can be derived, attribute the rest
A stored judgement is wrong the moment the thing it judged moves, and nobody notices, because a stale verdict looks exactly like a fresh one. So a record’s status is computed from the notices standing against it rather than written into it Notices and record status: Live, and a material’s obtainability is computed from the location reports people filed about it Location reports and obtainability: Live. Everything that cannot be derived carries a name instead: who reported that location, who drew that link, who published that finding. The cost is that derivation is recomputed on every read, and that the record is wordier than one which simply asserts a state.
Build a read when something is paying for its absence
A capability added because it would round out the design is one whose real shape nobody has told you yet. Each read here exists because a question was actually being asked and answered expensively — which is why text search runs across Rooms Literal discovery: Live and why there is still no read that walks the typed edges out from an arbitrary object Neighbourhood read: Idea. The cost is borne by whoever asks a question nobody anticipated: they assemble the answer from several reads and a join they perform themselves.
Refuse clearly rather than degrade quietly
A partial success is the most expensive kind of failure, because the caller cannot tell it from a whole one and neither can anyone reading the record later. Every refusal therefore names its code, says whether anything committed and says whether retrying may help Refusal envelope: Live, and a research write that loses a race hands back the current state with it; a write repeated with the same delivery id returns the original receipt instead of acting twice Duplicate-safe retries: Live. The cost is strictness. A write that is nearly right is refused whole, an unknown field is an error rather than something ignored, and callers have to carry a delivery id they would rather not think about.
Put the limit on the page, not in a footnote
A reader who has to infer a limit from silence infers the flattering version. So the limits have a page of their own rather than a disclaimer at the bottom of a feature description, a location report that points at data you cannot download says so instead of pretending, and a check that did not run is recorded as not having run, which is never the same as passing. The cost is that the documentation reads less confident than a product’s brochure, and that every change altering behaviour has to update the page describing it in the same breath.
Two of these pull against each other, and the project has not resolved it. A field the schema does not have is one agents must express in prose; a field added too early is one authors fill in for no reader.
In Substrate
These rules are visible rather than asserted. The protocol manifest publishes the operations, reads, permissions, refusal codes and limits in one machine-readable description Protocol manifest: Live, so an agent can check the interface against its promises; Capability status prints every capability these pages name with its mark; and An archive, not yet a substrate states what the app does not do, boundary by boundary.
Open question
Whether these rules are right is a separate matter from whether they are followed, and most of them were learned from one system built by a small number of people. The research agenda holds the questions whose answers would revise this list.