A Question Is Done When It Is Answered or Skipped
Why skipped is a boolean on the field rather than a status on the block, why it is refused on a required field, and why not-applicable is a separate question answered by logic
Decision
A field is done when it holds a value or carries skipped: true. A module or
document is complete when every field beneath it is done. skipped is refused on
a required field.
Nothing above the field stores a status. Progress at every height — block, module, document — is folded from the fields, so there is no second copy to go stale.
In plain terms: every question on the form is either answered or deliberately struck through. Nothing is left silently blank. You know the form is finished because there is nothing on it that is neither.
Who may skip, and what requiring does
Owner ruling, 2026-09-15. Two halves, both about who acts rather than about the invariant above, which is unchanged.
Skipping belongs to the Maker. Striking a question through is a way of
answering it — the field is done — so it is the act of the role that fills
the document in, not the one that builds it. A Builder laying out the form has
no client in front of them to decline a question, and is no longer offered
Skip or Unskip. The capability model already said so: the seam sits with
onValueChange and onClearValue, never gated on canEditBlock like move,
delete and retype beside it; what was missing was the other half, so the menu
read as though skipping were structural.
Requiring a struck-through question reopens it. The Builder has raised the
bar after the Maker passed the question over, so the question comes back and
must be answered again. transitionBlockFields clears skipped in the same
write — this is one act, not two facts, so the pair-invariant below is upheld
rather than bypassed: storage is never asked to hold "required and skipped" at
once. canSetRequired therefore no longer withholds the control on a skipped
field; it withholds it only where the write would still fail, on a computed
field.
In plain terms: the client struck a question out, then the firm decided it must be answered after all. The strike goes and the question comes back, so the client is asked again.
The Maker's decision is overwritten silently. A mark saying the field was reopened is wanted but unbuilt, and belongs with the rest of Maker mode (GB-93), which also owns moving Skip off the type mark — that control answers "what kind of thing is this", not "am I filling this in".
Three separate questions, at three levels
The retired interviewStatus column blurred these together, which is why it
could not be replaced by a single rule.
| Question | Answered by | Level |
|---|---|---|
| Does this part of the document apply at all? | logic | block or module |
| Must this question be answered? | required | field |
| Was this optional question deliberately passed over? | skipped | field |
They compose in that order, and the order is what makes each one small:
logicdecides applicability. A guarantee module that does not apply is excluded, and its fields never enter the count at all.requiredis only meaningful where the field applies. Asking whether a guarantor's name is required is a question you can only ask once you know there is a guarantee.skipped: truemay only be set whererequiredis false. If a guarantee is required, we need the guarantor's name. There is no honest way to record that we finished without it. Absentrequiredis not required, so the flag is available there too — the invariant reads off requiredness, not off whether the author typed the word.
In plain terms: whether the clause is in the deed at all is one question; whether a blank in that clause has to be filled is a second; whether a blank that need not be filled was deliberately left is a third. Answering them in that order is what stops any of them growing into a catch-all.
Skipping is therefore never how an inapplicable section is handled. That
was the tempting shortcut — a client says "there is no guarantor", and marking
the section skipped looks like the answer. It is not: the section's fields are
required, skipped is refused on them, and the honest record is that the section
does not apply. That is logic, and it excludes the whole thing rather than
striking through its parts.
Why the field, and not the block
An earlier draft of this decision put the skipped fact on the data block, on
the reasoning that a data block is the unit that holds an interview. The
retired system did something close to that: skipping a module wrote skipped
onto the module version and onto each of its data blocks — the same fact
stored twice, at two heights, free to disagree.
Putting it on the field is strictly better:
- It sits with the thing it describes. A skipped question is a decision about one question, not about a container.
- Everything above it derives. A block is done when its fields are done, a module when its blocks are, a document when its modules are. One stored fact at the leaf, and no fold to keep in step with a stored parent.
- It removes an ambiguity rather than adding a field. Under the previous
rule,
completemeant "nothing required is outstanding" — so a block whose questions are all optional flipped to complete on its first answer, with the rest blank. There was no way to tell a blank that had been considered from a blank nobody had reached. Now there is.
Consequences
skippedjoins the field contract as an optional boolean, besiderequired. Absence means not skipped, the same way absentrequiredmeans not required. It prints on the About card only when true, likerequired.completetightens. It now means every applicable field is answered or skipped, not merely every required one. A document sitting at complete with a blank optional field drops back to in progress until that field is answered or skipped. This is the intended behaviour change, not a side effect: it is what removes the ambiguity above.- A write that sets
skippedon a required field is refused, and so is a write that makes a skipped field required without clearing the flag. The two are one invariant read from either end. - No reason is stored. The retired column carried a reason vocabulary (declined, deferred, condition false, agent judgment) and a free-text summary. Ruled out: the reason a required thing was not done would matter, but a required field cannot be skipped; and why an optional question was passed over is not a fact the document needs to carry.
- Nothing else stores interview progress.
resolveDataBlockStatusand the folds above it in@goldie-blocks/domain/interviewremain the only answer to "how far along", and they readvalueandskipped.
Status
Ruled by the owner, 2026-09-02, settling backlog decision 11 (Library master or original — which Folio does the owner edit after Save to Library?).
logic is post-MVP, so the applicability leg above is not yet buildable. That
is not a gap for MVP: the MVP proof is a deliberately unconditional services or
confidentiality agreement, which has no inapplicable sections.
The skipped leg is MVP, and stays MVP after the interview was ruled
post-MVP on 2026-09-02. skipped is a fact about a question, not a piece of
interview machinery: a Builder filling a document directly answers some
questions and deliberately passes over others, and the completion rule above is
what tells them the form is finished. What ships later is Goldie conducting the
question-and-answer pass, not the ability to record that an optional question
was passed over.
Built 2026-09-05 (GB-152 Stage D row 2). skipped is a member of the one
field contract (packages/domain/src/field/field-schema.ts), stored only as
true; the contract's refinement refuses a skipped required field from either
end, and every field write parses with it before storage
(convex/folio/fieldWrites.ts). write-field-values sets and clears it
(fieldValueWrites.ts: answering drops the mark). The progress fold
(packages/domain/src/interview/progress.ts) reads it: a field is done when it
holds a value or is skipped, and complete means every answerable field is done
— the behaviour change this record intended. No field row offers a skip control
yet; that is owed to the canvas.
Info Lives on the Card; the Panel's ⓘ Becomes Search
Owner ruling 2026-10-09 — the side panel's About (ⓘ) view is retired everywhere. Workspace, Project and Library cards already show name, guide, tags and people when expanded. A Block or Module on the document gets About on its menu, which opens it in place as its Goldie card: top line, the clause then the guide in the panel, the title bottom left, people bottom right. Blocks show their tags. The panel header's ⓘ becomes 🔍 Search, opening the Add view.
Interview Turns Run gpt-5.6-luna at reasoningEffort "none"
Why the interview agent moved off gpt-5-nano, why reasoning effort was dropped to "none" rather than tuned, and what the ping-instrumented eval A/B actually showed