I-018 β Signed IR56M shows "Draft" on Records¶
Symptom¶
Owner signed IR56M forms, but the Records β IR56M tab kept showing them as Draft in the "Status" column.
Root cause¶
IR56M carried two status notions that were never linked:
-
The filing doc's own status β
tebs-erl/ir56mFilings/{endingYear}, fieldrecipients[].status(typeIR56MRecipientStatus = 'draft' | 'confirmed' | 'signed' | 'filed'). Set to'draft'once at seed time (seed.server.ts) and never updated again. The Records "Status" column reads this β so it always showed "Draft". -
A separate signing-request doc β
aote-system/ir56mSigningRequests/{requestId}, fieldstatus(draft β assigned β sent β signed β voided). The sign handlerrecordSignature()flips THIS to'signed'. The Records "Signing" column reads it via/api/ir56m-signing/lookupβ so it correctly showed "Signed".
Unlike WOPC β which mirrors its signed/voided state back onto the WOPC doc itself β
the IR56M signing flow was built with an explicit "no doc-mirror" note, so the
filing doc's own status was left stranded at 'draft'.
Fix (commit below)¶
Mirror the signing lifecycle onto the filing doc itself, the way WOPC does β so the IR56M doc is its own source of truth for the "Status" column.
lib/taxHK/ir56m/filings.server.ts:- New
setRecipientStatusServer({ endingYear, payeeId, status })β a targeted single-field update ofrecipients[].status(leaves form / frozen / history untouched; no-op if absent or already at target). saveIR56MFilingServernow also guardsstatus(alongside the existing frozen-total guard): a routine form-save carries the seeded'draft', so a prior'signed'/'filed'is preserved rather than downgraded.lib/taxHK/ir56m/signingRequests/operations.server.ts:recordSignaturemirrorsβ 'signed';recordVoidedmirrorsβ 'draft'(a voided IR56M needs re-signing). Best-effort + lazy-imported β a mirror failure never unwinds the signing transition (the request doc stays authoritative and the "Signing" column reads it directly).
Mapping implemented (minimal, lowest-risk): draft β signed only β signed forms
now read 'signed'; void reverts to 'draft'. The 'confirmed' (sent for signing)
and 'filed' (after the completed copy is distributed) stages are left available to
wire later if the owner wants a richer lifecycle.
Decision log¶
2026-06-29 β β Read AGENTS.md before working this ticket. Source: Records (Infrastructure) Β· https://claude.ai/code/session_018RDB37kCqfouHdygVXTAtD
Owner asked (verbatim): "like the WOPCs, an IR56M's status should be stored on the
IR56M firestore doc itself β¦ but not on a separate doc?" β confirmed the field
existed on the filing doc but was never advanced, and implemented the WOPC-style
mirror. Within T-047's signing scope (cross-linked, not a parallel task). Verified:
tsc --noEmit clean repo-wide; the pure IR56M unit tests cover filing.ts (unchanged)
β these server modules aren't exercised by them (vitest isn't installed in the cloud
sandbox). Runtime confirmation is owner-on-deploy (sign a form β Records "Status"
reads "signed").
Blast radius: IR56M signing operations (recordSignature/recordVoided) +
saveIR56MFilingServer now also touch recipients[].status on the filing doc; the
Records "Status" column now reflects signing. Agents on T-047's signing flow should
know the filing doc is now a status mirror.