The offer countdown could not hydrate, so React threw the banner away on every load
The homepage has been throwing React #418 — "the server rendered text didn't match the client" — on every load, in production as well as locally. The mismatch i...
An org without the app must not accrue achievements either
The award gate asked for VIEW_ACHIEVEMENTS and stopped there. Rights are not entitlement-filtered, so that right stays granted — and keeps answering true — in a...
The particles ran at the monitor's speed, and the chips were unreadable on two denominations
Two deferred things finished, both measured rather than eyeballed. THE PARTICLE LOOP IS TIME-STEPPED. `PixelParticles` advanced physics once per FRAME — every ...
Four things about the celebration only a browser could say
Measured in Chrome against the real component, not reasoned about. The headline was sized at a flat 13cqw, which is right for a number and wrong for a word: CH...
Refuse to award a member whose security type excludes it
AchievementController checks VIEW_ACHIEVEMENTS on all four of its endpoints, and that read like the rule being enforced. It was not: it is the rule enforced on ...
Rank only members whose security type includes achievements
The leaderboard grouped every member holding an achievement row, so a member whose role denies VIEW_ACHIEVEMENTS — who cannot open the page, the trophy or the w...
The same-commit-rebuild guard could never fire, and the digest check failed open
Both protections against a deploy that deploys nothing were inert, so the pipeline reported two green jobs while the pods stayed on the previous digest. That is...
A catalog row naming an app this build cannot resolve is not for sale
ServiceTypeConverter stopped throwing on an unknown app id and started resolving it to null, which is what a service must do — the enum ships inside each jar wh...
The opening effect's cancel guards were guarding nothing
`cancelled` was declared, read seven times, and never assigned — the effect returned no cleanup — so every `if (!cancelled)` in the load that opens a window was...
Early Bird and Twenty Doors read the laptop's clock, not the member's
`check-server-timestamps` was red on main: `rememberToday` bucketed the day with `new **************** which is the BROWSER's zone. The guard exists because tha...
The chips were on the table, not on the felt
A member reported that the player opposite them had chips half off the table. Measured in a browser: NINE of the ten piles were off the cloth. The reader's own ...
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...
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...
The computer's reply was silent against the quickest level
The four move cues carried an 80ms throttle. Each is raised once per published frame the board could prove it understood, and a frame is a move — so there was n...
Six the adversarial review upheld
Ten reviewers, three skeptics each. Twelve findings survived; most of the rest were refuted because they had already been fixed. Of the twelve, six were still r...
What an adversarial read of the whole thing found
Ten reviewers over the change, three skeptics per finding. These are the ones that survived, and most of them were in the wiring rather than in the parts that h...
Looking at an organization is not being in it
A workspace signed in to KamoCRM repainted itself as BluEleven - logo, colours, favicon, tab title, and the feature set driving the navigation - while every rec...
Three things a browser said and jsdom could not
The panels were built and tested entirely in jsdom, which can say a label is present and cannot say how wide it ended up. Rendering them at the widths ChessTool...
The chips in the middle are worth what the number says
A settled pot draws the CONTESTED total now, not everything that went in. `hand.pot` keeps every chip that entered the hand; `totalPot` reports what was played...
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...
The Games icon appeared for organizations that have no Games app
Reported on harmonyhomeloans, whose owner saw the icon in the top bar for an app their organization does not have, cannot enable in Apps & Features, and whose c...
The reveal turned your own cards face down, and four more from review
An adversarial review of the choreography commit, verified against the code. Six defects, two of which only a browser could have shown. YOUR OWN CARDS. The sho...
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 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 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...
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...
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...
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 ...
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...
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...
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 ...
Two more deadlines a background tab cannot meet
Swept the app for the failure the notification deck's repeat turned out to be: work whose correctness depends on a timer firing while nobody is looking. Chrome ...
A pane lock survives the editor alt-tabbing away
The client heartbeats its pane lock every 15s and the sweeper released any lock unheard from for 45s — three missed beats, which reads like a generous margin an...
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 notification raised on the wrong pod reached nobody
The broker here is enableSimpleBroker — in-heap, per pod, no relay — and this deployment runs two replicas. MemberNotificationService published straight into it...
The last two durable consumers become queues, and contact sync reaches every pod
The mail relay was one of four NATS subscriptions on a plain durable consumer. A plain durable admits exactly ONE subscriber, so at two replicas the second is r...
A bulk action announces the folder changed, like opening one message does
`email:folder-changed` is what the nav badge listens for while it is not being pushed a count — a socket that never came up, or one that came up and relays noth...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.