Correct the rationale on pre-created schemas
KamoInitializerService does set **************** true, so it creates these schemas itself. The previous comment claimed it did not. The file stays as explicit b...
Administrator bar panels rendered their key paths, not their copy
TipPanel took the panel's DOM id in a prop called `id` and then built its message keys from that same `id`, so every panel asked for **************** and next-i...
Let the access log fill its pane and page from the server
The tab bar already says "System Access Logs", so the h4 above the stats was the page's name twice. Dropping it also lets the pane use the shell every other Sec...
Stop the list scrolling when it already fits
Three things added height that was not content, so a list short enough to fit still got a scrollbar: - the infinite-scroll sentinel was rendered unconditionall...
Restore the administrator bar changes reverted by 3926d1d8
3926d1d8 carried AdminQuickLinks.tsx back to its ae45fc9c^ blob, undoing the org plural label, the short Blocks/Logs names and the gap removal. Same content as ...
String row ids, org-coloured controls, page icon, centred error bar
Creating a book and selecting it answered "Not found". CockroachDB unique_rowid() ids are 64-bit — a real one is 1200081912680906758 — and JSON.parse rounds any...
Publish row ids as strings — a new book 404'd the moment you selected it
CockroachDB unique_rowid() produces 64-bit ids. A real one from contact_books is 1200081912680906758; JavaScript's JSON.parse rounds anything past Number.MAX_SA...
Stop renewing the shared *** TTL for idle users
Fifth service holding its own copy of KSessionService, and the fifth sliding the shared *** TTL on every read. Each one alone was enough to keep a session alive...
Stop renewing the shared *** TTL for idle users
Caught with redis MONITOR: this pod was issuing GET + PEXPIRE against a *** key whose owner had been idle for over an hour, seconds after SecurityService had co...
Stop /api/user-info renewing the TTL for idle users
This route writes the *** TTL straight to Redis, so it bypassed the gating in SecurityService, MediaService and ChatService entirely — and useUserInfo polls it ...
Stop renewing the shared *** TTL for idle users
This service keeps its own copy of KSessionService, and it slid the TTL on every read. Gating SecurityService alone therefore fixed nothing: kamo-internal point...
Recover a received attachment whose first request was rejected
A video arriving in a conversation could not be played until the page was reloaded, while a video the member had just sent always played. Both copies were byte-...
Give each organization a real transaction boundary
StorageSnapshotSweep.catchUp carried @Transactional(REQUIRES_NEW) and was called from sweep() on the same bean. Spring applies @Transactional through a proxy, s...
Record message sizes instead of writing zero
SearchIndexService wrote sizeBytes = 0 for every message it ever indexed, under the comment "Not available from envelope". It was available — the fetch profile ...
Popover X closes the window, not just the popover
Dismissing the popover already had two affordances (click outside, Escape), so an X that only dismissed it was a duplicate and left no way to get rid of the hea...
A platform product is not one of its own tenants
isOrgEntitledToApp exempted only the top-level org, so an org marked isPlatformProduct was billed as if it were a customer. sign.pink sits on a FREE_DEFAULT sub...
Enforce self-or-owner on an account, not just the org boundary
Follow-up to the cross-org gate, now that the rule is decided: inside an organization you may manage your own billing account, and an organization owner may man...
Stop one organization reaching another organization billing
/api/billing/accounts scopes its listing by the X-Org-Id header, but every route beneath /{accountUid} took the id straight from the path and never checked who ...
Split Available on the catalog verdict, and stop Stage publishing an app
The account Apps tab derived Available / Not Available from development stage, so it contradicted the platform catalog the moment an operator published or withh...
Only real entitlement roots get the platform app rows
Owning subscription plans was treated as proof of being an entitlement root. It is not: a customer org runs its own commerce markets and sells its own plans whi...
Answer "is this sellable" from the app catalog, not the enum
Availability became operator-editable at runtime, so deriving it from ServiceType.getStage() meant publishing MLOS in Apps and Features left it invisible on the...
Close four ways round the vertical and app gates
SecurityModelMarketController read and mutated security-model market attachments with no session check, no org scoping and no right — any caller could pass any ...
Load Allowed Apps from an endpoint tenants can actually read
appCatalogApi.list() is platform-owner-only, so on any tenant org the Branch Types editor showed no apps and the save guard — which exists to stop an empty cata...
Validate add-on codes before they can grant an app
active_addon_codes was written straight from the request body. That was harmless while nothing read the column, but it is now an authorization input: an add-on ...
Same alias NPE in the initializer seeders
resolveAll() has no entry for a deprecated alias sharing an id with a live app, so looping ServiceType.values() and dereferencing the result would have thrown m...
Stop a page load from persisting the entitlement projection
computeEffectiveFeatures added the caller's Hibernate-managed OrgFeature rows straight to its output and then flipped isActive on them. Its own javadoc calls th...
Stop iterating ServiceType.values() against the resolved catalog
resolveAll() omits the deprecated aliases that share an id with a live app (DOC_MANAGER/DOCS, AI_CHAT/AI_SUPPORT), because those have no catalog row of their ow...
Bind the rename cutover as a Timestamp, not a String
CockroachDB refuses <timestamp(6)> < <varchar> rather than casting, so the app-config repair threw on its first statement every boot: 'unsupported comparison op...
Repair the second name-persisted site of the LOS rename
**************** is @Enumerated(STRING) and holds RoleRightType names, so a default role granting mortgage stores "LOS_VIEW_PIPELINE". That is the third place t...
Point the mortgage surface back at the mortgage rights
Companion to the shared-library change. These 13 controllers all guard mortgage endpoints — HMDA LAR, pipeline, application intake, disclosures, credit orders, ...
Stop mortgage endpoints enforcing a personal-loan right
The LOS_* -> MLOS_* rename was applied to the enum declaration and nowhere else. Because the freed names were immediately re-declared as the personal-loan right...
Bound the LOS rename repair to rows that predate the rename
The repair matched on the string alone and ran on every boot, so it stopped being idempotent the moment anyone granted the personal-loan app: a row holding 'LOS...
Master model honours a runtime retirement; drop a dead guard
provisionMaxedOutMasterModel force-enables every app for the platform org, and that breadth is deliberate — pre-launch dogfooding is what the model is for. But ...
Two more places that answered "is this app offered" from the enum
Both were missed when FeatureController moved onto the app catalog, and both would have disagreed with it the moment an operator published an app. Organization...
Repair mortgage grants orphaned by the LOS to MLOS rename
ServiceType is persisted in two places and the 2026-08-08 rename only accounted for one. ORG_FEATURES.FEATURE_TYPE stores the numeric id, so keeping mortgage at...
Render Contact sales for add-ons with no list price
PageAddOn.price was typed number and built with Number(addon.pricePerUnit), so an add-on with no list price — the enterprise-negotiated origination systems — re...
Show negotiated pricing instead of $0.00 for enterprise-only add-ons
The origination add-ons carry no list price — they are negotiated per agreement — and formatCurrency(null) renders $0.00, advertising an enterprise module as fr...
Hide unreleased apps from the Plans & Billing catalog
**************** back the tab where a customer chooses what to subscribe to, so it must not offer a product still in the Not Available list — the same rule the ...
Never offer an unreleased app on a buying surface, bundles included
The stage filter only ran for the public marketing proxy. This endpoint also feeds the in-app SubscriptionOrderWizard, which is where a customer actually pays, ...
Keep the is-prefix on PlatformAccountSummary's wire names too
Same Lombok/Jackson hazard as PlatformOrgRow: isTopLevel() loses its `is` on serialization, so the DTO put `topLevel`/`platformProduct` on the wire while the fr...
Declare security matchers explicitly before the next build breaks startup
kamo-shared-library 1.5.0 was republished today with spring-ws-core as a new transitive dependency, so Spring Boot now auto-registers a second servlet (MessageD...
Keep the is-prefix on the wire for isTopLevel/isPlatformProduct
Lombok generates isTopLevel() for a `boolean isTopLevel` field and Jackson strips the `is` prefix, so the live endpoint was serializing `topLevel` and `platform...
Grandfather orgs already running a gated commerce market
Gating MORTGAGE behind MLOS made the gate unsatisfiable for tenants: MLOS is still PLANNING, and FeatureController.enable refuses a non-COMPLETED app for a chil...
Declare security matchers explicitly so the service can start
The service has not deployed since 2026-07-03; every pod since has crash-looped before the context loaded: This method cannot decide whether these patterns a...
Seed app entitlement for every root, and stop inventing plan tiers
Two defects found by checking prod before flipping kamo.entitlement.fail-open. Sign Pink is a second entitlement root (isPlatformProduct, with its own FREE/BUS...
Raise the Next body cap that was truncating every large upload
THE cause of the failing 3 GiB attachments, and it was ours, not the network. **************** was '500mb'. It is not a rewrite/middleware setting: Next wraps ...
Fail a dead upload in minutes instead of holding it for an hour
connectionUploadTimeout is the tolerated SILENCE between reads, not a budget for the whole transfer. Setting it to an hour to 'match Traefik' confused the two: ...
Stop a dead upload spinning forever, and say what 100% means
A stalled upload sat at 100% with the bar full and no way out. Three separate reasons, all of them mine. XMLHttpRequest has no useful read timeout: when bytes ...
Let an in-flight upload finish instead of dying on a rollout
A 2 GiB chat attachment reached 100% and then failed with 'Bad Gateway' because a deploy landed on top of it: the pod took SIGTERM at 03:34:36 and the transfer,...
Make a failed upload say what happened, and log enough to diagnose it
A 2 GiB attachment failed at the end of a four-minute transfer with 'Upload failed: upload failed Internal Server Error' — a doubled prefix wrapped around a mes...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.