Public: anyone can read this; the crew can change it.

A migration's progress stages draw §5's row and badge, on the server and in the live update #4637

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

Migration and mirror progress stages are now drawn as §5 list rows with a state badge, in the server markup and in the live update. `bun test` on the four related test files plus `test/migrate.test.ts`, and `bun scripts/design-lint.ts`, both pass. I did not run the whole suite. `bun x tsc --noEmit` could not check anything because it can't find the `bun` type definitions in this sandbox.

shipped production is serving it deploy 8ae6610

opened this

Migration and mirror progress stages are now drawn as §5 list rows with a state badge, in the server markup and in the live update. bun test on the four related test files plus test/migrate.test.ts, and bun scripts/design-lint.ts, both pass. I did not run the whole suite. bun x tsc --noEmit could not check anything because it can't find the bun type definitions in this sandbox.

  • Shared row: the new src/web/stage-row.ts draws one stage as row() with a badge: Done (success), Running (attn) or Waiting (outline). The job's detail text sits in the row's meta line. src/web/pages/migrate.ts and src/web/pages/browse.ts both call it.
  • Live update: the migrate page script and mirrorJs in src/web/client.ts now set the badge text and variant and the meta text, instead of writing a glyph into .stage-dot.
  • Removed: .stage-dot and .stage-detail are gone from src/web/style/content.ts and from docs/DESIGN.md §5d. I trimmed the .stages li rules down to the Waiting dimming and updated the mirror stages row in the §5 table.
  • Test: a new case in test/migrate.test.ts fetches a job's page and asserts the three row states and badges. It also asserts there is no stage-dot or stage-detail.

I did not touch docs/design/baseline.json; it is empty and the design lint passes. The badge text and variants are written twice, in src/web/stage-row.ts and in the two scripts, and no test checks that they match. The old failed-state glyph (✕) in mirrorJs is gone: a failed job still shows its stages as Waiting, as before, with the error under the list.

Closes #4595

commented

Migration and mirror progress stages are now drawn as §5 list rows with a state badge, in the server markup and in the live update. bun test on the four related test files plus test/migrate.test.ts, and bun scripts/design-lint.ts, both pass. I did not run the whole suite. bun x tsc --noEmit could not check anything because it can't find the bun type definitions in this sandbox.

  • Shared row: the new src/web/stage-row.ts draws one stage as row() with a badge: Done (success), Running (attn) or Waiting (outline). The job's detail text sits in the row's meta line. src/web/pages/migrate.ts and src/web/pages/browse.ts both call it.
  • Live update: the migrate page script and mirrorJs in src/web/client.ts now set the badge text and variant and the meta text, instead of writing a glyph into .stage-dot.
  • Removed: .stage-dot and .stage-detail are gone from src/web/style/content.ts and from docs/DESIGN.md §5d. I trimmed the .stages li rules down to the Waiting dimming and updated the mirror stages row in the §5 table.
  • Test: a new case in test/migrate.test.ts fetches a job's page and asserts the three row states and badges. It also asserts there is no stage-dot or stage-detail.

I did not touch docs/design/baseline.json; it is empty and the design lint passes. The badge text and variants are written twice, in src/web/stage-row.ts and in the two scripts, and no test checks that they match. The old failed-state glyph (✕) in mirrorJs is gone: a failed job still shows its stages as Waiting, as before, with the error under the list.

Changes requested — before the latest push

The design direction is right: stages become §5 rows with a text badge (Done/Running/Waiting), which reads better to a screen reader than a bare glyph, and it works with JavaScript off. One thing to fix first: stage-row.ts says a test keeps the server table and the two client scripts in step, but no such test exists, and the same three labels and variants are now hand-copied in three places (stage-row.ts, mirrorJs, migrateJobJs). Add a test that would fail on drift, for example by asserting that each STAGE_BADGE text and variant appears in client.ts mirrorJs and in the migrate page script, or better, build the scripts from STAGE_BADGE via JSON.stringify so there is one table. Also add a test for the mirror page (stageList in browse.ts), which the new test does not cover. Smaller: the failed state is dropped from the live update (the old failed glyph and the data-state=failed styling are gone), yet DESIGN.md still lists data-state=done|now|failed|todo for this component. Make the doc match the markup, or give a failed job a visible failed stage with a danger badge. The failure is currently shown only as the error under the list. Also confirm bun x tsc --noEmit passes, since the builder could not run it.

commented

Migration and mirror progress stages are now drawn as §5 list rows with a Done / Running / Waiting badge. The live update writes the same markup. I could not run bun x tsc --noEmit here: it fails with TS2688 because node_modules/@types (the bun type definitions) isn't installed in this sandbox. bun test passes on test/migrate.test.ts, test/web-browse.test.ts, test/design-lint.test.ts and test/design-audit.test.ts, and bun scripts/design-lint.ts is clean. I did not run the whole suite.

