uid: T-179 title: HKFRS s.33 related-party gate β carve-out for money going INTO GL 1120 (Due from Director) status: done area: accounting created: 2026-07-24 updated: 2026-07-24 owner: girafeev1 related: T-168
T-179 β Related-party approval gate carve-out for GL 1120 inflows¶
Why (owner, 2026-07-24, verbatim)¶
"Can you turn off the gate of 'Categorizing this transaction with a related-party payee requires approval (HKFRS s.33).' when matching a tx for money going into 1120 (instead of leaving it)"
Categorizing any transaction to GL 1120 "Due from Director" always links a director payee (the
assign-account handler force-requires JC/JN for 1120), so the related-party approval gate
(HKFRS s.33) fired on every director-current-account categorization. The owner wants that
friction removed only for money going INTO 1120 β the company disbursing on the director's
behalf, which grows the receivable β while keeping the gate for money leaving 1120 (an
incoming director repayment).
Direction mapping (the crux β verified three ways)¶
"Into 1120" vs "leaving 1120" is the 1120 balance perspective, not the bank's:
- GL_DUE_FROM_DIRECTOR = '1120' is a debit-normal asset (constants.ts).
- directorCurrentAccount.server.ts buildLine: dueFromDelta = debit β credit on 1120 (a debit
posting grows the balance β "into 1120").
- derivedJournals.server.ts: a bank transaction with isDebit === true posts a DEBIT to
the categorized GL (Dr 1120, Cr Bank).
Therefore:
- isDebit === true β Dr 1120 β balance grows β "into 1120" β EXEMPT (no approval).
- isDebit === false β Cr 1120 β balance shrinks β "leaving 1120" β still gates.
(An outgoing bank payment categorized to 1120 = the company paid out for the director; an incoming receipt = the director repaid.)
What landed¶
- Pure policy predicate
isRelatedPartyGateExemptCategorization(accountCode, isDebit)inlib/accounting/constants.ts(next to the otherisXxxCodeGL classifiers β no server deps, so it is unit-testable in isolation): returns true iffaccountCode === '1120' && isDebit === true. Re-exported fromlib/rbac/relatedPartyGate.tsso the whole gate policy still reads from that one audit-control file. - Wired into the
assign-accounthandler (pages/api/accounting/transactions/[id].ts): when the exemption applies, the related-party gate is skipped and the exemption is logged (server-log audit trail); otherwise the gate runs exactly as before. Scoped to GL 1120 only β 2200 and every other account are untouched; the director-payee requirement for 1120 stays.
Scope notes / deliberately NOT changed¶
- The PATCH path (editing a transaction's
expenseMetadatapayee β message "Linking this transaction to a related party requires approval") is unchanged. The owner's request and quoted message are the categorize/assign flow; re-gating on a later payee change to an already-1120 transaction is defensible (s.33 wants to see a related-party reassignment). Flag for the owner if they want the same carve-out on that path. - GL 2200 (Director's Loan, the liability side) is not exempted β only 1120 was requested.
Verification¶
5 new unit tests (relatedPartyGateExemption.test.ts): exempts into-1120 (isDebit true); still
gates leaving-1120 (false); safe-default gates when direction unknown (undefined/null); never
exempts 2200 or unrelated accounts. Unfiltered tsc clean. Full suite green except 4
pre-existing env-flakes in workspace/billing/ingest.test.ts ("Unable to detect a Project Id") that
fail identically on a clean tree in this reprovisioned sandbox β unrelated to this change (verified
by stash-and-rerun).
- β Read AGENTS.md Β· checked the board by scope (no dup β no task owns the related-party gate; this is new scope) Β· tracking T-179.
- Source: Accounting (Diagnostics) Β· https://claude.ai/code/session_01G58Y71noihrYCDEDMexmea
- Commit SHAs (append-only): this ship commit (T-179 in subject; merged via PR).
- Deploy: pending (main π‘π‘ manual; done = merged).
- Blast radius: the HKFRS s.33 related-party approval gate on
assign-accountonly. Behavior narrows the gate for exactly one case (outgoing payment categorized to GL 1120); all other categorizations, all of GL 2200, the PATCH path, and the approval-token flow are unchanged.