Make label: search read the table that records labels
The clause tested si.label_ids, an array column on the search index. Nothing has ever written it — labelling a message inserts into email_metadata.message_label...
Name the remaining twelve switches, and guard the trap that unnamed them
MUI 7 drops `inputProps` on Switch — silently, with no warning and no type error, so the aria-label never reaches the DOM. Nearly every switch in this app puts ...
A search hit reads the same on your own messages as on everyone else's
The highlight inherited the bubble's text colour and drew itself as a 55% wash, and both of those quietly failed in the same place. The member's own messages ar...
State the first invoice on an option that has a setup fee
The card already listed the setup fee, but the only figure that summed it with the period price — the total over term — was gated on the commitment running long...
Show the one-time setup fee in the option's figures
The card, the live rail and the print preview all led with the option's period total, and the only figure carrying the setup fee — the whole-term contract total...
The one-time setup fee belongs in the quote's total
A setup fee typed on an option reached exactly one figure — QuoteOptionTotals put it in contractTotal — and applyOptionHeadlineTotals then built the quote's hea...
Give the mail columns back their own scrollbars
The offline-banner fix stacked MessageBrowser's root into a flex-col and moved the three mail columns into a row of their own. That row was `flex flex-1 min-w-0...
Give the SEND TO AI switch an accessible name
The switch set its aria-label through `inputProps`, which MUI 7 drops on Switch without a warning — so the label never reached the DOM. The words SEND TO AI bes...
The summary line double-counted sections
A section page is itself one of the articles, so "291 articles, 16 areas, 29 sections" invited the reader to add up three numbers that do not add up. One number...
Open Send To AI from the report window instead of dispatching
The SEND TO AI switch handed the report over the moment it was filed. It POSTed a bodyless dispatch, which left SecurityService to choose the instruction, the m...
ReportDefinition never shipped the narrower rights its resolver reads
ReportScopeResolver, its test and this class's own javadoc all name alsoGrantedBy, and ReportSecurityScope has had SELF/TEAM/ORGANIZATION since the framework la...
Reach the conversation on screen when it is pages down the list
Switching the navigator to the right tab was only half an answer. The list pages by last activity, 30 rows at a time, and the conversation a member has maximize...
A list read shipped every article's body, and a category page listed nothing
Two defects on the public reads, both visible on kamocrm.com/help-center. The index served 3.9 MB of HTML. tree-by-parent-slug returns every node with its full...
Stop the offline banner standing as a column beside the mail
Same defect the search results bar had, in the same container. MessageBrowser's root was a horizontal flex row whose children are the columns of the mail client...
Keep made-up article paths out of the index
The canonical check already stops a wrong path rendering the article -- it serves the not-found page instead. What it cannot do is change the status code: this ...
Send a cleared status label as a removal, not as silence
Emptying a custom label box and saving did nothing. The save built its payload from the labels that had text in them, so a box the org had just cleared was not ...
Accept a blank status label as the removal it is
The PUT is the org's complete set of custom labels, so it has to be able to carry an emptied box. Two things stopped it: an empty list was rejected as a malform...
Let an org put a custom status label back to blank
A status label had no way to be removed. The settings screen saved through an upsert-only bulk write, so the only thing a request could say was "this status is ...
Do not claim nothing matched when a filter hid the matches
The empty-list explanation added with the search results bar keyed off the query alone, so it also fired when the search had matched plenty and the Unread or St...
Article translation has never worked
deleteByArticleUidAndLocale is a @Modifying query and JPA refuses to run one outside a transaction. Nothing on this path ever opened one, so every locale of eve...
Stop mail search opening a strip down the side of the screen
MessageBrowser's root element is a horizontal flex row whose children are the columns of the mail UI. The search results bar was written as a bottom bar -- bord...
Follow the maximized chat window's tab in the navigator
Maximizing a chat popup left the conversation navigator on whatever tab it was already showing. `visibleRows` drops every row outside the active bucket, so the ...
Saving an article blocked on 21 translation calls
@Async was inert. **************** called translateArticle on the same bean, so the call went straight to this and never reached the proxy that makes it asynchr...
Stop Send To AI resetting the boxes while they are being typed in
A member filed this against the Send To AI dialog: the description "often resets back to the original description while you are editing it". It reset the instru...
A window that raised itself has not been read
The chat unread badge was invisible everywhere — the Chat button, the Interaction Center, the hexhead — and the reason was not the badge. All three read one cou...
Point at the real org, keep the tree in the URL, show related articles
KB_ORG_ID was "1". The help center lives in org 1168485648209608710, so every KB read on this site missed -- /help-center rendered its empty state no matter wha...
Announce a message only once it can be read
POST /sessions/{guid}/messages is @Transactional, and the NATS publish of the message has always waited for the commit — with a comment saying exactly why: publ...
Add the missing form-fillable route, and stop offering ungranted actions
Two defects behind one report: the PDF editor would not open, and delete was offered to a member who may not delete. **The editor.** DocManager posts to /api/d...
Ride down to your own message when you had scrolled up
Sending while scrolled up into the history left the member parked where they were, with their own message appended below the fold. From the seat it looks exactl...
Offer the billing term up front, and stop hiding it over Enterprise
Two separate ways this page withheld the choice. The org console HAD a three-term control, but it was tucked into the right of the "Choose plan" heading behind...
Quote the commitment saving in dollars on the plan cards
The discount is a flat $10 a year and $20 on three years, which is how the catalog sets it and how it is advertised everywhere else. Rendered as a percentage it...
Stop offering the internal platform-owner plan for sale
listPlansForMarket filtered on isActive alone, and active is not the same as on the menu. OWNER_UNLIMITED ("Platform Owner — Internal") is active, carries no pr...
Set "/seat/month" to the right of its own line
The price keeps the left edge and the unit takes the right, so the two bracket the card's width instead of stacking flush left — which left the number looking l...
Put "/seat/month" under the price, not beside it
Three-figure rates and "/seat/month" do not share a line on a four-across card. Inline at 1rem the label either wrapped mid-text or squeezed the number it was d...
A promotion that fails to resolve must not widen to every plan
An EMPTY applicablePlanIds means "no restriction" downstream, so a restriction that fails to TRANSLATE must not be allowed to become an empty list. A Business-o...
A promo code works on its own last day
The end date is the LAST day a code works, not the first day it does not — SubscriptionPromotions.check reads it that way on the server, and the offer band's co...
Land the header's Text, Chat and Note buttons on the tab they name
The lead view keeps its tab selection in the URL — `tab` for the main tab, `commsTab` for the Communications sub-tab — and a header quick action sets both: "Tex...
Say why a number could not be opened, instead of an empty dialpad
Opening the SMS tool on a phone number resolves a conversation for it first, and that resolve can be refused — VOIPService answers "no number to text from" with...
Stop offering an edit once somebody else has read the message
Every chat window that draws a MessageBubble — the member chat popups, and the social and ticket conversations that share ChatBox — offered Edit on the sender's...
Refuse an edit once another member has read the message
PATCH /api/media/messages/{id} was deliberately ungated on receipts, unlike the DELETE beside it. The reasoning written into it was that unsend makes read words...
Darken the xAI mark so it shows on the provider dropdown
Simple Icons ships the xAI glyph filled #FFFFFF, which is its brand color on a dark surface. The AI provider dropdown is white and the app forces light mode, so...
Let a bulk move reach the folders the member made
The "Move to folder" dialog behind the selection bar was built from a literal ['INBOX', 'Archive', 'Trash', 'Junk', 'Drafts'], so the only destinations it ever ...
Never leave a blank tab when a KamoDesktop launch stalls
The tab is opened blank inside the click gesture and only navigates once a link comes back. So anything slow upstream showed as a blank white page with no expla...
The agent health preflight must fail in seconds, not twenty
health() inherited the client's 20-second default. It is a liveness check in front of every KamoDesktop launch, and when the dev machine ran out of memory on 20...
Serve smart folders and labels as messages, not as index rows
Both endpoints answered out of email_metadata.search_index and handed the client what the table holds. A smart folder returned SearchIndexEntity — messageUid, f...
Make eslint actually run
`eslint .` reported nothing at all — not a clean tree, but a crash before it loaded a single file: TypeError: Converting circular structure to JSON at ...
The report form's questions move off the field's border
A member filed this against the report form itself: "What happened?" — and "What would you like to see?" on the enhancement side — had the field's border runnin...
A stamp that says which day, once the day is in doubt
Reported by a member: past chats cannot be identified or verified by the date they were sent or received — only a time is present. Their own history runs back t...
A new chat shows the exchange instead of going blank
Open a new AI chat, type a message, and the thinking bullets appeared and then nothing — no sent message, no reply, just the empty-conversation panel over a tra...
Let the sidebar's calendar checkboxes actually turn off
The checkbox beside each calendar was bound to `calendar.isVisible` and its onChange was `fetchEvents`. `isVisible` is sent by EmailService and written back by ...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.