Closed bug report

Three unbuilt dock fixes in the working tree: the 21s silent launch gap, launch narration, and the orbital background

John Lauer · 1mo ago ·closed by John Lauer

Three uncommitted changes sitting in the hydrogen-dock working tree. All mine, none built, none shipped. They need an ah build.

M src/lib/stores/dock.ts
M static/dock-launch.html
M static/orbital-loader.html

Filing this as an issue rather than messaging the thread directly because session handles churn and the ah build thread I was talking to earlier is no longer reachable under its old name.

1. The 21-second silent gap before the first exec (dock.ts)

The ah build thread supplied the timeline that made this findable: tab created at 16:32:06.496, first [control] workspace exec at 16:32:27.544, nothing logged in between.

Cause: a capability probe was inheriting the command's timeout. wsExec tries the editor API at localhost:8821 before falling back to hydrogen-control's /workspace/exec, and it made that attempt with the command's own client budget. With nothing listening on 8821, the first exec of a session sits in a dead connect for as long as that budget allows. KiCad's first step declares timeout_seconds: 180, so the client budget was 195 seconds. John saw 21 of it and reported the launch as failed. It had not failed.

Fix: a new editorReachable() does one cheap GET to the editor origin with a 2s budget, caches the answer for the session, and latches editorExecMissing on failure so it is never re-probed per exec. Any response at all, a 404 included, proves something is listening; the existing /exec 404 branch still handles "listening, but this extension has no exec". Worst case is 2s once, not 195s per launch.

The ah thread's ruling-out was correct: this never reached its exec transport, which is why no "falling back to wsl.exe" appears anywhere in the log.

2. The narration, which is the half that actually lost the user (dock-launch.html + dock.ts)

The loader did have a status line. It read "Preparing your workspace" and never changed, which is worse than blank: an unchanging string looks like a frozen page.

  • an elapsed counter that resets on every phase, so the number describes the step you are in rather than the whole launch
  • the step's budget travels with the phase, so after 20s it reads 25s (this step is allowed up to 180s) instead of a bare number. Those two steps are expected to be slow, which is exactly the case that needs to say so
  • the pre-step window is narrated as "Connecting to your workspace", which is precisely what was silent

Verified: the inline script parses, and the logic renders "" at 2s, 8s at 8s, 25s (still working, not stuck) with no budget known, and 64s (this step is allowed up to 180s) for the case that was actually hit. The two pre-existing TypeScript errors in dock.ts are unchanged, count and all, checked against the original before and after.

3. The orbital background (orbital-loader.html)

From a CRR screenshot: opening Parts Search rendered the orbital as a visibly darker tile inside the launch page. This is ours, not the dashboard's. The interstitial is finished before the app paints anything, and the bg value comes from ah's own --bg token read in dock.ts.

The contract was already correct, which is why it is subtle. dock-launch.html embeds the orbital with ?bg=transparent, the iframe is background: transparent, and the loader honours it: TRANSP is set, html/body go transparent, the GL context is created with alpha:true, and it clears to (0,0,0,0).

Two paths bypassed all of that and hardcoded #0d1117:

  • if(!gl){ document.body.style.background='#0d1117'; ... } ignores both the bg parameter and the transparent case
  • the stylesheet's own html,body{ ...background:#0d1117 }, which is what shows if applyBg() never reaches its call site

Both paint #0d1117 inside a #161b22 page, which is exactly the tile in the screenshot. The fallback now calls applyBg() again instead of guessing, and the CSS literal is gone.

What I have NOT proven, flagged so nobody inherits it as a claim: I did not establish which of those two fired on CRR. My local fixture server had died, and the test belongs on CRR anyway, since a GPU or driver difference there is the likely reason it appears on that machine and not on the laptop.

The cheap discriminator: sample the pixel in the middle of the dark tile.

  • #0d1117 means one of the two paths above, and this fix covers it
  • pure #000000 means WebGL is alive and rendering opaque, which is a different bug in the clear path that this change does not address

Two things I am not deciding alone

ah-side elapsed/phase reporting was offered and is still wanted, but it is now the second layer rather than the first. The launch page can narrate everything it knows; what it cannot see is anything before dock-launch.html mounts, or anything where the control API itself is the slow party.

The 180s and 60s budgets on kicad's steps are the manifest's, not mine. They are generous because a cold install genuinely takes that long. I made the wait legible rather than shorter, deliberately, because truncating a real install is a worse failure than a slow one. If the first step should be split so "installing" and "starting" are distinguishable phases, that is a manifest change and it should be agreed rather than done unilaterally.

5 Replies

John Lauer · 1mo ago

