The faces answer says how many people are in the conversation
GET **************** now carries `participants`: the console puts a face beside each message only when three or more people are in a conversation, since between...
A face for every message in every chat window
GET **************** answers, for one conversation, the photo to draw beside each message: everybody on it now AND everybody who ever wrote in it (a roster forg...
A meeting link in the conversation, always on the platform's Kamo Meet
POST **************** lets either side of an Exec2Exec conversation add a meeting link, behind the same gate as sending a message. The meeting is created as the...
Faces on the desk β a client's photo, last sign-in and presence
The desk's roster now carries, for every client, their own photo (users.avatar_id, built on the operator's live theme host β the only one their console loads im...
A conversation reaches the phone
A message on an Exec2Exec line now goes to the recipients' phones as well as their consoles: the customer's phone when KamoCRM replies, every desk member's phon...
Chat and bug emails link to the console the recipient can reach
ChatEmailNoticeService named the recipient org's first domain whatever its state. The reported case: Exec2Exec letters to makeitpopsigns.com, sent before its DN...
The desk's count of client messages not yet viewed
GET **************** returns how many messages from clients this EXEC2EXEC_ACCESS holder has not viewed, across every conversation, and each roster row carries ...
Seat the whole desk on every chat, show who is on it, close the chat feeds
- Standing membership: every explicit EXEC2EXEC_ACCESS holder sits on every Exec2Exec conversation. Exec2ExecDeskReconciler seats and unseats from the grant...
Parse the desk's audience query at test time
findHolderMemberIdsOf lives in the shared library, so nothing in this package parsed it β and a mistyped path there crash-loops MediaService at boot, every endp...
A customer's message reaches the desk, not only the thread
An executive wrote into their Exec2Exec chat and nobody at KamoCRM heard. announce() told the session's own members, and an operator is only a member of a conve...
Serve the executive channel
A conversation with its own audience rule and no ticket machinery, following SystemBug's shape: its own package, its own controller, its own visibility, and Med...
An announce that throws must not roll back the buy-in
`announceToConversation` runs INSIDE the transaction that seats the host and charges them β unlike `announceTable`, which the controller calls after the fact. T...
Colleagues in the invite list, and an invitation from a chat that arrives
Two reported defects, both in who a table can reach. **The invite dialog offered accounts.** `invitableFor` read `members.findByOrganizationId`, and an organiz...
No empty tables, numbered tables, and one table per member
Four rules, all of them things a member reported seeing broken. EMPTY TABLES. A lobby showed three tables while one game was being played. Two had no seats at ...
Prove the endpoints actually CONSULT the entitlement, not just that it works
GamesEntitlementTest proves the gate answers correctly. Nothing proved the three controllers ask it β and that distinction is the entire defect this change set ...
A hand shown on the flop is five cards, and gets a name
`showHand` named a hand only with a full five-card board, while `finishHand` scores one from three β and two hole cards plus a three-card flop ARE a five-card h...
Show the hand nobody made you show
A pot taken with everybody folding is the one hand at the table whose contents only its owner knows, and there was no way to say what it was. Showing a bluff is...
A raiser could raise again after being called
One character, and it decided pots. `canRaise` is exactly `!actedThisStreet`, so that boolean is the whole of "may you raise". The service reconstructs it from...
Opening a table buys you into it, and the last one out closes it
Both ends of a table's life allowed the same thing: a table with nobody at it. OPENING ONE COST NOTHING AND SEATED NOBODY. A host could put a table in front of...
The plies, and how long each one took
Two things the move panel needs, neither of them on the published frame. `GET /games/{id}/moves` hands over every ply in order. It is a separate read rather th...
Chess, Hold'em and the wallet never asked whether the org has the app
The companion to the kamo-internal commit, and the half that actually mattered. The browser gate was cosmetic: ChessController, HoldemController and CheddarWall...
A re-let chair was handed the previous occupant's mucked hand
Two defects the linger made reachable, found by reviewing the commit that added it. THE REDACTION. viewFor matched hand-seat rows to seats by seat NUMBER alone...
The felt never saw a showdown, and a fold-out pot was counted twice
Two defects that were invisible for the same reason, and the data a poker table needs to present a result at all. THE SHOWDOWN NOBODY COULD WATCH. finishHand()...
New table 500'd on a ternary that unboxed a null button
Pressing New table answered 500: NullPointerException: Cannot invoke "java.lang.Integer.intValue()" because the return value of HoldemTable.getButtonSeat()...
Stop rebuilding the wallet and the guest list on every check
`viewFor` fetched the recipient's Cheddar balance and queried the whole organization's member list β both per RECIPIENT, on every published frame. At a full tab...
The clock could never have fired, and a full all-in re-opened nothing
Two defects found by reading the code back, neither of which any test could see. ## The clock would have thrown on its first tick `HoldemDeadlineSweep` carrie...
Spring Data does not register a NESTED repository interface
MediaService crash-looped on the Hold'em image. The six repositories shipped as nested interfaces inside one `HoldemRepositories` class β one file rather than s...
A server-authoritative Texas Hold'em, and the Cheddar wallet seam
Up to ten players a table, started from any conversation, with anyone else in the organization invitable into it. Every rule lives here; the browser owns none. ...
The chat entry is a door to the pair's board, and you can ask them back
Two colleagues who have played once have a board together for good. So the chat entry stops offering to introduce them: `gameWith` answers with the SHARED game ...
The frame stops carrying an archive nothing renders
The window's notation panel is gone β the captured pieces have that space β so `moveList` and `fenHistory` came off the published view. `fenHistory` alone was s...
Map.of throws on a null value, so "no game yet" was a 500
`gameWith` answered with `Map.of("game", β¦)`, and `Map.of` rejects a null value with a NullPointerException. So the one endpoint whose documented normal answer ...
The inviter plays immediately, and the invitee is told when it is their turn
An invitation used to produce a board the inviter could look at and not touch, waiting on somebody who might be away from their desk. Now the game is running fr...
Let a refusal keep the sentence it was written with
The chess code refuses with reasons meant to be read β "not your turn", "this game is not in play", "illegal move". None of them reached anybody. `server.error....
Drop a field that was always false and a statement that did nothing
`aiThinking` was on every published board and was never once true β the AI answers inside the request that provoked it, so the window that asked already knows i...
Stop letting one bad boot deafen the VOIP relay for the pod's life
The relay subscribed once, from @PostConstruct, and never again. When VOIPService's voip.> stream did not exist β which it did not β both replicas logged exactl...
A whole game of chess, server-authoritative, over NATS
The rules live in ONE place and it is this one. ChessEngine implements the whole ruleset β move generation, legality under pin and check, castling, en passant, ...
Stop writing "/" as the destination of a review notification
The Growth Hub has no screen of its own β kamo-internal's widgetRegistry says so where it decoders to give the widget an href: "the widget IS the feature". So t...
A reporter filter, for platform team members only
The board is global β every organization sees every report β and what protects a customer is SystemBugIdentityPolicy withholding WHO filed a row. A control that...
An approval settles the member's achievement
Approving a submission now tells SecurityService to recount that member's SPREAD_THE_WORD standing, so the trophy lands in the same second as the decision rathe...
The queue a member works through, and the queue an admin reviews
MediaService's Growth Hub surface at /api/media/marketing/growth. It owns this for the same reason it owns tracking, the scoreboard, materials and Canva β and b...
Relay an unlock to the member it happened to, and to nobody else
SecurityService publishes **************** on core NATS; this puts it on **************** Same arrangement as the training badge, and for the same underlying re...
Parse every declared query, not the two somebody remembered
The three queries this feature added were never parsed by anything. That matters more than a wrong predicate would: Spring Data validates every @Query while it ...
A redacted status event kept its type, and pin the redaction
Two things, both found by writing the test for the actorName path rather than by reading it. messageType was being read off the body AFTER redaction. redactEve...
Open the board to every org, withhold who filed each report
The tenancy check is gone from visibleOr404 and from all four queries, so every organization can read, comment on and vote on every report. SystemBugIdentityPol...
Stop the presence gate silencing every mail notification
A member with a live MediaService socket was treated as having already seen every non-call push, mail included. That is true of what travels on that socket β a ...
The thread page names its reader, and drops an unused helper
`viewerMemberId` on the thread page, so the console can tell the viewer's own reactions from everybody else's without a second call to /api/user-info. A ref fil...
The thread behind a report, and the two statuses that need one
`SystemBugThreadService` is the whole feature: a report's MediaSession, the status events written into it with the reason their author gave, the comments anybod...
Let the reporter confirm their own fix, and carry a denial's reason
Adds POST /{id}/verify-fix β the one status change in this feature that is not gated on MANAGE_SYSTEM_BUGS. A separate endpoint rather than a hole in the one be...
Relay coder usage onto a per-member topic
menu subscribes to over the existing chat STOMP connection. Built as a twin of the training relay β same subject shape, same single-token rule, same core-NATS-...
Credit a signup whose page views were never recorded
**************** was the ONLY thing in the fleet that ever inserted into MARKETING_VISITORS, so the whole conversion pipeline silently depended on a browser bea...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.