assessment-model/docs/adr
Daniel Roth 1019e3ea3f feat(dates): enter and display dates as dd/mm/yyyy, site-wide
The create-project form's date fields were `<input type="date">`, whose
display format follows the *browser's* locale rather than the document's. On a
US-configured browser they rendered mm/dd/yyyy inside an app that renders
en-GB everywhere else (~40 call sites). That is not cosmetic: 03/09/2026 is a
valid date under both readings, so a user cannot tell which one the box took
and no validation can catch it. The failure mode is silently wrong data, not
an error message. No attribute, `lang` value or CSS overrides the native
control, so the control had to go.

`DateInput` replaces it: a text field that masks to dd/mm/yyyy as you type,
whose value and onChange remain YYYY-MM-DD. The display format therefore stops
at the input's edge — the schema, the request body and the Drizzle `date`
column are untouched, and dates keep sorting lexicographically with no
timezone in play. The cost is the native calendar picker, which ADR-0019
argues is the right way round: a picker is a convenience, an ambiguous entry
format is a correctness problem. If one is wanted later it belongs behind
`DateInput`, not in a revert to the native control.

The parsing lives in `src/utils/dates.ts`, pure and Date-free — `new
Date("2026-03-01")` is midnight UTC, which is the previous day in a
negative-offset zone, so this compares and builds strings instead. Impossible
days are rejected explicitly because `Date` would roll 31/02 forward into
March rather than refuse it.

Two behaviours worth knowing, both covered by tests. A *finished* but
impossible date is handed to the schema as typed rather than reported as
empty: a field visibly holding 31/02/2026 while an optional-date schema reads
it as unfilled would tell the user nothing. Unfinished input does report
empty, so no error fires mid-keystroke. And the mask only re-adds a separator
while characters are being added — doing it during a backspace would make the
slash undeletable.

`DateInput` adjusts state during render rather than in a `useEffect` (the
documented alternative) to resync when the form sets the field from outside.

Per CLAUDE.md's utils split, dates.ts is generic and lives in the new
`src/utils/`; `src/app/utils.ts` stays for company-specific helpers (EPC
bands, SAP points) and `src/lib/utils.ts` is vendored Tremor/shadcn.

CLAUDE.md records the rule and the "never `<input type=\"date\">`"
prohibition so the next agent finds it before writing the wrong thing.

Five other date inputs remain wrong under this ADR — PibiSection,
PibiDatesEditor and PropertyFilters — left alone as unrelated to this branch
and recorded in ADR-0019 as convert-when-next-touched.

TESTS: tsc --noEmit and ESLint clean; vitest 576 passing (53 files), 18 of
them new for the date helpers. Cypress was NOT run — this environment's
DATABASE_URL still points at production. The spec's four date entries were
converted to day-first, an assertion added that 01/03/2026 crosses the wire as
2026-03-01, and a new case covers the mask and the impossible-date refusal;
all three are unverified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 10:50:09 +00:00
..
0003-app-authored-scenarios.md feat(scenarios): portfolio Scenarios tab — gallery, detail, creation journey 2026-07-06 08:34:47 +00:00
0007-postcode-search-creates-properties.md fix(postcode-search): classify RH (HMO) family as addable residential 2026-07-09 10:33:07 +00:00
0008-modelling-runs-filters-to-distributor.md feat(modelling-runs): run config on tasks.inputs; backend contract updates 2026-07-07 10:46:29 +00:00
0009-portfolio-organisation-is-per-user.md docs(adr): 0009 — portfolio organisation is per-user, not shared 2026-07-07 21:11:21 +00:00
0011-app-owned-task-marker-in-task-source.md feat(live-reporting): bulk document download from the Documents tab 2026-07-08 14:11:42 +00:00
0012-portfolio-list-resolves-descriptors-via-override-precedence.md docs(portfolio): ADR-0012 — list resolves descriptors via override precedence 2026-07-10 23:21:21 +00:00
0013-tags-are-app-owned-property-groupings.md docs: ADR-0013 tagging system + CONTEXT (Bulk tag assignment, Run filter tags) 2026-07-13 15:45:14 +00:00
0014-epc-cards-count-certificates-not-predictions.md fix(reporting): EPC cards count certificates, not predictions (ADR-0014) 2026-07-14 12:19:02 +00:00
0018-ara-projects-supersedes-hubspot-live-projects.md docs(ara-projects): ADR-0018 + CONTEXT.md Ara Projects domain language 2026-07-21 08:30:32 +00:00
0019-uk-date-format-in-form-inputs.md feat(dates): enter and display dates as dd/mm/yyyy, site-wide 2026-07-22 10:50:09 +00:00