← all branches

fix/rpu-12-digit

needs attentionviewing older commit
77a5d70 · incrementalPR #246reviewed 2026-07-05 21:09 UTC0H · 2M · 9L · 12I
The branch
Purpose
Fix blank toast and frozen submit button when creating a contract with a short RPU — the drawer was marking an 11-digit RPU as 'Disponible' and the form had no useful error surfacing on the server's 400 ZodError rejection.
Goal
Add explicit RPU validation at both entry points so incomplete RPUs never reach the server, and surface meaningful errors when they do.
Sub-goals
  • SG-1: RPU_LENGTH constant as single source of truth
  • SG-2: normalizeRpuInput — strip non-digits, cap at 12 — applied at all write paths
  • SG-3: AddContractDrawer: lookup gate at exactly 12 digits
  • SG-4: InlineContractForm: client-side guard + descriptive toast via extractServerErrorMessage
  • SG-5: Test coverage for pure rule logic, drawer gate, and form error paths
The changes (whole branch)
What
Added RPU_LENGTH + normalizeRpuInput to rpu-errors.ts. AddContractDrawer now normalizes on onChange and onExtracted, maxLength changed 14→12. InlineContractForm uses RPU_LENGTH direct length check. Tests expanded: normalizeRpuInput suite, pluralization, empty-string, ALREADY_EXISTS fallback, container-scoped form query.
Why
Prior loop review (586531a5) flagged 13-digit permanent-loading, flaky setTimeout, and missing test cases. This commit addresses all of them.
Areas
apps/platform/src/app/[locale]/(dashboard)/bills/_lib/rpu-errors.ts+230apps/platform/src/app/[locale]/(dashboard)/bills/_components/AddContractDrawer.tsx+146apps/platform/src/app/[locale]/(dashboard)/bills/_components/InlineContractForm.tsx+254apps/platform/src/app/[locale]/(dashboard)/bills/_lib/__tests__/rpu-errors.test.ts+1080apps/platform/src/app/[locale]/(dashboard)/bills/_components/__tests__/AddContractDrawer.rpuGate.test.tsx+1100apps/platform/src/app/[locale]/(dashboard)/bills/_components/__tests__/InlineContractForm.rpuError.test.tsx+1430
Blast
8 files, +472/-12. Confined to /bills route-scope. No backend, API schema, or migration changes.
client-side-only no-migration hotfix
CI checks· GraphQL token lacks statusCheckRollup permissionTypeScript· author-reported: tsc --noEmit cleanunit tests· author-reported: 14/14 pure-rule tests passCodeRabbit· .coderabbit.yaml not present

Findings · 11

correctness2

medium

maxLength=12 truncates pasted formatted RPUs before normalizeRpuInput runs

apps/platform/src/app/[locale]/(dashboard)/bills/_components/AddContractDrawer.tsx:415

Browser enforces maxLength before onChange fires. Pasting '1234 5678 9012' (14 chars) truncates to '1234 5678 90' — normalizeRpuInput yields only 10 digits. Remove maxLength or raise to ≥16.

low

Telemetry rpu_length tracks raw PDF string length, not digit count

apps/platform/src/app/[locale]/(dashboard)/bills/_components/AddContractDrawer.tsx:366

security1

low

Server schema missing .regex(/^\d{12}$/) on contractNumber

packages/api/src/schemas/utility-contract.schemas.ts:353

conventions3

medium

Literal 12 used in AddContractDrawer instead of RPU_LENGTH

apps/platform/src/app/[locale]/(dashboard)/bills/_components/AddContractDrawer.tsx:176

Lines 176 and 389 hardcode 12. RPU_LENGTH was introduced for single-source-of-truth but AddContractDrawer doesn't import it.

low

Same 12-digit predicate expressed two ways across call sites

apps/platform/src/app/[locale]/(dashboard)/bills/_components/InlineContractForm.tsx:150

low

onChange comment's first clause describes what, not just why

apps/platform/src/app/[locale]/(dashboard)/bills/_components/AddContractDrawer.tsx:418

tests2

low

normalizeRpuInput('') not tested

apps/platform/src/app/[locale]/(dashboard)/bills/_lib/__tests__/rpu-errors.test.ts:39

low

ALREADY_EXISTS → createFailed fallback not integration-tested in InlineContractForm

apps/platform/src/app/[locale]/(dashboard)/bills/_components/__tests__/InlineContractForm.rpuError.test.tsx:85

improvement3

low

isValidRpu encodes literal 12 in regex instead of delegating to RPU_LENGTH

apps/platform/src/app/[locale]/(dashboard)/bills/_lib/rpu-errors.ts:24

low

digits useMemo strips non-digits from already-digit-only value (no-op)

apps/platform/src/app/[locale]/(dashboard)/bills/_components/AddContractDrawer.tsx:147

low

isValidRpu(debounced) enabled flag is always equivalent to !!debounced

apps/platform/src/app/[locale]/(dashboard)/bills/_components/AddContractDrawer.tsx:166

History · 6 commits

  1. 427115eneeds attentionincremental0H · 1M · 3L2026-07-05 21:43
  2. c6ce7d8needs attentionincremental0H · 3M · 6L2026-07-05 21:35
  3. d8cbd91needs attentionincremental0H · 0M · 3L2026-07-05 21:25
  4. 20aa256safeincremental0H · 0M · 2L2026-07-05 21:14
  5. 77a5d70needs attentionincremental0H · 2M · 9L2026-07-05 21:09current
  6. 586531aneeds attentionfull0H · 5M · 10L2026-07-05 20:51