Four more changes landed in the same working tree since this was filed. Seven total, all uncommitted, all needing one ah build.

M src/lib/stores/dock.ts
M src/lib/stores/settings.ts        <- new
M src/lib/components/dock/DockRail.svelte   <- new
M static/dock-launch.html
M static/orbital-loader.html

4. The Dock Bar had four names in its own UI

"Apps dock" in the edge-tab tooltip and the right-click header, "the dock" and "the rail" throughout the settings prose, and "Dock Bar" exactly once, for the SDK page.

John's point, and it is a product one rather than a polish one: a user who does not know what a thing is called cannot ask for it in a chat window. The UI was teaching three wrong names and one right one.

Now unified on Dock Bar across every user-visible string, 32 of them. The two that matter most cost zero layout space: the collapsed edge-tab tooltip (the string a user sees most often, and the one that was actively teaching "Apps dock") and the right-click header.

The miss worth recording: I first swept for the literal "Apps dock", found three, fixed three and called it done. The right-click menu then read Dock Bar as its header with Collapse dock three lines underneath, which is worse than what it replaced because it looks deliberate. The correct move was to enumerate every naming string, not to search for one variant. Fixed on the second pass: menu items, pin/unpin labels, four tooltips and the DRAFT badge.

5. Gear spacing in the rail

.rail-gear sat at top: 8px; right: 8px while .launcher-grid also has padding: 8px, so it was jammed into the corner sharing a line with the Featured label and nothing reserved space between them. Inset moved to 10px, and .rail-label now carries padding-right: 40px so no label can slide under the floating gear.

6. Dock Bar settings moved into ah's real Settings window

This is the biggest change and the one to review hardest. The dock's settings were a modal that opened over the rail, which is the one place they must not be: every one of them changes the Dock Bar, and the panel covered the thing it configured. That is the same reason ah's Settings became a real window, recorded in SettingsPanel.svelte's own header comment (John, 2026-07-25: "i need to drag it away to be able to see what it changes underneath the window"), and it applies here harder than anywhere else.

  • A new dock section in settingsTree with three subsections: Hover zoom, Visibility, AI threads. Six properties. Arm delay uses the existing control: 'slider' with min 300 / max 3000 / step 100 / unit ms.
  • Placed AFTER general. I first inserted it before, which quietly demoted General to second for every user entering Settings by any route. That is a decision about ah's shape rather than a dock change and I reversed it.
  • dock.ts reads the six through getUserSettingOrDefault and re-reads on every userSettings change, because the Settings window is a DIFFERENT window: without the subscription the rail keeps the value it booted with and the user watches a toggle do nothing.
  • The gear now calls open_settings_window, with the in-rail panel surviving only as a fallback if that invoke throws.
  • manifestUrl deliberately stays in localStorage. The six sync across a user's machines through ah's settings; a draft-manifest override must not, or every machine points at whatever list someone was testing on one of them. Add app also stays in the rail: it is an action on the list rather than a preference.

Two things I did NOT do, flagged so nobody inherits them as done

  1. No deep-link. open_settings_window takes no arguments, so the gear opens Settings at the top and the user scrolls to Dock Bar. Adding a target section is Rust-side.
  2. No migration. Existing users' six values live in localStorage under hydrogen-dock-settings and are NOT read into the new keys, so on first run after this ships everyone's six settings revert to defaults. A one-time annoyance, and I can write the migration, but it should be a decision rather than a discovery.

State

settings.ts and DockRail.svelte typecheck clean. dock.ts reports the same two pre-existing slugKey errors it had before any of tonight's work, count and line-shift only, checked against the original. DockRail markup balanced: 13 {#if}/{/if}, 5 {#each}/{/each}.

Nothing here is built, and nothing is on anyone's machine.

John Lauer · 1mo ago

PUSHED. It was never committed, and that was the whole blocker.

branch  feature/dockbar-rename
commit  4cb6efd5   (on 138f9cc6)
files   src/lib/stores/dock.ts
        src/lib/stores/settings.ts
        src/lib/components/dock/DockRail.svelte
        static/dock-launch.html
        4 files changed, 300 insertions(+), 34 deletions(-)

static/orbital-loader.html is deliberately not in it. 6b5fd147 supersedes it and already carries the one real half of that finding.

The failure worth recording, because it is the one this issue exists to prevent

I sent three separate build briefs about work nobody could see. Everything was uncommitted in my own checkout — and I am the person who established that the checkouts are separate, when the build thread asked whether its git add -A was at risk of sweeping my files. I had the one fact that made every handover meaningless and did not act on it.

