Tighten oversized vertical padding on page title headers
The gradient page-title headers had far more top/bottom padding than the horizontal inset where the title text starts, wasting vertical space. Bring the vertica...
Use the lightning-bolt icon for Leads to match the /leads UI
The Leads option used AccountTreeIcon; the /leads "Leads Available" actions use BoltIcon (@mui/icons-material/Bolt). Switch the registry's Leads icon to Bolt so...
De-slop remaining Quick Tips content + make leads tips collapsible
- security, operations, account, and CRM settings help columns: removed all emoji (💡 🚫 ⏳ ✅ 🌍) and rainbow-coloured bullets; every list marker is now one ...
Pipeline per-transaction grouping was broken
TransactionSummaryDTO.loanUids carried LOAN-FILE uids, but the pipeline console keys rows on the APPLICATION uid — so grouping silently fell back to one row per...
**************** (the doc-requirement key)
Surfaces the backing LoanFile.uid so the pipeline can map an app row to its document requirements.
Settings topics are expand-only, not links
Settings topics (Essential Setup, CRM, Security, …) are group headers with no page of their own — only their sub-topics are real destinations. Drop the topics' ...
Member-vault upload was broken (access_level NOT-NULL)
The account-level imaging path had never actually run (0 vault Imgs in prod): uploadDocument was passed accessLevel=null. Pass CONFIDENTIAL for borrower PII (ID...
Stop party fragmentation — enrich the stamped party in place
Live E2E showed a single loan producing 4 parties for 2 humans (an empty placeholder was created at borrower-create before identity, then a 2nd party at identit...
Clean rail alignment, uniform top-bar tiles, and replace Settings slide-out with a sub-option menu
- NavPri logo: the 56px tile made the top of the rail wider than the 44/48px options below it, and collapsed options rendered left-aligned. The logo now sha...
Mlos requirement single-live index keyed per-human (borrower_uid)
Drop the party-only **************** (it would reject a legitimate 2nd co-borrower requirement); create **************** on **************** Already applied to ...
Satisfy-across confused-deputy IDOR + account party self-heal
- HIGH: satisfy-across gated on the path partyId but fanned out over the DOCUMENT's own party downstream; verify the document belongs to the authorized party ...
Party-link cross-human leak + account-level backfill
Adversarial-review fixes: - HIGH: drop the memberId dedup that conflated the loan's isPrimary borrower with the account OWNER — a member self-creating a loan ...
Self-heal party links before enriched requirement read
listDocumentRequirements calls ensurePartyLinks so requirement rows always carry an accountBorrowerPartyId (the borrower upload/satisfy target).
Vendors-products — white-label default-product terminology, dialog option, FFA header
- Rename 'KamoMLOS' → 'Borrower Origination Web Portal' everywhere in the vendors-products UI (star tooltip, snackbars) — this is a white-label multitenant pr...
Default-product set failed — HQL bulk UPDATE disallows the vendor→org join
setDefault used a bulk 'update LeadVendorProduct ... where p.vendor.id in (subquery)' — Hibernate bulk updates reject the implicit association join, so the call...
CreateBlank must persist the app graph before bootstrapBorrower
bootstrapBorrower seeds a Declarations/HMDA shell whose NOT-NULL borrower FK requires the Borrower to be persistent; createBlank called it BEFORE the cascading ...
Borrower self-create = createBlank then stampOwnershipAndGet (two txs)
Sequence the borrower ownership stamp as a separate service call after createBlank commits, so the new borrower/declarations graph is flushed before the account...
Stamp borrower ownership in a separate tx (avoid transient-graph cascade)
createBlankOwnedByMember re-saved the app graph in the same tx as createBlank, before the borrower/declarations rows were flushed → TransientPropertyValueExcept...
Drop light gray text; use dark gray-800 for labels/secondary
Medium grays (gray-500/600/700, #6b7280/#9ca3af) read as disabled. Push all secondary text and labels to gray-800 / #374151 across the detail page, shared Field...
Governance proxy PUT/DELETE + per-org governor overrides UI (D4)
- Governance proxy now forwards PUT/DELETE (the platform-default save + per-org delete were unreachable — GET/POST-only proxy). Adds mlosDelete http helper. -...
Stop loan-pipeline grid flicker loop; full-width detail
- Loan pipeline datagrid: the grid was wrapped in a SectionCard 'fill' body (overflow:auto) around a height:100% AG Grid, causing a ResizeObserver/height fe...
Fire the accept-lead popup on becoming Available; drop the fire animation
The popup now triggers on the rising edge of (a credit lead is acceptable) AND (nav-top status is Available) — so it fires both when a lead is already waiting a...
Scan mlos.intake repos (§5.A) + drop orphan mlos_aus_connection_config (D40)
- Add com.kamo.z.shared.mlos.intake to @EnableJpaRepositories — the §5.A **************** was component-scanned but not a JPA repo, aborting KI startup befo...
Honest return type for updateStageOverride (raw row, not StageAutonomyView)
Review observation: the PUT returns the raw stored override entity, not a StageAutonomyView (the effective/floor recompute is GET-only). Typed Promise<unknown> ...
Consumer review findings - MLOS secret, HTTP timeouts, max-deliver clamp, 4xx skip, boot rebind
Adversarial review (2 lenses; 5 verifiers died on a session limit - adjudicated the 9 raw findings by hand, 6 real): - WRONG SECRET (confirmed by hash compariso...
Type TrialStatus ids as string to match Long-as-string serialization
BillingService now serializes Long as a JSON string (org/member ids are CockroachDB unique_rowid() > JS MAX_SAFE_INTEGER). Align TrialStatus.organizationId and ...
Serialize Long ids as strings to stop org-id precision loss
Org ids are CockroachDB unique_rowid() values that exceed JS MAX_SAFE_INTEGER. BillingService was serializing them as raw JSON numbers, so kamo-internal's JSON....
Register JSR-310 on the consumer mappers - real envelopes carry an Instant occurredAt
E2E caught it: both real decision.routed events were dead-lettered as 'unparseable' because the bare ObjectMapper cannot deserialize java.time.Instant. findAndR...
Hot Reassign — always post the required call note; keep current assignee selectable
Review follow-ups: (1) drop the comment-dedup ref that could silently skip the required note on a later attempt (or an edited retry) after a failed mark — alway...
MlosConfigChangeLog date_created — drop @ColumnDefault (duplicate default)
Both @ColumnDefault("now()") and columnDefinition="TIMESTAMP DEFAULT now()" made Hibernate emit 'TIMESTAMP DEFAULT now() default now()', which CockroachDB rejec...
Exclude /api/voip/sms/templates from OTK session filter
The doc-07 SMS template endpoints are session-less internal calls guarded by InternalAuthFilter (X-Internal-Auth), but OTKValidationFilter still ran on them and...
Apply adversarial-review findings on the steward write composers
- a11y: WAI-ARIA arrow-key radio pattern (shared onRadioKey helper) for the verdict + run-purpose segmented controls (they were keyboard traps); focus retur...
Close residual cross-org existence oracles + cap WORM-bound JSON blobs
Adversarial-review findings MLOS-W-01/03/04: - the 404-normalized empty list envelope now echoes the request's identity keys **************** so unknown, fore...
MediaObjTransit.date_created insertable=false so DB default fills it
The builder never set dateCreated; Hibernate bound NULL and violated the NOT NULL constraint, breaking addMembersToSession (and thus the social lead-accept hook...
Atomic claim before lead creation — prevent orphan pooled leads
social.lead.new can be processed concurrently (old + new SecurityService pod both hold a core-NATS subscription during a RollingUpdate → one publish delivered t...
Don't fire the new-lead popup on refresh / when not Available
myStatus from AvailabilityContext defaults to 'AVAILABLE' until two async fetches (/user-info then /members/me/availability) resolve, so on a browser refresh th...
Underwriting review polish (i18n, a11y, contrast, enum humanize)
Apply review findings: localize frozen/yes/no + humanized aria-labels, humanize enum pills, phase title-case parity (shared titleCase), null-safe ausKindId, WCA...
Fail-closed tenant guard on underwriting waivers/validations
Review found the org guard was a no-op on the common empty-list case for the by-id waivers/validations reads (which the MLOS service does not org-filter), leaki...
Add missing /api/security/lead-imports proxy route; default to Import Templates
- The base GET/POST /api/security/lead-imports had NO Next proxy route.ts (only sub-paths did), so Past Imports fetch (and the import POST) 500'd at the Next ...
Gate FFA acceptability on suspension in available-summary + available
available-summary now resolves the member's allotment and skips the product when suspended BEFORE the free-for-all short-circuit, and available() gates creditOk...
Suspension now actually blocks acceptance (alert + accept + FFA)
findApplicableAllotments filtered 'AND la.isActive = true', so getMostSpecificAllotment returned a less-specific ACTIVE fallback (or nothing) when a member's sp...
Implement POST /api/bulktext/send internal transactional SMS
SecurityService's BulkTextSmsClient (password-recovery + account-settings SMS) has always POSTed **************** to /api/bulktext/send, but the controller was ...
Send leadId as string when creating a comment
parseInt() rounded lead ids past JS MAX_SAFE_INTEGER, so the backend looked up a nonexistent lead and returned 404, surfacing as 'Failed to create post' on the ...
Accept leadId as string in createPost to preserve CRDB id precision
Lead IDs are CRDB unique_rowid() values that exceed JS MAX_SAFE_INTEGER. The frontend now sends leadId as a string; parse both String and numeric forms so findB...
Resolve member names on /leads/credits + link to their account
The member column and filter showed raw ids because the name map was built from /api/security/members, whose CockroachDB Long ids serialize as JSON numbers and ...
Make EditableCard onEdit optional so reassignment gating type-checks
The assignment card passes `canReassignManually ? startEditAssignment : undefined` to EditableCard.onEdit, but onEdit was typed `() => void` (required), failing...
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.