Changes from the review:

  • One table: STAGE_BADGE in src/web/stage-row.ts is now the only copy of the badge labels and variants. mirrorJs (src/web/client.ts) and the migrate page script both build their badge table from STAGE_BADGE_JS, so they can't drift from the server markup.
  • Drift tests: the migrate page test asserts the page's script contains var badges = ${STAGE_BADGE_JS};. The mirror page test asserts mirrorJs contains the same table.
  • Mirror page test: test/web-browse.test.ts now checks the mirror job page. It asserts seven <li data-stage-name> rows, each wrapping a .row and a badge, and no stage-dot or stage-detail.
  • Failed state: I chose to make the doc match the markup rather than add a failed row. docs/DESIGN.md now lists data-state=done|now|todo for mirror stages. A failed job still shows its stages as Waiting, with the error under the list, as it did before this change.
commented

I merged main into the branch and pushed. The relevant tests and the design lint now pass.

My first conflict resolution in docs/DESIGN.md was wrong and I pushed it anyway. It dropped main's list of code-view classes (.blob-view, .ln, .tok-*), which broke two design tests. I rebuilt the file from main's version and re-applied only this pull's two edits:

  • Mirror stages row: now .stages > li > .row, with data-state=done|now|todo.
  • Page furniture list: .stage-dot and .stage-detail are removed.

git diff origin/main -- docs/DESIGN.md now shows only those two edits. I ran bun test on test/migrate.test.ts, test/web-browse.test.ts, test/design-lint.test.ts, test/design-audit.test.ts and test/design-map.test.ts (72 pass, 0 fail) and ran bun scripts/design-lint.ts (clean). I did not run the whole suite. bun x tsc --noEmit still can't run here because the bun type definitions aren't installed.

The pushed branch carries the bad merge commit followed by the repair commit, so the merge commit alone has the broken docs/DESIGN.md.

Approved — before the latest push

Stage rows now draw §5 row + badge on the server and in both live scripts, from one table (STAGE_BADGE), with drift tests; stage-dot/stage-detail are gone from CSS and DESIGN.md; state is now a word, not only a glyph, which helps screen readers; works with JS off. Preview answers 200. Two things next: (1) drop the redundant variant field in STAGE_BADGE and the ternary in STAGE_BADGE_JS (tone already decides data-variant; default maps to outline); (2) show a failed job as a Failed badge instead of Waiting on every stage, and make the migrate script null-safe on .row-meta like mirrorJs is.

commented

I merged main into the branch and pushed. The one conflict was in docs/DESIGN.md, in the page-furniture list. I kept main's version of that line and removed .stage-dot and .stage-detail from it.

Against main, docs/DESIGN.md differs by only two edits: the mirror stages row and that class list. I ran bun test on test/migrate.test.ts, test/web-browse.test.ts, test/design-lint.test.ts, test/design-audit.test.ts and test/design-map.test.ts (72 pass, 0 fail), and bun scripts/design-lint.ts is clean. I did not run the whole suite. bun x tsc --noEmit still can't run in this sandbox because the bun type definitions aren't installed.

Approved — before the latest push

Stages now draw as §5 rows with a Done/Running/Waiting badge, server and live, from one table (STAGE_BADGE) with drift tests; dead .stage-dot/.stage-detail CSS and docs removed; state is now in words, not just a glyph, which helps screen readers; works with JS off. Next: (1) in stage-row.ts, STAGE_BADGE has a redundant variant field and the badge() call passes variant outline for every state; derive the JS table from tone alone so there is one rule. (2) A failed migrate job still shows every unfinished stage as Waiting; give the failed stage a danger badge (Failed) so the page says where it broke, not only the error beneath.

commented

I merged main into the branch and pushed it. The only conflict was the "page furniture" class list in docs/DESIGN.md.

  • Resolution: I took main's list, which no longer has .app-shelf, .front-pin-any or .front-weights. I removed .stage-detail and .stage-dot from it, because this pull deletes them from the stylesheet and nothing under src references them now.
  • Tests: bun test on the migrate, web-browse and design suites passes (72 tests), and bun scripts/design-lint.ts is clean. The full bun test was still running after about six minutes when I stopped waiting, so I didn't get its result. The forge's check runs the whole suite on this push.
  • Type check: bun x tsc --noEmit can't run in this sandbox. It fails with "Cannot find type definition file for 'bun'", because I never ran bun install here. So there is no local type-check result; the forge's check will cover it.
Changes requested — before the latest push

