Menu
← Blog

An answer needs a state: confirmed, to check, or gap

A bare "yes, it's encrypted" cannot be defended a year later. A fact with a state, an owner and an expiry date can.

20 September 2026

Abstract editorial illustration for “An answer needs a state: confirmed, to check, or gap”

The problem with a value that is only a value

You ask a client whether data is encrypted at rest. Someone says yes. You write it into a security overview, a data processing agreement, a trust page and, three weeks later, into answers 14, 31 and 52 of a questionnaire from their largest customer.

Eleven months on, that customer's vendor manager asks you to confirm it. You open your notes and find the string yes.

You now cannot tell the difference between four situations that look identical on disk: the client's CTO checked the database configuration and said yes; a model pulled yes out of an existing policy you uploaded; an account manager guessed because the question felt like it wanted a yes; or you copied the answer from a similar client last spring and never went back. The fourth is the dangerous one, because it looks the most like work.

A value alone has no defence. A fact with a state, a person and a date does.

Four states, and what each one licenses you to do

The fact store in this product keeps one row per client per slot, and the row carries a state: empty, extracted, confirmed, stale. The states are not decoration; each one licenses a different action.

empty is the honest zero. Nothing has been said about this slot. Worth noting what also counts as empty: a suggested default by jurisdiction. The product can propose a typical answer for a client registered in Germany, but the proposal sits on screen unaccepted, and an unaccepted default stays empty. A default that silently became an answer would be exactly the guess we are trying to eliminate, only faster and at scale.

extracted means something produced a candidate value that no human has stood behind. Three things land here. A model reading the interview transcript, where confidence above 0.8 records the value and anything lower turns into a clarifying question rather than a write. An imported document, where a policy and a subprocessor list the client already has can close a large share of slots in one pass. And copying from a similar client — "fill this in like the other logistics one" — which moves infrastructure, process and retention answers across, and marks every one of them extracted, never confirmed. That last rule is the one people argue with, and it is the one that matters most: the fastest way to manufacture a defensible-looking lie is to inherit forty answers from a client that resembles this one.

confirmed carries confirmed_by and confirmed_at. A person put their name on it. This is the only state that a document may be generated from, and the only state that lets a questionnaire answer be marked confirmed. Once a fact is confirmed, a later extraction cannot quietly overwrite it — a new candidate value from a model does not downgrade a human confirmation. Changing a confirmed value is a deliberate act, and it has consequences downstream, which is the next section.

stale is a confirmed fact past its valid_until date. It is not wrong. It is unwitnessed. The distinction is the whole point: you are not telling the client "your encryption is gone", you are telling yourself "nobody has looked at this since March".

Facts do not all have the same shelf life

A registered address and a headcount change rarely, and when they change, somebody in the business knows. A production access model, an offboarding procedure, an MFA policy and a backup schedule change whenever an engineer changes them, which is to say without an announcement.

So validity is set by the group the slot belongs to. Facts in the infra and process groups expire six months after confirmation. Everything else — company, product, retention, vendors, and the regime-specific groups — expires in twelve. The rule is deliberately crude. A more elaborate per-slot schedule would be more accurate and would not survive contact with a portfolio of two hundred clients, because nobody would be able to predict what the system was about to ask them.

What this buys is a query you could not write against a JSON blob. One index on firm, slot and state answers the questions that turn up in the first month of running a practice on a shared store: which clients have no enforced MFA, whose confirmations have expired, what changed since the last generation. On a client list, the earliest expiry date across that client's confirmed facts is a single column — the date the oldest part of their documentation stops being witnessed. That column is an annual review, scheduled by the data rather than by somebody remembering.

A negative answer is a closed fact

mfa_enforced: false is not a blank. It is an answer, and it closes the slot the same way true does.

This sounds obvious and is routinely got wrong, because a product that treats "no" as an unfinished state quietly pushes everyone toward "yes". The interview must be able to say: this is not in place, we will write it honestly and add a plan. Generation then produces the honest sentence — the measure is not currently in place, it is planned — rather than dropping the section, and the editor will refuse an instruction to write the opposite. The wording it gives back is that the client's own data says otherwise, and if the situation has changed, update the interview answer and the section is regenerated.

The reason is not squeamishness. The person on the other end of a vendor questionnaire reads these for a living. A package where every security control is present and none has a date is less credible than one that says two things are missing and names when they will be addressed.

What goes into a document when the fact is missing

Nothing plausible. That is the whole rule.

When a required fact is absent, generation writes [[GAP:slot_key]] into the body and collects the gaps onto the document record. The marker resolves to the interview question for that slot, so the rendered output does not say "gap" — it says what to go and ask. In an exported file it appears as a bracketed instruction to complete, carried through into the DOCX and PDF rather than stripped at the door. The consultant accepted responsibility for it at the export gate; hiding it afterwards would defeat the gate.

The alternative — a model writing a reasonable-sounding sentence about a control nobody described — is the failure mode that ends a consulting relationship, and it is invisible at review time precisely because it reads well.

The same logic governs questionnaire answers, with three states of their own. confirmed requires a pointer to a specific section of one of the client's own documents; an answer that claims confirmed status without a valid source is downgraded to review in code, not by asking the model to behave. So is an answer that introduces a certification claim — SOC 2, ISO 27001, PCI DSS, HIPAA, the word "audited" — that appears nowhere in the client's facts or document excerpts. review means drafted but resting on general wording. gap means the client does not have this, written plainly, with a plan. Answers pulled from the firm's own reusable library land as review, not confirmed, because a template that fitted the last client is a candidate for this one, not evidence about it.

The question this is actually answering

Every one of these mechanisms exists to answer one question, asked by an auditor or a corporate customer or your own client six months from now: how do you know?

"It's in our records" is not an answer. "It was confirmed by this person on this date, it is valid until that date, and here is the document section the questionnaire answer was drawn from" is. That chain is what clausebench stores per fact, and it is the difference between documentation you can stand behind and documentation you merely produced.

See what changed since your clients' policies were written

Enter up to ten client websites. Free, no sign-up, the first report in about a minute.