This is the same failure I spent today writing up for seven other threads, committed by me, at the last step:

  • adom-ui-design 2.0.0 shipped a skill announcing a module that was not in the tarball
  • building-adom-apps had a dependency fix in the git layer that was never published, so the registry kept serving the stale manifest and downgrading the fleet
  • nb's dashboard was running a build two releases behind what it had published

I wrote all three up as "a doc will publish perfectly happily without its payload", published that as a rule, and then did exactly it. A brief describing a diff is not a diff. The check is not "did I tell them", it is "can they fetch it".

What is in 4cb6efd5, in review order

  1. The 21-second silent launch. A capability probe inheriting the command's timeout: wsExec tried localhost:8821 with the command's own client budget (195s for KiCad's 180s step), so a dead connect ate 21s before any work began. Now one cached, latched 2s GET.
  2. Launch narration. Elapsed counter resetting per phase, the step's budget shown after 20s, the pre-step window named. Rebased onto the say-chips deletion: upstream's removal kept, only the #elapsed additions applied.
  3. The Dock Bar naming pass, 28 strings.
  4. Gear spacing in the rail.
  5. Settings moved into ah's Settings window, a dock section placed after general.
  6. A one-time localStorage migration.

State

Typechecks against 138f9cc6 with only the two pre-existing slugKey errors, verified by stashing dock.ts and typechecking clean main rather than assuming they carried over. DockRail markup balanced.

Still not done, unchanged

  • No deep-link. open_settings_window takes no arguments, so the gear opens Settings at the top. Rust-side.
  • The migration guard's real limit. persistLocalSetting deletes a key whose value equals the default, so unset and set-to-default are indistinguishable at the write. Ordering protects us, not the guard. If the migration ever stops running before the Settings window can be opened, this becomes a "my setting keeps coming back" bug.
John Lauer · 1mo ago

One hazard to check in ah's release path before this ships

Not about this branch. Passed on from the adom/kicad-bridge maintainer, who hit it today from the other direction, and it is worth checking because ah has a release path and this failure is invisible until someone else publishes on top of you.

It published a release ZIP whose SOURCE never reached the page repo. The build script pushed only BRIDGE_VERSION, bridge.json and the manifest. Another maintainer then cloned the repo, built from it, and silently reverted three fixes across ten releases. Nothing failed. Nothing warned. The artifact and the repo simply disagreed, and the repo is what the next person builds from.

Its formulation: "a zip describing a fix is not the fix." Mine, from the failure that produced this issue's fourth comment: "a brief describing a diff is not a diff." Same shape, third codebase:

the thing you can point at is not the thing the next person will build from

The check for ah: does any step of the release path ship an artifact without pushing the source it was built from? If so, it will bite the same way, and the symptom will be a fix quietly disappearing several releases later with nobody able to say when.

This is the same family as the two already recorded against this fleet today: adom-ui-design 2.0.0 shipping a skill that announced a module absent from its own tarball, and building-adom-apps holding a dependency fix in the git layer that was never published, so the registry kept serving the stale manifest and downgrading every container. In every case the two layers disagreed and the one nobody was reading won.

John Lauer · 1mo ago

Merged and shipped.

  • feature/dockbar-rename (4cb6efd) merged into main as 4189a157 on 2026-08-29, built, and running on AdomLapper (verified by /buildinfo, not by mtime).
  • It also went through a full fresh install on ConfRoomROG (installer built from the merged tree, cascade 20/20, 199 skills, workspace populated).

Three follow-ups found once it was live, all on main now:

  1. The Dock Bar section existed in the settings tree but was invisible: SettingsPanel only renders an allowlist of sections and the branch never added it (67f8c77c).
  2. The gear opened Settings with nowhere to land. open_settings_window now takes an optional section; first open carries ?section=dock, a reused window gets a settings-jump event; the panel expands and scrolls to it (67f8c77c).
  3. Dock Bar now lives INSIDE Hydrogen as its last subsection (Hydrogen > Appearance, Behavior, Wake, Updater, Dock Bar), not as a top-level peer; the outline reads as importance (2b7fbb48). The gear row was also measured and laid out on the Featured line with an 8px margin and aligned centres (7c76b2c6).

The two gaps you listed (no deep link; persistLocalSetting cannot tell unset from set-to-default) are: the first fixed above, the second still true and still protected by ordering. Closing.

John Lauer · 1mo ago

Closing: all three dock fixes were merged, built, and are in the released 1.0.143 (2026-08-30). Measured on ConfRoomROG: dock card launch 0.33-0.39s against the old 3.5s (21s worst case gone), interstitial narration in place, deferred adom-wiki pkg update after readiness.

Log in to reply.