The row and badge are the right design and the shared table is a good move, but the live update is broken for a stage that starts empty. row() in src/web/ui.ts omits .row-meta entirely when meta is empty, and stageRow passes an empty meta for every row that is not now. So on first paint only the running row has a .row-meta; every other row has none. In the migrate script row.querySelector('.row-meta').textContent = ... then throws a TypeError on the first stage that moves from todo to now, and the live progress stops. In mirrorJs the if (note) guard hides the throw, but the running detail (e.g. 'receiving 61%') never shows for any stage that was not already running when the page loaded. The tests only render the server markup, so neither case is caught. Fix first: always render the meta span (extend row() with an option, or have stageRow build it so .row-meta is always present, empty when idle) and add a test that every li[data-stage-name] contains .row-meta. Also worth doing: the doc and tests say a failed job shows Waiting rows; fine as before, but say so on the page near the error.

commented

I merged main into the branch and pushed it. The conflict was the same line of docs/DESIGN.md as last time, and I fixed it the same way.

I kept main's class list and removed .stage-detail and .stage-dot from it, because this pull deletes them. main has also dropped the .backups-* classes from that line since the last merge, and I kept that. The migrate, web-browse and design suites pass (72 tests), and the design lint is clean. I did not run the full bun test or the type check here, so the forge's check covers those.

I have not addressed @juniper's review. The .row-meta fix for stages that start empty is still not written: row() still drops the .row-meta span when meta is empty. I read the code and started on it, but made no edits. I also haven't added the test that every li[data-stage-name] contains .row-meta, or the note near the error saying a failed job shows Waiting rows. Those still need a pass.

Approved — before the latest push

Approved. Stages are now §5 rows with a Done / Running / Waiting badge. The state is a word, not a colour or a glyph, so it reads in a screen reader and with JavaScript off. The server markup and both live scripts come from one STAGE_BADGE table, and tests pin that. I checked row(): the meta span is emitted for every stage, because an empty Html object is truthy, so the scripts' .row-meta lookup never hits null. My earlier worry about that was wrong. The preview answers 200. I did not exercise a job page, which needs a session. Next: (1) a failed job still shows its stages as Waiting, so add a Failed state to STAGE_BADGE, or at least put the error right under the list with role=alert; (2) STAGE_BADGE_JS repeats the tone-or-variant rule from badge(), so add a test that a script-patched badge has the same data-variant as the server one.

commented

I merged main into the branch and pushed it. The conflict was again the "page furniture" class list in docs/DESIGN.md.

I took main's list, which now also lacks .merge-box, .merge-headline, .merge-sub and .merge-form, and nothing under src still uses them. I removed .stage-detail and .stage-dot from it, because this pull deletes them.

The migrate, web-browse and design suites pass (72 tests) and the design lint is clean. I did not run the full bun test or the type check here, so the forge's check covers those.

@juniper's requested changes are still not made. row() still drops .row-meta when meta is empty, so the live update still throws on a stage that starts empty. I have not added the test that every li[data-stage-name] has .row-meta, or the note near the error about Waiting rows after a failed job.

Approved — before the latest push

Stages are now §5 rows with a Done/Running/Waiting badge, in the server markup and in both live-update scripts. The badge table lives in one place (STAGE_BADGE) and both scripts are built from it. The preview answers 200, no stylesheet debt is left behind, and the tests cover the new markup and the drift guard. I could not see a running job on the preview, so I judged the live update from the source.

One correction to the notes on this pull: row() does not drop .row-meta when the meta is empty. stageRow passes an Html object, which is always truthy, so every li carries a .row-meta and the live update will not throw. That earlier concern does not hold, so the change did not need to be blocked on it.

Two things I would do next:

  1. Add a test that every li[data-stage-name] contains .row-meta and a .badge, so the scripts cannot break if row() changes.
  2. Say in the UI that a failed job leaves its stages as Waiting. Put a short line next to the error, because a person reading all-Waiting rows next to an error may not realise the job failed.
commented

I merged main into the branch and pushed it. This push also contains the fix for @juniper's review of the stage rows.

  • Merge: docs/DESIGN.md conflicted on the "page furniture" class list again. I took main's list, which now also lacks .wall-cells, and removed .stage-detail and .stage-dot, which this pull deletes. Nothing in src uses .wall-cells any more.
  • Live update:

- row() in src/web/ui.ts has a new metaSlot option that draws .row-meta even when meta is empty, and stageRow sets it. Every stage row now has a .row-meta, so a stage that moves from Waiting to Running after load gets its detail. - The migrate script in src/web/pages/migrate.ts now checks for .row-meta before writing to it, so it can't throw. - The mirror page's script in src/web/client.ts already had that check, so I left it. The mirror page also builds its rows with stageRow, so it gets the same markup.

  • Failed jobs: The page now says, under the error, that the stages show Waiting because the job stopped and none is running.
  • Test: The job-page test in test/migrate.test.ts now checks that every li[data-stage-name] contains class="row-meta". That would fail without metaSlot.
  • Checks: The migrate, web-browse, design, asked and app-domains suites pass (103 tests) and the design lint is clean. I did not run the full bun test or the type check here, so the forge's check covers those.
  • Not covered: No test runs the live-update scripts in a browser. The null-safety is checked by reading the code and by the markup test.
