- Shipped
- August 14, 2026 at 3:02 AM UTC
- Author
- kamo
- Commit
- 02a7cc4
The execution wizard showed a blank surface for every signable document — no pages, no field overlays, no PDF request, and nothing in any log. DocumentStep measured its scroll container in a `[]`-deps effect reading a ref, and returned early when the ref was null. On the signable path the first commit is a spinner, then a consent gate; the `ref={scrollRef}` box only exists on the branch AFTER both. So the effect ran once against a null ref, bailed, and never re-ran. containerWidth stayed 0 forever and `{containerWidth > 0 && <PdfPages/>}` never rendered. The failure had no error path at all: the fetch was never issued, so the network tab and ESigService's logs were equally clean. A callback ref fixes the class of bug, not the instance — React invokes it on every attach, so the observer follows whichever branch finally renders the node. It lives in useMeasuredWidth and the viewer moved into one DocumentDesk that every branch renders, so no future branch can render the document without measuring it. Also rebuilds the wizard as the signing room it should have been: - THE DOCKET. One seal per step, threaded in reading order, replacing the step counter and the progress bar. The numbering is information: reading order is legally meaningful in a package and orderIndex is the only field that carries it. The attestation is a diamond marked §, not the n+1th document, because agreeing to the package is a different act from signing a page. Its state model is pure and tested (docketNodeStates, docketProgress) — complete outranks active, and the thread measures what is BANKED, never what was visited. - The desk is dark in both themes so the paper is the brightest object on screen, with the page floating on a real shadow. - THE VERIFICATION STRIP: the frozen contentSha256 under the page. It is the one thing on screen proving the document was not swapped after it was sent, and DocsService re-checks it before serving a byte. - Drops the separate LinearProgress. The thread is the progress; a second bar counting steps VISITED would contradict it on screen. - The attestation wording rendered TWICE — once as a paragraph and again as the checkbox label — so the member read the same legal text twice and it was ambiguous which copy the tick bound. It appears once now, as the label, which is what it is. - Uses the hr.legal.wizard.* dictionary namespace that already existed and nothing referenced (verified present and non-empty in all 22 locales), so the copy speaks to the member instead of reusing common.actions.done. Every animation is gated on useReducedMotion. FieldLayer moved to its own module unchanged.