The compact rail clipped a payout flag off the top of the window
The rail reserves a fixed strip above the pucks so a label does not make the strip taller and move the board — but it reserved room for ONE row and the showdown...
The table says what just happened
The felt re-rendered a STATE. It never presented an EVENT. Of twenty-six things that happen in a hand of poker, exactly two had any presentation at all — a card...
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()...
The table list had nothing between it and the lobby header
The lobby's scroll container carried `px` and `pb` and no `pt` at all, so the first table's top border sat exactly on the container's edge, flush against the he...
Move the balance out of the top bar and into the Games menu
The bar is fixed chrome and already crowded — greeting, branches, availability, the compliance clock, the bell, chat, language, account — and a balance is not s...
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()...
The same-commit-rebuild guard could never fire, so every dispatch failed
Rebuilding this service without a commit of its own — a workflow_dispatch, a re-run, or a kamo-shared-library change it must pick up — has been failing at deplo...
The wedge is yellow, and it stops depending on the tenant's brand
`/icon/cheddar.svg` was five paths of pure #000000 — a black cheese wedge, which on the nav bar's dark ground was very nearly nothing at all. It is a real chedd...
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...
Four defects only a real browser could show
Rendered the felt, the compact layout, the lobby and the action bar in headless Chrome against a fabricated table and MEASURED them. Four things were wrong, and...
A poker table in a tool window, and Cheddar in the nav bar
Two genuinely different layouts, a lobby, an invite path that reaches anyone in the organization, and the wallet readout that appears whenever Games does. ## T...
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 app, the right, and the six tables a poker game needs
HOLDEM (36) joins KAMO_UNIVERSE and CHESS under GAMES, with PLAY_HOLDEM (319). Both ids were the next free ones; nothing is renamed and nothing moves, because O...
The chat entry opens the pair's board, and you can ask an opponent back
Two colleagues who have played once have a board together for good, so the chat entry stops offering to introduce them. It reads "Open your game" and goes strai...
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 ...
Record when a player was last prodded to come back
DATE_LAST_NUDGE, one clock per game rather than per sender — otherwise two people can take turns nudging each other every five minutes and call it twelve messag...
A capture shelf where the move list was, and a hexhead that says it is your turn
THE SHELF. A move list is a record; between two colleagues playing for fun the pieces you have taken are the thing worth looking at, so they get that space and ...
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...
The board you play on now lives in the same room as the pane that started it
You chose a game in a dark room of board lacquer and brass, pressed start, and landed on a white MUI form with a board floating on it — `var(--surface)`, `divid...
The two mode plates were clipped by their own scroller, at every size
The selected plate lifts 2px and carries a 1px ring, and it is the first child of an `overflow-y: auto` column — so its top border sat 3px above the clip edge a...
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 ...
Starting a game from a chat asks once, then plays — it never asks who
Clicking chess in a conversation opened the new-game pane and asked whether you wanted to play the computer or a person, then made you pick the person. The pers...
The opening pane, rebuilt around a game instead of an icon
The pane you get when chess has no opponent yet was the SaaS-card kit: an icon in a rounded square, two tab-cards, two segmented rows, a button. It looked like ...
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...
An invited game starts running, and records whether it has been seen
Inviting somebody created a PENDING game nobody could touch, so the person who had just asked for a game sat in front of a board they were not allowed to use un...
The proxy could still be walked out of, because a dot is not encoded
The catch-all re-encodes each segment, and the comment claimed that meant it could only ever address the chess API. `encodeURIComponent('..')` is `'..'` — dots ...
The error test did not typecheck, and next build runs tsc
`await promise.catch((e: Error) => e)` does not give you an Error. The catch handler's return type unions with the promise's resolve type, so the result is `Che...
The BFF route that was never written, and an error that was a megabyte of HTML
Pressing Start game returned 1,529,239 bytes of markup. `/api/media/*` is not a proxied prefix — every path under it is a hand-written Next route and there is n...
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....
AppType hid two live apps, and the guard could not see the place they were hidden
The Java app enum is mirrored into TypeScript twice, and only one of the two was guarded. AppType.ts — the mirror Organization's app getters actually read — had...
An app id an older build cannot name must not fail every feature read
ServiceType ships inside each service's jar while ORG_FEATURES is shared, so a newly added app is ALWAYS in the database before the older readers have been rebu...
Drop aiThinking from the client mirror too
It was always false on the wire and nothing rendered it. Removed alongside the server field so the two shapes stay identical — a mirror that keeps a field the s...
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 the history fetch from deleting the text that just arrived
SmsThread loads its page and REPLACED the list with it. A message landing between the query executing and its response arriving was appended by the live subscri...
A black piece on the Kamo board was the colour of the square under it
Only a browser found this. The Kamo scheme derived its piece colours from `--color-primary` as well as its squares, and both mixed the same token into similar d...
Put the stream in the config the pod actually reads
The previous commit set nats.jetstream.stream in **************** shipped, deployed — and the new pod still logged NATS stream 'CHAT_MESSAGES' already exis...
@kamo/chat-core 0.1.18, for the game-invite fields
The lockfile is edited by hand — four lines: the root range, and the version, resolved URL and integrity of the one package. `npm install --package-lock-only` r...
Carry an arriving text across the boundary the dock sits above
An inbound SMS never reached an open SMS window, and the reason was not the transport everyone went looking at. SmsMessageProvider was mounted in Authenticated...
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...
Give voip.* a stream to live in, and stop lying about who sent the text
There was no VOIP_MESSAGES stream in NATS at all. Every `voip.*` publish answered 503 No Responders Available and both media pods logged, once, at boot: [V...
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, ...
Games becomes a parent app, with Kamo Universe and Chess under it
GAMES was a category with exactly one thing behind it — the nav icon launched Kamo Universe directly, so the app and the thing inside it named the same click. C...
Dial the detail dialog's tel: through the shared normaliser
The dialog built `tel:${action.tel}` by hand because telHref() was not on main when it landed — it was in a concurrent branch, and importing it then would have ...
One formatter, and one dialable link, for every number on screen
Follow-on to the lead-view country-code fix, closing the places that still answered the same question their own way. `NumbersTab` kept a private US-only format...
Light the bell, and make a click mean something
Three defects behind one report: the browser tab alerted for an unread notification while the bell stayed dark, and clicking rows on /notifications went to the ...
Filter the bug and improvement reports by who filed them
Reuses /leads' Agent filter — the same field, the same picker, the same gesture — pointed at a different directory: everybody who has filed at least one report,...
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.
