/** * What a submission row calls the form it came from. * * THE DEFECT THIS EXISTS FOR, measured on Great River: every row read * `24335589fc6d5b461c86fec07c3d99e1`. Not a title, not a slug - thirty-two hex characters, identical on * every row, in the column whose whole job is to say which form a submission came from. * * WHY THE OLD FALLBACK WAS REASONABLE AND STILL WRONG. It fell back to the form HANDLE, on the stated * grounds that *"the handle is what the practice named the URL, so it is recognisable rather than * opaque."* That is true of a handle a practice CHOSE. But the server mints one when the practice does * not: * * register-post.ts: body.formHandle || randomBytes(16).toString('hex') * * An auto-generated handle is sixteen random bytes. Printing it as a name tells a receptionist * nothing, and worse, it LOOKS like an identifier they ought to recognise. * * WHY NO TITLE RESOLVES AT ALL RIGHT NOW, which is the actual cause and is NOT in this file: * `GET /R4/public-forms` answers `{"forms":[]}` for every practice - measured 2026-08-23 and again * 2026-08-31, a week apart. So the title lookup this fallback backs up can never succeed today. * -> This module cannot fix that. What it can do is stop the failure being reported to a human as a * uuid. */ /** Sixteen random bytes, hex-encoded - what the server mints when a practice names no handle. */ const GENERATED_HANDLE = /^[0-9a-f]{32}$/; /** * A handle a practice chose is worth showing; one the server invented is not. * * Deliberately narrow: only the exact shape the server generates is treated as meaningless. A practice * that names a form `intake2026` keeps seeing `intake2026`, which is the half of the old behaviour that * was right. */ export const isGeneratedFormHandle = (handle: string | undefined): boolean => GENERATED_HANDLE.test((handle ?? '').trim()); /** * WHAT THE ROW SHOWS, in order of how much it actually tells somebody: * * the published title the practice named this form * the handle the practice named the URL * "Unnamed form" we have neither, and a uuid is not a name * * The last case says what is true rather than printing the id anyway. A receptionist cannot act on * thirty-two hex characters, and showing them implies the value means something to somebody. */ export const formLabelFor = ( title: string | undefined, handle: string | undefined, ): string => { const named = (title ?? '').trim(); if (named) return named; const raw = (handle ?? '').trim(); if (raw && !isGeneratedFormHandle(raw)) return raw; return 'Unnamed form'; }; /** A submission's label: the title the server sent with it, else one from the published-forms list. */ export const submissionFormLabel = ( submission: { formHandle: string; formTitle?: string }, listedTitle?: string, ): string => formLabelFor(submission.formTitle?.trim() || listedTitle, submission.formHandle);