LIFE COMPASS

0004 — Prose stays Markdown; question definitions become TypeScript

Context

Every blank in the worksheets is currently marked <span class="fill">______</span> — 443 of them, in two widths: 369 wide (fill, 15rem) and 74 narrow (fill-sm, 6rem). These are drawn underlines, not form fields: the stylesheet hides the underscores and draws a border. They carry no identity of any kind.

Once answers are stored, every blank needs an identifier stable enough to survive edits to the prose around it, because that identifier is the storage key. Positional identity — the seventh span in day one — breaks the first time a blank is inserted above it.

There is also structure the current markup cannot express. Day one’s “five chapters, three fields each” is fifteen anonymous spans. The interface wants one repeatable group with an add-another control; the agent contract wants an array.

Options

O1. Schema blocks embedded in the Markdown. Rejected. Fenced YAML inside each worksheet file. One source of truth, no drift — but the raw file stops reading as a worksheet on GitHub, and a public repository of worksheets being browsable is much of what it is for.

O2. Plain YAML sidecar per page. Rejected in this form. Right shape, wrong material. Untyped, and drift between the two files is caught by nothing.

O3. Typed sidecar, joined at checked anchors. Chosen. Prose in content/days/*.md, question groups in src/questions/*.ts, joined at explicit anchors in the prose.

Decision

The standing objection to sidecar files is drift: two files, one gets edited, nothing notices. That objection dissolves once the build can fail. Anchors in the prose — <!-- questions: chapters --> — are checked in both directions: every anchor must resolve to a group and every group must have an anchor, or the build stops.

Combined with strict typing, question identifiers become compile-time checked, and they are the same identifiers used by the storage layer and by the agent output schema. One rename, three call sites, all verified.

Consequences

C1. The Markdown stays readable and printable on GitHub, unchanged in character from today.

C2. Editing one section of a worksheet means touching two files. Accepted as the price of the above.

C3. The fill spans become scaffolding with a scheduled removal. They stay untouched through the initial rewrite, so its output can be diffed against the live site, and come out page by page as each page’s questions are defined. Their visual idea does not die with them — 0010 makes the print renderer their successor.

C4. Renaming a question identifier is a migration, not a rename — stored answers key off it. This needs a versioning and mapping plan before the first real answers exist, because there is no fixing it afterwards. Flagged here rather than discovered later, and settled in 0011.