Three of the four homeowners in this product have no account, so most signatures in it are made through a link. A link alone asserts; a link plus a code identifies; and only one of those puts money on a contract. The difference is drawn as a fact about the total, never as a fact about the person.
Dave needs this signed before the plumber comes back on Friday.
The stack came up nine inches off the drawing. Dave found it when the wall opened, and the run has to move before the plumber can close.
`change_order_signatures` has a `consent_text` column and it is `NOT NULL` — the row keeps the exact wording, not a version number pointing at whatever the wording is today. That column is the only reason this screen can be honest a year later, and it is already there.
No no password needed, no lighter type, no second-class framing. `FICTION.md` is absolute about it and the reason is the record: a year on, the binder must not be able to tell a link signature from a session one, and must not care. What differs is what the money does, which is frame 3.
I have a question first is not a decline and does not close anything. It is the deferral drawn on mockup 32, and a signature screen that dropped it would be the one place in the product where asking a question was not allowed.
We sent six digits to the number this link came to: the first time it signs for money, and again if it has been a while. After this, the link is enough.
_ds/forms.css settled this before this page existed: "A page putting it in front of a login has misread the model." Nobody is stopped on the way into their own house to prove they own an address. What is gated is the one moment a number moves, which is why the amendment is drawn on the same screen as the boxes.
The code and the link arrive on the same phone, so a code on every signature re-proves a fact the link already proved. What it buys is one thing — a forwarded link cannot sign — and that is worth asking for once, when the number is new to us, and again if it has gone quiet long enough to be worth asking. Between those two moments the link plus the signed sentence is the record, which is what every e-signature product does and what this one should have said from the start. A second ask, back to back, is not a second proof; it is the same proof, charged twice to somebody doing you a favor.
The confirmation is against the number, not the person and not the amendment, so a signature arriving from somewhere this job has not seen asks again. That is one of two re-asks in the design and the one where the thing being proved has genuinely changed; the other is time passing rather than the number, and it is named further down.
signature_assurance.go fixes the spelling — token_challenged — and deliberately does not declare it, because nothing writes it: "a value with no writer is the same defect as a column with no writer." There is no code table in any of the 86 migrations either. Frames 1 and 2 draw a mechanism that does not exist. What does exist is a fail-closed function ready to receive it.
The component rule, and it holds here even though this is the highest-stakes place it appears. A code that is expiring says so in a line underneath at rung 1. A clock ticking on the box is anxiety with no action attached, and this is the screen with the least room for it.
This is the frame most likely to break FICTION.md's rule and it is drawn to show that it does not have to. Neither row names a mechanism, a channel or an account. Signed Thursday 13 May by Ben Okonjo is the whole of what the record says about either of them, and the one that cost a code is indistinguishable from the one that did not — which is the point. The code is a fact about a number, never a fact about a signature.
Two cases, and they are the same card 13-money frame 3 gives CO-1: a first amendment signed and not yet confirmed, and one signed from a number this job has not seen before. Neither is on this screen because Cedar Court has neither — and drawing a held row here would have taught that holding is the normal state, which after the ruling it is not. Frame 2 is where a held amendment actually lives: it is the screen somebody is looking at while theirs is held.
When a row is held it renders as its own card and not as an ordinary line, because a held amount inside the total makes the total wrong, and one left off the screen makes the confirmation feel like paperwork about nothing. 13-money frame 3 carries the treatment for Sam, which is where it now appears twice rather than three times.
On a held row the control is ask him to confirm it rather than a red count or a chase timer. The person who can resolve it is holding the phone, the thing they can do is send one message, and the account-less tier's send rule still applies: never send somebody something that does not need them.
Mockup 01 frame 7 drew the code on the front door and gave it to Sam, who by mockup 13's own argument will never see it. Mockup 13 frame 3 asserted that the signature code and the email code are one mechanism. The backend has never had either. What it does have is signature_assurance.go: two declared values, a third reserved by name and deliberately left undeclared, and a fail-closed default that refuses to promote money on a string it does not recognize. That file is the most careful thing in the gateway and it has been waiting for this page.
A confirmation table — the number, a hash, an expiry, attempts — one send through the outbound path that already exists, the constant declared, and one case added to signatureAssurance. No column moves on change_order_signatures. The level was always derived rather than stored, and that decision is what makes this cheap: a policy that tightens later comes out retroactively right on every historic row instead of wrong on all of them.
The row binds a number, not a signature, which is the only structural consequence of the ruling below. Assurance is then a question about the number a signature arrived on, asked at read time — so confirming once counts everything that number has already signed, and everything it signs afterward.
It does not put a code in front of a login, it does not draw a badge saying who has an account, and it does not give Ben a dashboard. Requiring a second factor at sign-in is a real question and a different one, and it is answered on 15 · Account & being told, frame 8, next to the rest of the account rather than next to this.
Once per number, and not again unless the number changes or the confirmation goes stale. An earlier draft of this page left the question open between three answers: unconditional, over a figure, or the builder's to set per job. It is none of them, and the reason the fourth answer was missing is that all three assumed the code proves something the link does not.
It does not. The code is sent to the number the link arrived on, so on every signature after the first it re-proves possession of a phone that possession of the link already proved. The one thing it genuinely buys is that a forwarded link cannot sign — and that is worth one interruption at the start of a relationship, not one per amendment.
The three rejected answers, and why:
25 refuses for the digest cadence and for every heard-at: a limit is only worth something if the person it protects against cannot move it.Six months, and it resets every time it fires. A confirmation is not a permanent grant; it is evidence with an age, and the age that matters is confirmed_at, not the day the project opened. A number confirmed last week and a number confirmed two years ago read identically to a join that only asks is there a row — so the derivation gets a second clause: confirmed, and confirmed inside the window.
Six months clears US carrier number-recycling practice — a dormant number can be reassigned in as little as 45–90 days — with room to spare, without re-asking anyone who is actively signing. A signature does not reset the clock on its own; answering a fresh code does, so a homeowner mid-project who signs monthly is never interrupted, and one who goes quiet for two seasons is asked again before the next amendment counts.
Re-asking does not catch a number that already changed hands, because the new challenge goes to whoever holds the phone now — same as the old one did. What it buys is the same thing the first ask bought: a record that says the last person to answer this phone did so recently enough to mean something, on the row a dispute would actually read.
Same rule as the digest cadence floor: the window is not the builder's to extend. Six months is the constant, not a per-job setting.