Live (part 1) — notify + email on AUTO-MATCH linked
Goal¶
Part 1 of the "make it live" initiative (T-037 = umbrella + full audit). When the
auto-matcher LINKS a tx↔invoice, fire the existing notifyPaymentMatched (in-app + email
at severity ≥ warning). Today applyVendorLink (matching/vendorMatch.server.ts ~82) only
console.logs. #1 "feels not live" gap — the producer already exists; just call it from
the auto-link path (and pick a severity that emails). Recipients: ACCOUNTING_NOTIFICATION_ROLES.
Log¶
- 2026-06-14 created (T-037 split, owner).
Decision log¶
2026-07-09 — re-scoped (half shipped along the way) + routed to Accounting (Diagnostics)¶
- ✅ Read AGENTS.md. Backlog-review probe (2026-07-09):
notifyPaymentMatchedIS now wired on the transaction-PATCH path (pages/api/accounting/transactions/[id].ts— one notification per NEWLY matched invoice), so half this task shipped incidentally. Remaining scope = the AUTO-matcher path only:applyVendorLink/ the matching libs still contain zero notify calls — an auto-link lands silently. Owner routing (2026-07-09, verbatim): "route T-038, T-040, T-072, T-083, T-051" per the review recommendations → Accounting (Diagnostics) (same producer family as T-040/T-041); queue behind their active T-156/157/158 cluster. - Source: EOP Local Assistance (fork) · session edb0abc7-6373-449b-8e31-379fd38d391b
2026-07-10 — BUILT + SHIPPED (owner: "proceed") — status → done¶
- ✅ Read AGENTS.md · checked the board by scope (no dup — T-162's waves govern consumption, not producers; verified zero notify calls in the matcher pre-change) · tracking T-038.
- Source: Accounting (Diagnostics) · https://claude.ai/code/session_01G58Y71noihrYCDEDMexmea
- What landed: new producer
notifyVendorAutoMatched(notify.ts, exported via the barrel) + the call inapplyVendorLink(vendorMatch.server.ts) — the single link point both matcher directions (invoice-side + transaction-side) funnel through, so one wire-up covers every auto link, including the periodic re-run sweep in hooks.server.ts. - Design decisions (why not exactly the old goal text):
- The goal said "fire the existing
notifyPaymentMatched" — that producer is CUSTOMER-invoice shaped (projectId/year/invoice-preview URL) and severityinfo(never emails). The vendor matcher links VENDOR invoices to debits; forcing the customer shape would produce broken action links. Built the automatic sibling instead, copying the one-per-newly-linked pattern and failure tolerance per the 2026-07-09 re-scope ("copy its pattern, don't re-invent"). - Type reused (
payment_status), no new taxonomy entry — slots into T-162's preference matrix as-is; zero coordination burden on User Management. - Severity
warning→ in-app AND email (the task's stated goal: "in-app + email at severity ≥ warning") — an automatic ledger change with no human in the loop is what the offline-reach layer exists for. - Message is self-contained (amount, tx id, vendor, invoice, matched fingerprint) per the
hide-and-seek rule fixed in T-162; action link →
/accounting?tab=transactions. - Notify failure never unwinds the link (
try/catch+ log; the link is the source of truth). - Non-link outcomes (ambiguity / new vendor) deliberately stay silent here — they are T-041's suggestion notifications.
- Verification: 5 new tests (
vendorMatchNotify.test.ts): one-candidate → exactly one notification with full payload (both directions); ambiguous + new-vendor → silent; notify failure → link survives. Suite 653/653; unfiltered tsc clean. - Commit SHAs (append-only): this ship commit (T-038 in subject; merged via PR).
- Deploy: pending (main 🟡🟡 manual — done means merged, not deployed).
- Blast radius: notification volume only — accounting roles now receive one warning-severity notification (+ email) per vendor auto-link. No matcher logic, amounts, or data shapes changed.