Prove closed-loan trainer convergence + retire + concurrency
Drives ClosedLoanTrainerService across successive passes with the (pre-live) MeridianLink wire and vision read stubbed, locking the behaviour the design hinges ...
Cache closed-loan docs across passes; retire on solve/exhaust
The trainer now refines a loan over multiple passes instead of one-and-done: - TrainingDocStore is a PERSISTENT, deterministically-keyed cache (key = hash of...
Multi-pass closed-loan training — pass counter + corpus upsert key
The closed-loan trainer now re-reads a loan on successive passes until its extraction reproduces the loan outcome, so: - LeadLosLink.closedLoanPasses drives a p...
Trainer must not clobber its own claim or an operator's pause
After the atomic claim() bulk-updates the row to RUNNING, mirror that in the in-memory entity — the pool thread has no open session, so a later full-row save wo...
Status-preserving progress write for the closed-loan trainer
run is RUNNING, without touching status. An operator pause (status → PAUSED) can no longer be clobbered by a full-row save from the pool thread — the guarded up...
Harden closed-loan trainer — concurrency, idempotency, limits
- Concurrency: in-process activeOrgs guard + the DB claim() so this instance never double-walks an org and two replicas can't overlap; a run whose heartbeat...
Harden closed-loan trainer — run lock + per-loan idempotency
- ClosedLoanTrainingRun.claim(): atomic conditional UPDATE that takes ownership of a run only when it is not already RUNNING or its heartbeat is stale (prev...
Closed-loan auto-trainer panel on the platform Document AI tab
Top-level owners can run + monitor the MeridianLink closed-loan trainer across every tenant from Settings → Platform → Document AI. Per-org rows show status, lo...
Closed-loan auto-trainer + platform control endpoints
A closed loan is ground truth: its MeridianLink metadata is the answer key, its documents are the input. ClosedLoanTrainerService walks each MeridianLink org's ...
Org-scoped loan roster query for the closed-loan trainer
**************** gives the trainer every LOS-linked loan for an org+provider, each carrying the externalLoanName it reads status + documents for.
Closed-loan auto-trainer foundation (MeridianLink ground truth)
Foundation for training document extraction against funded loans (the answer key): - ClosedLoanTrainingRun entity+repo — per-org run control + live counters - E...
DOC_REJECTED email carries the plain-language reason
Both reject paths now pass **************** to the borrower's rejection email instead of the raw enum literal.
Plain-language borrower messages for document rejections
RejectionReasonType was a bare enum (the borrower literally saw "ILLEGIBLE"). Each value now carries a borrowerMessage() remediation string + a messageFor() map...
Platform review queue on the Document AI tab
The Document AI tab now hosts the cross-tenant review queue: low-confidence extractions from every lender, lowest-confidence first, with inline confirm/correct/...
Platform QC queue + review endpoints (top-level owners)
system-config gains a cross-tenant extraction review queue + confirm/correct/reject, gated to top-level owners — the central labeling surface for the shared mod...
Platform-wide QC review (cross-tenant labeling for the shared model)
A document is a document — extraction and the model are platform-level, not per lender. Adds a cross-tenant NEEDS_REVIEW queue + QcReviewService.platformReview ...
Platform extraction config + cross-org corpus/accuracy/export
system-config GET/PUT now carries extractionAutoApplyConfidence + extractionModelId and reports the platform-wide corpus size + per-doc-type accuracy; adds a cr...
Platform "Document AI" configuration tab
Adds a Document AI tab to **************** the auto-apply confidence threshold, the registered fine-tuned model id, the platform-wide training-corpus size + per...
Platform Document-AI config on SystemConfiguration + cross-org corpus
Adds **************** (default 0.85) + EXTRACTION_MODEL_ID to the platform SystemConfiguration singleton — the platform-wide levers for the QC gate and the regi...
Org-wide "Document QC" steward sub-tab
Adds a Document QC console to the mortgage steward strip (?sub=docqc): the org-wide queue of low-confidence AI extractions grouped by loan, with inline confirm/...
Org-wide QC queue (employee review portal)
Adds an org-scoped NEEDS_REVIEW query + QcReviewService.orgQueue so employees can work every loan's low-confidence extractions from one portal, not one loan at ...
Steward Document-QC review box on the application detail
Adds a "Document QC" section to the loan detail: the queue of low-confidence AI extractions with confirm / correct / reject per field (each decision trains the ...
QC endpoints + confidence-gated extraction + gift/tax reads
- QcController (/api/security/mlos/qc, LOS_VIEW_PIPELINE): review queue, review action (confirm/correct/reject), NDJSON training-data export, per-doc-type a...
Confidence-gated QC box + labeled training data + gift/self-employment reconcile
QC engine (Phase 4 core): - VerifiedFact gains first-class EXTRACTION_CONFIDENCE, DOC_TYPE_CODE, QC_STATE columns (QcState: **************** Reconciliation ...
Raise guacamole memory 1Gi→2Gi to stop OOM mid-RDP-session
The Tomcat webapp idles near ~800Mi, so a 1Gi ceiling left almost no headroom. Opening an RDP session pushed RSS over 1Gi and the container was OOMKilled (exit ...
Extract benefit/award income (SSA, pension, child support)
Adds extraction prompts for SSA_AWARD / PENSION / CHILD_SUP (AI reads the gross monthly amount + a label), and stamps the OtherIncomeSource id deterministically...
Reconcile otherIncome.* facts into OtherIncome rows
Extends fact reconciliation with an otherIncome.* branch: award/benefit documents (Social Security, pension/retirement, child support) land a real OtherIncome r...
Auto-classify uploads to catch wrong-document uploads
A cheap LIGHT-tier "what is this document?" pass on the first page classifies the upload into a coarse family and compares it to the requirement's asserted type...
Extract 12-month bank statements + written VOE
Widens vision extraction to two more borrower doc types that reuse the existing reconciliation vocabulary (zero reconciliation risk): BANK12MO reads as an asset...
Multi-page PDF document extraction (Phase 2)
The vision path was image-URL only, so a borrower's multi-page PDF (bank statement, tax return) couldn't be read. Now: - VaultDocPublicController serves ?page=...
Full-res per-page PDF render for document extraction
Adds DocPageRenderService + POST /api/conversion/render-page (page N → PNG at 150 DPI, capped 300) and /page-count. This is the read-quality companion to the 30...
Rebuild against kamo-shared-library SSN encrypt-on-write
No SecurityService source change — this empty commit triggers the CI, which clones kamo-shared-library main at build time, so the deployed image picks up the ne...
Capture + encrypt full SSN on the borrower application
The application posture needs the borrower's REAL Social, not a last-4 (a lender can't do anything with 4 digits). Borrower.ssnEncrypted existed but was never w...
Optional ?phone= reverse lookup on GET /api/security/leads
The softphone CRM tab resolves an active caller number to a lead. Add an optional phone RequestParam that filters the org lead list by canonical (last-10-digit)...
Wire CRM Integration tab to real data
Replace the mock CRM tab with a live reverse-phone-lookup panel. - Resolve the active call / dialpad number to a CRM lead via leadsApi.searchByPhone (new ?pho...
Support "unblock forever" remote-image consent
Adds a wildcard consent (allowAll / isAlwaysAllowed) so a member can opt to display external images in every message. Reuses the existing consent table via a re...
Add "unblock forever" option for blocked external images
The external-images gate now offers two actions: Unblock (this message, as before) and Unblock forever, which displays external images in every message going fo...
A different preferred name forks a new lead
A genuinely different preferred name (compared case-insensitively with outer spacing trimmed) is a different person, so create a brand-new lead instead of renam...
Reach the borrower's OWN officer directly, no support-right gate
Drop the ACCEPT_SUPPORT_TICKETS requirement from assignToPreferredAgent: the borrower's assigned loan officer is reachable regardless of whether they're a confi...
Proxy GET /lo-presence to MediaService
The support-session proxy already forwards the raw body, so the merged widget's preferredAgentMemberId reaches MediaService untouched. Add the presence proxy so...
Direct-to-assigned-LO routing + LO presence endpoint
Powers the borrower portal's merged LO/chat widget: - **************** direct-assigns a public-chat ticket to a SPECIFIC agent (the borrower's assigned loan o...
Expose assigned-LO member id + phone for direct chat + presence
The merged LO/chat widget needs to (a) target the assigned officer directly in the borrower's live-support session and (b) query the officer's live presence. Bo...
Assign a loan officer to a NAME-ONLY lead (before email/phone)
The borrower portal already creates the lead the instant a name is given, but enterAssignmentPoolIfActionable kept a name-only lead OUT of the credit accept poo...
Load history via per-tab OTK path + retry/error UI; drop preview toggle
- Root cause of empty chat history on long-lived tabs: media proxy routes forwarded only the *** cookie (lapses ~30min) instead of the per-tab X-***-Token; ...
Stop putting message content into missed-message emails
Remove messagePreview computation, the ledger PREVIEW write, and the messagePreview template variable; drop the includePreview preference. Emails now carry send...
Inline-CID org logo (SVG->PNG) so it renders in Gmail; remove message content; preserve From-domain case
- FIX (security): notification emails carry no message body — remove messagePreview from template vars, ledger, samples and the settings toggle. - FIX (logo):...
Drop message-body preview paragraph from missed-message email templates
Security: notification emails no longer render any message content; the member signs in to read messages. Sender + count + CTA only.
Missed-message email deep links, auth-continuity stash, unread chat auto-popup, notification settings
DeepLinkToolBootstrap opens ?openChat/?openTicket tool windows (params survive the login round-trip via a sessionStorage stash captured pre-auth and preserved a...
Missed-message email notifications (chat + support) with per-source suppression
Durable NATS consumer chat-email-notifier on chat.session.> feeding a MESSAGE_EMAIL_NOTICES ledger (PENDING/SENT, per-sender for chat, per-ticket for support), ...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
