The authoring convention for a Versable app's surface docs. One doc per screen, the same eight headings in the same order, every time.
Audience: an agent (or person) writing the next surface doc.
Reference implementation: walmart-mvp/docs/surfaces/, 11 surfaces.
§A Principles and mental models#
1. The fixed shape is a mechanism, not tidiness. Eight headings in one order, in every surface doc:
| # | Heading | Contains |
|---|---|---|
| 1 | What it is for | product intent, one paragraph |
| 2 | How you get here | every entry point, cited |
| 3 | Who can see it | auth, org role, staff gating |
| 4 | What it shows | named regions and their data sources |
| 5 | What you can do here | each action: trigger, precondition, observable success, observable failure |
| 6 | States | boot, loading, empty, error, permission-denied |
| 7 | Data surfaces | loader, cache key, revisit behavior, blank gate |
| 8 | Known gaps | true today, and a reader would otherwise file it as a bug |
The order is the payoff: sections 5, 6, and 2 generate the positive cases, the
negative cases, and the setup respectively, so a test becomes a transcription
rather than an invention (02-deriving-e2e.md).
2. The grid forces the cell nobody would have written. Section 5 is a table, so every row must fill an "observable failure" cell even when the author was not thinking about failure. That is where the valuable findings come from: a publish action whose zero-eligible case raises a WARNING rather than an error is the kind of behavior a from-imagination test suite never covers, and it exists in the doc only because a cell demanded it.
3. Add no sections. A heading that is not applicable on most surfaces trains readers to skip sections, and a skipped section is worse than an absent one. Genuinely load-bearing oddities (a performance quirk, a keyboard affordance) go in section 8, which is what section 8 is for.
4. Depth follows richness; the shape does not. The headings are uniform, the depth under them is not. A rich surface earns around 150 lines and that is the ceiling, not the target; a single-table surface lands at 70 to 100. Padding a simple surface to match a complex one makes the set less readable, not more thorough.
5. True today, with a pointer. Docs describe what ships, never what is planned. A line describing an unshipped state is a lie with a good excuse. Where a ruled-but-unbuilt change must be mentioned, it carries its tracking pointer inline so the line is findable by grep when the fix lands, rather than by memory. When the fix lands, the line dies, and recording the retirement (rather than silently deleting) is the policy visibly working.
6. Cite so a reader can check rather than trust.
Every behavioral claim carries a file:line. Each doc names the commit it was
verified against, so a reader knows the age of the claims. An unverifiable claim
says so instead of rounding up to certainty.
7. Exemplar first. Write ONE surface doc completely, put it in front of a reviewer, and hold the rest until it comes back. The first doc earns the corrections that would otherwise have been made N times: the shape, the depth ceiling, and a stale gap line all surfaced from one review before nine more docs inherited them.
8. The doc set carries its own scope table. An index that lists what is documented AND what is deliberately not, with the reason, prevents both re-litigation and accidental gaps. Legacy-but-routed and dead-but-present are different states and are recorded differently, because one day someone will try to delete the wrong one.
§B Presets#
| Situation | Preset |
|---|---|
| New surface ships | new doc, eight headings, verified-against sha on line 3 |
| A ruled change is not built yet | the line, plus its tracking pointer inline |
| A gap gets fixed | retire the line, record the retirement with the fixing commit |
| Code makes a doc claim false | whoever changed the code updates the claim, same commit if possible |
| A surface is out of scope | it goes in the index's scope table with the reason |
§C Use cases through the apps#
walmart-mvp: 11 surface docs plus the index's scope table. The set was adversarially gated on 2026-08-09 against the code it describes, which is the strongest available evidence the shape holds: roughly 180 citations checked, and the defects clustered in the non-surface docs rather than in the eight-heading ones. The gate also found what the shape cannot do on its own, which is worth knowing: a doc can describe an action perfectly and still not be transcribable if the control has no accessible name.