Repository navigation
feat: fleet view, migration flow and staged state UI (S2 lane 6b) - #95
Merged
lr00rl merged 7 commits intoOct 17, 2026
Merged
Conversation
…nge waits on
Design 28 S2 lane 6b, the UI half of plan sections 6, 7 (lane 6b row) and
11. A fleet-bound record's edit waits in staged-v2 until core promotes it,
so the Records table now says both facts in the Published column: what is
live, and the staged revision with what it waits on ("plan pending",
"publish", "plan stale", "apply failed"), with both revisions in the proof.
The row menu, the side panel, the record page and the palette share the
new verbs through the action registry: Publish staged revision (propose,
then publish in one click when no live share in the closure names an
identity; a filed plan or a refusal opens the plan sheet), Migrate to
fleet, Share identities (an assignment-only plan for shares that answer
the decoy, a clear-only plan for an identity that buys nothing) and
Discard staged revision (a confirmation naming both revisions and the plan
it stales). A fleet-bound record's Delete goes through plans.propose
{action: "delete"}, shows the shares it archives, and is blocked with
"Remove from <combination>" while a combination names the record.
MigrationFlow.vue is one stepper for the four plan modes. A migration
stages the record and the other legacy members of every combination that
reads it (migrate_record), shows the selection, the plugin's warnings and
the files that block it (predicted from the list, and named by
refused.files), asks for an identity or an archival per share with graph
records defaulting to their own identity, warns when an identity holds
none of the lines, and proposes one plan. The status step reads
planState(): pending with Open in Approvals, stale with Propose again,
failed with the record's live revision from the list, and a partially
applied multi-record plan with the records that applied and Propose the
rest. Abandon migration discards what the flow staged.
The Fleet view is a new layer: fleet-bound records on the left; for the
chosen one, identities as rows with one bind.preview per identity on
expand or Preview all, reason chips, exclusion groups with core's fix,
Create share for this identity and Bind identity to this selection, whose
unknown-method answer (operator decision 8 not taken) is said as such.
Every refusal a mutating method sends as {saved: false, refused} is read
as one: delete (fleet_delete_requires_plan, with a sentence in en, zh-CN
and ru), migrate_record, discard_staged, import and migrate. A new
record's refusal on the error channel now names the record by the id it
would have had instead of as another record. A legacy record's output,
preview and file output show the owner_credentials_withheld notice with a
Migrate to fleet action, its Fetch now is disabled with the reason, and a
probe that reaches the guard says the rule, never an outage. The record
page counts a fleet record's selection steps from fleet_preview.
core-types.ts is regenerated at lattice-server 7ba7206 for the plan
sections, assignments, archivals and the status row's stale, action and
mode. A pending intent from the palette, a panel or the Fleet view no
longer meets the Records screen's flow state before it is declared.
Constraint: bind_selection is declared by the manifest and not served by
core until operator decision 8 is recorded; the UI says so and links
vpn-core Users.
Rejected: a fifth component for the plan view; PlanStatus.vue carries the
chip and, with detail, the plan text, as the plan's file list allows.
Tested: npm test (65 files, 779 passed, 1 skipped), npm run typecheck,
npm run build, npm run verify:build, contract.test.ts regenerated against
lattice-server 7ba7206.
…hs and themes The harness gains the plans fixture (?fixture=plans, dev/planFixtures.ts) and core's plans service, migrate_record, discard_staged, the staged state the list reports, the structured delete refusal, the owner-credential withholding of a legacy record's render and probe, and bind_selection (dev/planHost.ts), all inert without ?manifest=s2. ?plans= picks core's plan states: denied, large, failed, promoted, partial, stale, closure and bind. Revisions are shaped as the plugin writes them, 32 hex characters. migration.spec.ts and fleet-view.spec.ts drive each state of lane 6b's UI acceptance rule by named elements at 1440 and 375, light and dark, with axe finding nothing serious, then zh-CN and ru, and write a screenshot per state when SHOTS_DIR is set. The client sheet's target chips fail colour contrast on every record, this lane's or not; the withheld-output test excludes that one selector and says so. Tested: npx playwright test, whole suite against a private dev server: 365 passed, 2 skipped (the English-only skips); the two new files: 134 passed.
… true The code and design reviews of lane 6b found states that showed nothing, or the opposite of the truth, and one migration that could not recover. A co-migrated sibling whose migrate_record fails is now tracked per record: it blocks Next and Propose, the flow names it with the reason, and "Try staging again" re-runs only the missing ones, so a plan can no longer go out with an empty to_revision. Abandon asks first, in the flow, naming each staged revision it drops and the pending plan it stales; it sits in its own slot away from Back and is offered at the status too, also for a migration reopened from Publish. A carried-over step's warning is a warning notice with its way out (abandon, then the record's steps open in the editor), repeated beside the record in the propose summary. A files-blocked migration says the files in the footer, disables Stage after a file refusal, and links each file to its panel. The Fleet view asks again for every open row when Live and Staged switch, says "answers the decoy (expired)" on an inactive identity and offers it no share, brings the detail into view on a phone and stacks a row's counts under its name. The side panel and the record page show the staged revision, the plan with core's state, reason and the live revision, the decoy shares and a mixed combination, each with its way out, so the Overview's attention items no longer lead to a panel that reads "ok". A fleet-bound row's Delete says shares are archived, and its last step is a danger "Delete" with the proof that core files a plan when a share names an identity. A pending delete or share plan shows in the Published cell. Remove from <combination> opens the members tab with a notice on how to get back to the delete. The discard dialog heads its notes "What happens:". The plan view's share rows have a chevron and open when a share receives nothing or has lines left out, counts are spelled out, every promoted record is listed, a plan reopened later says its content is in Approvals, and steps this sitting never showed are not ticked. Also: the target chip's format label drops its 0.75 opacity, which failed axe contrast, so the withheld-output test no longer excludes it; the name check skips patterns past 256 characters or with a nested quantifier and reads as advisory; core's explicit-dependents sentence is parsed in one tested place; "plans" rides the harness address so its states survive a navigation; operator copy drops "S3" and "operator decision 8". Tested: npm test (785 passed, 1 skipped), typecheck, build, verify:build, the dev harness typecheck, the whole Playwright suite (393 passed, 2 skipped), the system-go UI-reading tests.
…ete or abandon leaves The second design review of lane 6b found six problems that remained. A row menu item that opens a sheet closed the menu, and the menu then put focus back on its trigger after the sheet had focused itself. Focus ended up behind the sheet, under the scrim at 375. closeRowMenu now gives focus back only when nothing else has taken it. A sheet, drawer or output sheet opened from the menu returns focus to the menu's button in the row, because the menu item is gone by then. At narrow widths the first ArrowDown in the Fleet records moved focus to the detail, and later presses only scrolled the page. Arrow keys now keep focus in the radio group. A click or tap, Enter, Space, or a new "Show the identities for <record>" button after the list brings the detail into view. The chassis gives a cell's sub-line a minimum width of 126px, which is wider than the Published column at 1440, so the cell cut off the decoy and darkened sentences. The sub-line now takes the cell's width and wraps. The "Abandon, then edit the steps of <record>" button did not wrap and was wider than a 375 sheet. It now reads "Abandon and edit steps". The record is named in the notice and in the button's accessible name. A delete on a record with a staged revision now says the staged revision is dropped and that the pending promote plan goes stale. In the table, the Fleet view and the record panel, a pending, stale or failed delete plan wins over the staged revision and its promote plan (pendingDelete, rowPlan). Propose again on a delete plan opens the delete again, not Publish. Abandoning a partly applied plan now names each combination that stays blocked, with its shares, and points to Propose the rest. The line under the button no longer says that everything keeps serving. Nits taken: Preview all is asked again for every row after a revision switch; an archived share is left out of the plan's unbound list; the co-migrated record "will be staged" before migrate_record answers; the sibling retry sits under the reason below 480px; each refused file is named once; the Fleet row error uses the body face. The dev harness gains ?plans=applied and ?plans=rejected. settled() now also fails when an open sheet's body scrolls sideways. Tested: vitest 64 files (787 tests, 1 skipped); vue-tsc; dev harness typecheck; npm run build and verify:build; Playwright fleet-view and migration specs, 198 passed at 1440 and 375, light and dark, en, zh-CN and ru.
…ecoy The first assertion looked for the word archived in the unbound list, a marker the fix removed along with the archived entries, so it passed with or without the filter. It now asserts that both shares are archived and that the unbound list is absent. A mutation that lists archived shares again fails it.
…eet records after arrow keys The focus and arrow-key tests now leave a screenshot when SHOTS_DIR is set, so the review can see where focus is at 1440 and 375, not only read it in an assertion.
CI's ru run of the new cell check found the nowrap badge 7px past the kind cell on every legacy row: "учётные данные владельца" in the Linux face is wider than the column at 1440, and the cell clips. The badge now takes at most the cell's width and wraps to a second line when it must. With a wider face forced locally it wraps inside the cell; on macOS it stays one line.
lr00rl
merged commit Oct 17, 2026
8c94388
into
feature/20261010_s2-fleet-sources
5 of 6 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Design 28 S2 lane 6b: the Fleet view, the migration flow and the staged state (
ui/). Plan sections 6, 7 (lane 6b row) and 11, over the contracts of lanes 4 (plugin methods and structured refusals), 5b (plans, closure, gateway) and 6a (client.ts,fleet.ts). No tag, no release.What this changes
Staged state in Records. A fleet-bound record's edit waits in staged-v2, so the Published column says both facts: the live share state, and the staged revision over what it waits on (
plan pending,not proposed,plan stale,apply failed,plan approved), with both revisions in the proof (title and screen-reader text). Shares that answer the decoy (no identity on a fleet-bound record) and identities that buy nothing (an identity on a non-fleet record) get a line of their own. A legacy record carries anowner credentialsbadge in the kind cell, andisFlaggedreadsowner_credentialstoo, so the attention sort and the side panel and record page flag cover both. A combination flagged bothfleet_boundandowner_credentialsreadsblocked: migrate <member> first.New verbs, one registry.
recordActions.tsgains Publish staged revision, Migrate to fleet…, Share identities… and Discard staged revision, each shown only on a record in the state it is for (applies), with a reason when the session lacks the method. The row menu, the side panel, the record page and the palette all use them; the panel and the page hand plan verbs, and a fleet-bound record's Delete, over to the Records screen, which holds the plan sheet.plans.propose, thenplans.publishin the same click when core answersrequired: false(a migrated record with no shares publishes from the menu alone). A filed plan, or a plan already waiting on that revision, opens the sheet at its status;shares_without_identityandmigration_requires_planopen it at the share identities step.plans.propose {action: "delete"}with the record's own shares listed as archived; while a combination names the record explicitly the delete is blocked, and "Remove from " opens that combination's editor with the member already removed. A plain delete the plugin refuses (fleet_delete_requires_plan, read from{saved: false, refused}) is said in words with "Delete through a plan" beside it.discard_staged.MigrationFlow.vue: one stepper for four plan modes (migrate, publish, delete, assign). A migration stages the record and the other legacy members of every combination that reads it (
migrate_record,co_migrate), shows the selection, the plugin's warnings and the files that block it (predicted from the list before staging, named byrefused.filesafter), asks for an identity or an archival per share (graph records default to their own identity; an export record has none), warns when an identity holds none of the lines with "Bind identity to this selection", and proposes one plan over every staged record. Status readsplanState(): pending with Open in Approvals (/approvals?open=<id>, on the console's allowlist), stale with Propose again (a replaced staged revision and a grown closure included), failed with the record's live revision fromlistbeside it ("was promoted" or "was not promoted"), and a partially applied multi-record plan naming the records that applied, whose shares already serve their identities, with Propose the rest. Every step offers Abandon migration. The plan view lists, per share, what its identity receives and loses and the lines left out grouped by reason with the fix, then the assignments, clearings and archivals. Nothing shows a credential or a share link. Abandon and Next wait while the siblings stage.Fleet view (FleetScreen.vue), a new layer shown once the handshake declares any S2 method: fleet records and the combinations that gather them on the left; for the chosen record, identities as rows with one
bind.previewper identity on expand or Preview all (two at a time, never N×M eagerly), reason chips, exclusion groups with core's fix, the decoy count with Share identities…, the staged revision previewed beside the live one, the record's plan with its status, Create share for this identity (fleet-bound records only) and Bind identity to this selection. The proof line names the catalogue version, the line count, probe availability, the revision previewed and the identity count.Refusals and the withheld state. Every mutating call reads
{saved: false, refused}: delete,migrate_record,discard_staged, import and migrate (per-recordstagedandrefusedfrom an import are said after the count). A legacy record's preview, client output and a file over one show theowner_credentials_withheldnotice with Migrate to fleet (WithheldNotice.vue); Fetch now is disabled on such a record under 0.18, and a probe that reaches the guard says the rule, never a provider outage. The record page counts a fleet record's selection steps fromfleet_preview("117 → 23", not "23 → 23").Overview adds attention items for records that still serve owner credentials (counted), mixed combinations, decoy shares, failed plans and waiting staged revisions.
Carried items
useSubscriptions.tsare kept and owned: save sendsdraft.fleetand reads the structured refusal.refusalMessage(now taking an optional lead, "Not deleted: …"), with a sentence forfleet_delete_requires_planin en, zh-CN and ru, and tests;migrate_record,discard_staged, import and migrate read it the same way. Restore has no caller inui/src(no archive surface yet), so there is nothing to wire there.planCalls.test.ts, killed mutation 3 below).propose {action: "delete"}thenpublish {action: "delete", expected_revision}onrequired: false; a clear-only plan isfrom == towith everyshare_identitiesvalue"".Review fixes (second round, e64c138)
The code review and the design review of e6f76cc, each finding with its fix and its evidence (an e2e or unit test, and a screenshot under the directory below).
Code review:
migrate_recordfailure is kept per record; while any sibling has no staged revision, Next and Propose are blocked and a danger notice names it with core's reason and "Try staging again", which re-runs only the missing siblings (unstagedSiblingsinplanFlow.ts). Evidence: e2e "a sibling that fails to stage blocks the flow until a retry stages it" over the new harness state?plans=sibling; unit test; mutation M10;migration-sibling-failed-*..target-chip-producesdrops itsopacity: 0.75(the chip's muted ink already sets it apart), and the withheld-output test runs axe with no exclusion. Evidence: that test at 1440 and 375, light and dark, zero serious;withheld-output-*.e2e/plans.tsnow captures the viewport whenever a sheet or dialog is open. The design review below drove both surfaces. Evidence:migration-*-375-*,delete-propose-375-*.isFlaggedonly guarded by e2e: unit test forisFlaggedandflagOf(owner credentials before the regex label). Mutation M13.unmatchedNameStepsskips a pattern past 256 characters or with a nested quantifier, reads labels to 128 characters, and its warning now says it is checked in the browser and that the plugin's engine decides. Core's explicit-dependents sentence is parsed byexplicitCollectionsFrom, whose unit test pins the sentence fromsubstore_svc_plans.goso a rewording fails a test. Mutation M14.Design review:
fleet-staged-row-*.RecordPlanState.vue, mounted in the side panel and the record page header, shows the staged revision with its proof, the plan with core's state, reason and the live revision verdict (Propose again, Check again, Open in Approvals), the decoy shares with Share identities…, and a mixed combination with Migrate to fleet. Evidence: e2e "an Overview attention item opens a panel and page that show the failed plan" and "a combination core refuses says so in its panel"; mutation M12;overview-failed-panel-*,overview-failed-page-*.migration-abandon-confirm-*,migration-abandon-status-*.migration-2-staged-*.LtConfirmDialogtakesconsequencesTitle; discard heads its notes "What happens:" in the body face. Evidence: e2e discard test; mutation M18;discard-confirm-*.data-variant="danger"and proof;delete-propose-*.delete-pending-row-*.noticeslot added toSubscriptionEditor.vue. Evidence: e2e explicit-member test;delete-remove-member-editor-*.nextBlockedchecks the files before "stage first", Stage is disabled after a file refusal, and each predicted file opens its own panel. Evidence: both file e2e tests; mutation M16;migration-blocked-files-*,migration-refused-files-*.migration-4-status-*.fleet-inactive-*.fleet-chosen-*.plan-reopened-*.plansjoins the harness address params, so?plans=states survive the first navigation (unit test inpageState.test.ts, mutation M19).Files outside this lane touched by the fixes:
LtConfirmDialog.vue(one optional prop),SubscriptionEditor.vue(onenoticeslot),styles.css(the chip opacity),RecordSidePanel.vueandRecordPage.vue(mountRecordPlanState),recordActions.ts(titletakes the record),dev/consoleAddress.tsanddev/planHost.ts(harness).Review fixes (third round, 6b2135a and ba0d55d, tests tightened in 69ac154 and d5e5ab7)
The second design review of e64c138 left six Should-fix findings and nine nits. Each Should-fix is closed with an e2e or unit test and screenshots at 1440 and 375.
Focus left behind the sheet when a flow opened from the row menu. The menu closed in the same tick and then put focus back on its trigger after the sheet had focused itself.
closeRowMenunow gives focus back only when nothing else has taken it (focus still on<body>or in the vanished menu). A sheet, drawer or output sheet opened from the menu returns focus to the menu's button in the row (overlayTrigger), because the item is gone by then. Evidence: new e2e " from the row menu puts focus in the sheet, and Escape gives it back to the menu" for migrate, delete, share-identities and publish-staged at 1440 and 375, plus discard's dialog; mutations M20 and M28;focus-*.At 375 the first ArrowDown in the Fleet records moved focus to the detail. Arrow keys now keep focus in the radio group. A click or tap, Enter or Space on a record, or a new "Show the identities for " button after the list (visible when focused, below 960px only) brings the detail into view and focuses it. Evidence: e2e "arrow keys walk the records and keep focus there; Enter and the skip button bring the detail" (two ArrowDowns: focus on the third radio, scrollY unchanged); mutation M21;
fleet-arrows-*,fleet-skip-375-*,zz-fleet-skip-375-en.png.The Published cell cut off its decoy sentence. The chassis gives a cell's sub-line a minimum width of 126px (
.pc-table td small), wider than the column at 1440.small.rec-decoyandsmall.rec-blockednow take the cell's width and wrap. Evidence: e2e " : the Published cell's sentences stay inside the cell at 1440" in en, zh-CN and ru, light and dark, checking every child rect oftd.rec-publishedandtd.rec-kind-cell; mutation M22;records-published-cell-*,zz-published-*.The nowrap "Abandon, then edit the steps of " button scrolled the 375 sheet sideways. It now reads "Abandon and edit steps". The record is named above it in the notice and in the button's accessible name ("Abandon and edit steps: ").
settled()now fails when any open sheet's body scrolls sideways, so every state the suites drive checks this. Evidence: the carried-over warning e2e asserts the label and accessible name; mutation M23 (the long label back) fails the main migration test at 375 through the new check;migration-fix-steps-*,zz-fixsteps-*(the sheet body measured 374 of 374 px at 375 in all three locales).A delete on a staged record with a pending promote plan said nothing about either, and the table kept "staged … plan pending". The delete's What changes step now has a "Dropped with it" block: the staged revision is dropped and never published, and the pending plan goes stale once the record is deleted.
pendingDeleteandrowPlaninplanFlow.tslet a pending, stale or failed delete plan win over a staged revision and its promote plan in the table badge, the Fleet view and the record panel and page.deleteStategainsstale. Propose again on a delete plan there hands over Delete, not Publish. Evidence: e2e "a delete over a staged record names what it drops, and the table says delete over promote" (the reviewer's steps: remove from the combination, save, delete, propose, close); unit test "lets a delete plan win over a staged revision and its promote plan"; mutations M24 and M26;delete-staged-drops-*,delete-staged-row-*.Abandoning a partly applied plan claimed that the legacy records keep serving. The confirmation now names each combination left blocked, with its shares ("Japan combination stays blocked: … refuses to serve its shares (Japan family link)"), and points to Propose the rest. The line under the button names the combinations that stay blocked. Evidence: e2e "abandoning a partly applied plan names the combination it leaves blocked"; mutation M25;
migration-abandon-partial-*.Found by the new cell check on CI, not by the review: in the Linux face the nowrap "owner credentials" badge ("учётные данные владельца") ran 7px past the kind cell on every legacy row in ru. The badge now takes at most the cell's width and wraps (ba0d55d). On macOS it stays on one line. With a wider face forced locally it wraps inside the cell (
zz-owner-badge-wide-ru.png). The CI run on ba0d55d is the proof, because the macOS fonts never overflowed.Nits taken:
migrate_recordanswers. Asserted in the main migration test.zz-sibling-375-*.refused.filesblock names each file once: our sentence plus the list, with core's sentence kept in the title. Asserted in the refused test.?plans=appliedand?plans=rejected: a plan proposed in the sitting reads as applied or rejected the first time its status is read. E2e "a plan the approver applied, and one the approver rejected";plan-applied-*,plan-rejected-*.Nits not taken:
pipe.healthfor every record, outside this lane.recordTable.tslabel and thestyles.csswrap rule, both outside this lane).Files outside the lane touched in this round: none beyond the round-two list (
RecordPlanState.vueandPlanStatus.vueare this lane's).Files in other lanes' or unowned files (smallest changes)
ui/src/core-types.ts(6a): regenerated withgo run ./tools/tsgen -ref 7ba720658817b959978d3d97fc3077dbf633422c(the server feature head, lanes 5a and 5b merged);contract.test.tsregenerates and matches withLATTICE_SERVER_DIRat that commit.ui/src/fleet.ts(6a):refusalMessagetakes an optionallead.ui/src/pipeline.ts(6a):ViewIdgainsfleet.ui/src/components/SubscriptionEditor.vue(6a): the withheld notice isWithheldNotice(samedata-testid, plus Migrate to fleet); the now unused.side-coderule removed. Messages:fleetEditor.refusal.codes.fleet_delete_requires_planin three locales.Shell.vue(the Fleet tab),lensChrome.ts,pageState.ts(thefleetview),recordActions.ts(the S2 verbs,ActionContext, Fetch now withheld),RecordMenu.vue(icons,data-action),RecordActions.vue(hand-over),RecordSidePanel.vueandRecordPage.vue(flagOf, withheld, fleet step counts),TargetSheet.vue(withheld),useSubscriptionOps.ts(import and migrate refusals); testsrecordActions.test.ts,commandPalette.test.ts(capability fixtures),subscriptionsList.test.ts,filesList.test.ts(the source scan accepts the shares context); harnessdev/fakeHost.ts,dev/fixtures.ts(one hook each).src/planFlow.ts(the pure rules, tested),src/components/WithheldNotice.vue,src/components/RecordPlanState.vue,src/planFlow.test.ts,src/planCalls.test.ts,dev/planHost.ts,dev/planFixtures.ts,e2e/plans.ts.Dev harness
?fixture=plans&manifest=s2serves the plans fixture (asia-fleet staged with a pending plan and a decoy share, fleet records with identity shares, legacy export and graph records, a combination that migrates two graph records together, a file that blocks a migration, a mixed combination after a partial migration, a provider record whose share names an identity).?plans=denied|large|failed|promoted|partial|stale|closure|bind|sibling|applied|rejectedpicks core's plan states (sibling: the firstmigrate_recordof the co-migrated sibling fails, a retry stages it;appliedandrejected: a plan proposed in the sitting reads as decided the first time its status is read). Revisions are 32 hex characters, as the plugin writes them.Requests
origin,createandforon/platform/publishing, so "Create share for this identity" cannot preselect the identity; the notice names the identity to choose. Anidentityparameter there would close it.tools/tsgen):subStorePlansPublishReplyis not generated; the UI types it locally (PublishReplyinplanFlow.ts).Mutation checks (each applied to the committed tree, the named tests run, restored with git checkout)
shareFieldssends an identity-to-identity move:planFlow.test.tsfails.planCalls.test.tscases fail.draft.id.trim()instead of the derived id:planCalls.test.tsfails.holdsNoLinenever warns:planFlow.test.tsfails.planCalls.test.tsfails.Second round, on e64c138, each killed:
RecordPlanState: the Overview e2e test fails.isFlaggedignoresowner_credentials:recordTable.test.tsfails.planFlow.test.tsfails (the test's label is short enough to fail rather than hang).nextBlockedsays "stage first" before the files: the files-blocked e2e test fails.consequencesTitle: the discard e2e test fails.plansdropped from the harness params:pageState.test.tsfails.Third round, on 6b2135a and 69ac154, each killed:
closeRowMenugives focus back even after a sheet took it: 6 of the 10 focus tests fail (migrate, delete, share-identities at both widths).settled()'s sheet-width check.Tests run
At 6b2135a (UI code), with the test-only commits 69ac154 and d5e5ab7 rerun, and the record-table and cell tests rerun at ba0d55d:
npm test: 64 files, 787 passed, 1 skipped (core-types regeneration needsLATTICE_SERVER_DIR).npm run typecheck,npm run build,npm run verify:build: clean (the existing chunk-size warning). The harness typechecks under a scratch config that includesdev/.migration.spec.tsandfleet-view.spec.ts: 198 passed, every state at 1440 and 375, light and dark, axe zero serious with no exclusion, the new sheet-width check in everysettled(), then zh-CN and ru.GOTOOLCHAIN=go1.26.9 go test -count=1 -run 'Operator|Parity|Vocabulary|UI|Manifest' ./...oversystem-go/: ok. No Go code changed.At e64c138:
npm test: 64 files, 785 passed, 1 skipped (the core-types regeneration check, which needsLATTICE_SERVER_DIR).npm run typecheck,npm run build,npm run verify:build: clean (the existing chunk-size warning). The harness typechecks under a scratch config that includesdev/.migration.spec.tsandfleet-view.spec.ts: 162 passed, every state at 1440 and 375, light and dark, axe zero serious with no exclusion, then zh-CN and ru.GOTOOLCHAIN=go1.26.9 go test -count=1 -run 'Operator|Parity|Vocabulary|UI|Manifest' ./...oversystem-go/(the tests that readui/src): ok. No Go code changed.At e6f76cc (first round): 779 unit tests passed, 365 e2e passed, CI run 38932250709 green except the expected "package twice and compare bytes".
Screenshots
Third round, from 6b2135a (later commits change tests, and the badge at ba0d55d, re-rendered in
records-published-cell-*):/private/tmp/claude-501/-Users-cdcd-roobli-RTFS-justTaste-Probe-Dashboards-Lattice/27b544c4-30e3-43cb-89f0-aa6a8b2ed3ca/scratchpad/wave3-fix-6b/shots/, 229 files. Every state above is re-rendered at 1440 and 375 in light and dark. New states: delete-staged-drops, delete-staged-row, fleet-arrows, fleet-skip (375), focus-migrate, focus-delete, focus-share-identities, focus-publish-staged, migration-abandon-partial, migration-fix-steps, plan-applied, plan-rejected, records-published-cell (1440, three locales). Close-ups start withzz-: zz-fixsteps-, zz-published-, zz-sibling-375-*, zz-fleet-skip-375-en.Second round, from e64c138:
/private/tmp/claude-501/-Users-cdcd-roobli-RTFS-justTaste-Probe-Dashboards-Lattice/27b544c4-30e3-43cb-89f0-aa6a8b2ed3ca/scratchpad/wave2b-fix-6b/shots/, 166 files named<state>-<width>-<theme>-<locale>.png, each state at 1440 and 375 in light and dark (a viewport capture when a sheet or dialog is open, else the full page): assign-decoy, clear-identity, delete-blocked-member, delete-pending-row, delete-propose, delete-refused-requires-plan, delete-remove-member-editor, delete-through-plan, discard-confirm, fleet-chosen, fleet-denied, fleet-dropped, fleet-empty, fleet-error, fleet-failed-promoted, fleet-inactive, fleet-loading, fleet-previews (also zh-CN, ru), fleet-readonly, fleet-staged-decoy, fleet-staged-row, migration-1-changes, migration-2-staged, migration-3-identities, migration-4-status, migration-abandon-confirm, migration-abandon-status, migration-blocked-files, migration-identities (zh-CN, ru), migration-refused-files, migration-sibling-failed, overview-failed-page, overview-failed-panel, plan-closure-grew, plan-failed (also zh-CN, ru), plan-partial, plan-reopened, plan-stale, plan-too-large, propose-denied, withheld-output.First round, from e6f76cc:
/private/tmp/claude-501/-Users-cdcd-roobli-RTFS-justTaste-Probe-Dashboards-Lattice/27b544c4-30e3-43cb-89f0-aa6a8b2ed3ca/scratchpad/wave2b-6b/shots/(118 files).Done
Not done
pipe.health, outside the lane); the slug breaking at its hyphen (outside the lane).bind_selectionis not served by core until operator decision 8 is recorded; the UI calls it and says "not available on this server" with a link to vpn-core Users when core answers unknown method.record.fleetintodraftFromRecord(lane 6a's optional suggestion) was not taken.migrate_record's warnings are the plugin's English text and are shown as sent.