Changes requested — before the latest push

The idea is right and the shared stageRow + one STAGE_BADGE table feeding both scripts is clean. One thing to fix first: the rows are no longer inside a §5 list. Both <ol class="stages"> lists (migrate.ts stageRows, browse.ts stageList) lack the list class, and this pull deletes the .stages li + li divider. .list > li + li (style/components.ts) is what separates rows, so the seven stages now stack with no rule between them and no card, which is not "§5's row". Fix: render the ol as class="list stages" (keep the data-* hooks) and keep .stages { list-style:none; margin:0; padding:0 } only if .list does not already reset it. Then confirm in the preview at 360px that the badge stays on the row's trail without wrapping the label.

Two smaller points: (1) a failed job shows every stage as a 'Waiting' badge, so the one stage that failed is not marked; the sentence under the error helps, but a failed row (danger badge, text 'Failed') would be what a person needs, and DESIGN.md's old failed state was the right call. (2) the badge changes live with no announcement; put aria-live="polite" on the ol so a screen reader hears 'Running' / 'Done'. Tests cover the markup and script-table drift well; add one asserting the ol carries list.

commented

Both stage lists now sit in §5's .list, so the rows have dividers again. A failed job also marks the stage it stopped on. I pushed this to the same branch.

  • List: migrate.ts and browse.ts draw <ol class="list stages" aria-live="polite">, with the data-* hooks kept. I kept the .stages reset because .list doesn't reset the list style, margin or padding itself. A screen reader now hears "Running", "Done" and "Failed" as they change.
  • Failed stage:

- MirrorJob has a new failedAt field, set in advance() when a job moves to failed. This was needed because advance() overwrote the stage on failure, so the page couldn't know which stage failed. - A new stageStateFor() in src/web/stage-row.ts replaces the two separate state calculations. It gives earlier stages Done, the failing stage a danger "Failed" badge, and later stages Waiting. - I removed the "stages show Waiting" sentence, since the Failed badge now says it.

  • Live scripts: the mirror and migrate scripts still paint every row Waiting for a failed event. They reload the page straight after, so the server-drawn Failed badge is what a person sees.
  • Tests: test/migrate.test.ts and test/web-browse.test.ts now assert that the ol carries list and aria-live. A new test checks that a failed job shows Done, then Failed on the failing stage, then Waiting. Those two files plus the design and origins suites pass, and the design lint is clean. I did not run the full bun test. The type check can't run in this sandbox (bun types are missing), so the forge's check covers it.
  • Not done: I did not check the 360px layout in the preview, so I can't confirm the badge stays on the row's trail without wrapping the label.
  • Docs: docs/DESIGN.md line 185 is updated for the new markup and the failed state. Its table column is now wider than the other rows, which I didn't re-pad.
Approved

Approved. Every stage of a migration or a mirror is now a §5 .list row with a word badge: Done (success), Running (attn), Failed (danger) or Waiting (outline). The server markup and both live scripts build their badges from one table, STAGE_BADGE. advance() now records failedAt, so a failed job marks the stage it broke on and keeps the stages before it as Done, instead of showing every stage as Waiting. Security is clean: STAGE_BADGE_JS is a compile-time constant, so mirrorJs still carries no runtime data under the nonce'd CSP. job.detail is still escaped through html. failedAt is only a stage name, and the change touches no write paths, auth, body parsing or SQL. On the design side, the .stage-dot/.stage-detail rules are gone from the stylesheet and from DESIGN.md, with no hand-rolled markup left. The page works with JavaScript off, and aria-live announces state changes. The tests would fail without the change: they check the row and badge markup, the .row-meta slot on every row, the failed-stage ordering, and that the scripts and the server markup use the same table. On the preview, / answers 200 and /migrate sends a guest to sign in. I could not watch a live job there without a session, so I judged the live update from the source.

Non-blocking follow-ups:

  1. STAGE_BADGE.variant duplicates what badge() already works out from tone, and stageRow passes variant: "outline" for every state. Drop the field and have STAGE_BADGE_JS apply tone === 'default' ? 'outline' : tone, so the rule exists once.
  2. On a failed event, both live scripts still paint every row Waiting just before they reload. It is harmless, but the scripts could use badges.failed on the last running row, or simply skip the paint before reloading.
  3. No test renders the mirror page (stageList) for a failed job with failedAt. Only the migrate page covers that path.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs