A failed workspace selection no longer destroys the sign-in
Reported as being thrown back to the email field with "Your sign-in timed out. Please sign in again." after clicking Continue. The timeout had not happened — th...
Stop the logo pass starving backgrounds, and read <picture>
Diagnosed against a real site that returned six logos, brand colours and zero background images. Three separate causes, all ours. The logo pass could eat the e...
Close the dead space under the lead grid's pager
The pager sits at the bottom of the grid Card's CardContent, and CardContent ships `&:last-child { padding-bottom: 24px }` of its own. That selector carries a c...
The auto-reconnect was watching for a class that never appears
It keyed on **************** That class exists in Guacamole's stylesheet and in none of its templates, so the selector matched nothing: the script loaded, ran, ...
Cap Guacamole's heap, and unbreak the deploy that was blocking it
Two faults, one of them mine. MINE FIRST: the `node --test` gate added with the auto-reconnect script pointed at a DIRECTORY, and the runner's node resolves a ...
Say plainly what the domain field is for
The hint explained the field in terms of the hosts it produces — internal.<domain> for the workspace, login.<domain> for sign-in — which means nothing to somebo...
Drop the frozen ordinal CHECK constraints Hibernate froze at create
Hibernate writes CHECK (col >= 0 AND col <= N) over an @Enumerated(ORDINAL) column at CREATE TABLE, where N is the highest ordinal that existed that day, and dd...
Close five gaps in the website brand suggestions
Five things found reading the first cut back, all of them real. The "Added below" badge lied. It tracked only which card had been clicked, so hitting Remove on...
Enter as System Member no longer needs your own membership
The button was disabled by canEnterOrg, which asks whether the VIEWER holds a usable membership — so it was greyed out for exactly the orgs it exists to reach, ...
An unfinished domain picks a different host, not a refusal
Entering an org was refused outright unless its own custom domain had finished DNS and SSL. That was right while entering meant navigating to https://internal.<...
Stop the canary crying wolf after every legitimate restart
session_durable treated a REJECTED token as a durability failure. That is not the outage it guards: a gateway restart, or Guacamole's own inactivity timeout, in...
Stop every deploy from throwing everyone off their desktop
"An error has occurred and this action cannot be completed" after leaving a desktop open was not an idle timeout and not a browser problem. It was CI. deploy-s...
Build the search pattern outside the query, and parse the query in a test
likePattern turns an absent search term into '%' so no null parameter ever reaches a string expression, and escapes % and _ in the term so a search for a litera...
Stop the bug list 500ing on every unfiltered load
PostgreSQL cannot infer a type for a null parameter inside a string expression: LOWER(CONCAT('%', :search, '%')) with a null :search guessed bytea, and the list...
Run a dispatched session in the workspace's common parent
sage's VS Code is a multi-root workspace holding all 63 repositories, so taking the first workspace folder rooted a bug about the login site in aiservice — the ...
Add the AiDispatchRequest the pushed code already imports
SecurityService's SystemBugAiDispatchController and SystemBugAiDispatchService are on main and import **************** but the record itself was never committed...
Say what a dead KamoDesktop connection actually means
Guacamole's stock CLIENT.ERROR_TUNNEL_204 is "The requested connection does not exist. Please check the connection name and try again." There is no connection n...
Stop the SSO token expiry from emptying a live desktop session
"The requested connection does not exist. Please check the connection name and try again." on a KamoDesktop reconnect was not a missing connection. It was the S...
Retry npm ci, which is where this image actually fails
The build has failed on every push since 2026-08-15 and it is not the code. The log shows npm ci dying with ERR_SSL_CIPHER_OPERATION_FAILED and ossl_gcm_stream_...
Submit the bug report without simulating a keystroke
vscode:// URI handler and sent a synthetic Return. Measured on desktop-1, that cannot work: KDE's screen locker holds an exclusive X input grab whenever the scr...
Send the member to the workspace host, not a relative path
SignInCompletionService returned a relative /validate?otk=. That resolves against the host that served the SIGN-IN — login.<apex> — and kamo-login has a /valida...
Delete the "first organization in the database" fallbacks
Seven blocks across five controllers ended their org-resolution with, in effect: if the server name is localhost or a bare IP, return whichever organization the...
Keep an alias unique platform-wide, on both write paths
Creation checked the alias only within one security provider, and PUT /org/{id} checked nothing at all — it applied whatever it was given. Both were reasonable ...
Paint the branding of the org in the tab, not the host
getThemePath() derived the theme base from window.location.hostname. That answered the right question while every organization had a hostname of its own — and f...
Clear the cloned session in the enter-as tab
Entering an org opens a tab with window.open('', '_blank') and points it at /validate. That was cross-origin until now, so nothing was shared. It is same-origin...
The five pre-existing verticals must ship available
Shipping all six children PLANNING was wrong for five of them. RETAIL, RENTAL, SERVICE, SUBSCRIPTION and PROCUREMENT are not new functionality — they are what C...
Read the session from the tab, not the shared cookie jar
46 client modules read the *** id out of document.cookie and sent it as X-***-Token. sessionStorage is per-TAB; a cookie is per-ORIGIN. While every organization...
Refuse an alias that names more than one organization
byAlias took LIMIT 1 over orgs.alias, which has no uniqueness constraint: the create path checks it per security provider and PUT /org/{id} does not check it at...
The scheduled-support presenter picker offered nobody
The Presenters tab dropdown was empty for every organization, and always had been. GET **************** answers with { teamMembers, total }; the tab read data.m...
Resolve the domain on /org/current server-side
internal.kamocrm.com failed to render with "Invalid organization data: missing 'id' or 'domain'". Organization has no `domain` field -- it has a `domains` colle...
Give /api/org/current the domain the client requires
internal.kamocrm.com failed to render with "Invalid organization data: missing 'id' or 'domain'". Organization.fromJSON refuses a record without a domain, and t...
Move jump-to-newest in with the toolbar's other actions
Search now owns the whole left track of the toolbar, because the empty part of that track is exactly the room the field opens into. The scroll-to-bottom control...
Give the workspace path the same post-login work as the host path
Two gaps found by re-reading the original login tail against the new one, before enabling the picker. The form-encoded /login endpoint built its LoginRequest w...
A sent message animates in once, not twice
The message list keyed each row on the message id, and a sent message's id changes exactly once — the optimistic row is appended under a local id, and the STOMP...
Name rooms after the org id, not the hostname
getOrgToken() took the first label of the current host, and its own comment said why: "so identically-named rooms cannot collide across orgs". On the shared hos...
Scope rooms to their organization on the shared meet host
Room isolation was the HOST. A member of org B could not present a *** cookie on meet.<org-A-domain>, so knowing org A's room name got them nowhere. Serving org...
Make the auto-login cross-tenant guard actually run
The guard read the host org's id with /"id"\s*:\s*(\d+)/ -- a bare digit straight after the colon. SecurityService's JsSafeLongSerializer writes any Long above ...
Stop handing an alias row over as the org's domain
**************** walked org.getDomains() filtering only on isActive. That collection holds the org's root domain AND its alias rows -- api, login, theme and the...
Take the chat-core that stops a sent message showing twice
@kamo/chat-core 0.1.6. The conversation reducer now adopts the pending optimistic row when the member's own message comes back over STOMP, instead of appending ...
Stop requiring DNS verification to sign in
OrgHostResolver.resolveByDomain filtered on od.is_dns_verified = TRUE, so a domain row that existed but had not finished verifying resolved to nothing and login...
Stop RingCentral OAuth signing white-label tenants out
Two faults, both on the same hop, and each one hides the other. RingCentral rejects every scope value this app can ask for — "invalid_request / Parameter [scop...
Show cents on an add-on rate that has them
Additional Storage is $2.50 per 10 GB block, and the catalog stores that as a number — so 2.50 arrives as 2.5 and rendered straight into the card it read "+$2.5...
Settle Additional Storage at $2.50 per 10 GB block
Confirms the block size and rate as $2.50 per 10 GB rather than the $4 per 25 GB the production row had drifted to. The seeder, the catalog row, the Stripe pric...
Price Additional Storage as $4 per 25 GB unit, FLAT not metered
Additional Storage is bought by the unit, belongs to no plan on any tier, and is not seat-based. The seeder still described it as $2.50 per 10 GB block, which i...
Stop offering Business the add-ons it already includes
Choosing Business still presented video conferencing, the AI assistant, the HR system and e-signatures as things to buy, even though the plan bundles all four. ...
Bind add-ons to the app they sell, and stop Business granting mail free
**************** is the column **************** matches on. KamoCRMPricingLoader never wrote it, so every KamoCRM add-on row has it NULL and that comparison can...
Stop selling add-ons the chosen plan already includes
The catalog has always recorded which add-ons a plan bundles, in **************** — Business and Enterprise carry video conferencing, the AI assistant, the HR s...
Let the SSL check lower the flag, not only raise it
checkDns only ever latched sslConfirmed to true. A domain whose stored flag was set under the old any-one-host rule therefore kept a green SSL card and an unloc...
Verify-dns answers for the present, not for a stored flag
The endpoint skipped probing entirely when ssl_confirmed was already true, on the reasoning that under the all-hosts rule it could only have been set when every...
Re-verify domains already marked SSL-confirmed, and heal them
findAwaitingVerification filters confirmed domains out by design, so once ssl_confirmed was set nothing ever looked at that domain again. That was fine while th...
Like what you see shipping?
Every one of these updates lands in your workspace automatically. Start free and watch it grow week after week.