Skip to content

Close the device-gone hole, then delete the retired step-stack device pane - #171

Open
Yona-Appletree wants to merge 10 commits into
mainfrom
claude/retire-device-pane-2242af
Open

Close the device-gone hole, then delete the retired step-stack device pane#171
Yona-Appletree wants to merge 10 commits into
mainfrom
claude/retire-device-pane-2242af

Conversation

@Yona-Appletree

Copy link
Copy Markdown
Member

Closes the defect that made the retired device pane reachable, then deletes the pane.

Read docs/defects/2026-07-28-retired-device-pane-still-reachable.md first — it carries the full root-cause trace. (That file wasn't in main; it and the README-hero fix rode the tail of claude/upbeat-leavitt-0a9b73 and never merged, so they come along here.)

Phase 1 — the holes (4ef773d)

The editor has exactly one device surface, but lens_device_card() returned None the moment the lens device reported DeviceState::Gone: the gallery roster's Offline filter was firing at lens scale too. Nothing resets the project on device-gone, so the project stayed Ready, panes kept rendering, and the shell fell through to the retired pane. Stable state, not a transient.

  • device_card_from_live_evidence is the unfiltered, total derivation. live_device_card keeps the Offline filter for the gallery roster only (there the registry card is better informed). The unplugged lens now fades to "Seen …/Reconnect" rather than vanishing — the lens and the project are untouched, per Yona's call: a flaky cable must not yank anyone out of their editor.
  • Live evidence carries no registry entry, so the offline lens borrows the remembered card's sighting instead of reading "Not seen yet".
  • settle_connect_outcome's four remove_kind calls became clear_connect_slot, which quiesces the lens first when it sits on that kind. remove_kind alone dropped the lens id but left the mirror dressed.

Three tests where there were zero before: panes_never_render_without_a_lens_card (Booting / BlankFlash / Bootloader / ForeignFirmware / Gone + the sim lens), an_unplugged_lens_fades_to_an_offline_card_and_keeps_the_editor, a_soft_connect_ending_on_the_lens_kind_returns_to_the_gallery.

Phase 2 — the deletion (9b116ee)

~1750 lines out. The interesting part is the 16 device_section_target call sites, which split by what they narrate:

  • Six project-facing ones retarget to the PROJECT pane (UxActivityTarget::pane(ProjectController::NODE_ID) — the precedent refresh_project and sync_project_after_attach already use).
  • Ten device-link ones are removed. The card derives that narration itself (ConnectFlowStategallery_connect_evidence, session.operation_label(), and the card-owned op flow), so the pane emissions were a parallel copy that landed nowhere whenever the gallery was showing. management_event_sink loses its UiActivityView mirror to match; run_device_management now publishes a fresh view before the long manage await so the card overlay is up.

Tests were rewritten, not dropped — the M6 ladder ending, the incompatible and no-firmware escalations, and the pane inventory now assert on the lens card.

⚠️ One capability actually goes away

DeviceOp::DisconnectDevice loses its only UI entry point (the pane's Disconnect button). The op, its handler, and its e2e coverage all stay; the card has no disconnect verb. It was on the verified delete inventory, but flagging it explicitly since it's a real behavior change — say the word and I'll add a card affordance in a follow-up.

Erase is not affected: the card's Danger tab dispatches DeployOp::EraseDevice, which runs the same reset_to_blank the pane's "Erase device" did.

Decided explicitly, as asked:

  • UiTerminalLine / TerminalOutput kept. They hang off UiActivityView (a KEEP surface), still render there, and still have story coverage. Nothing in production populates the field — that's its own cleanup, not this PR's. The two zero-caller mutators (push_terminal_line, retain_recent_terminal_lines) are gone.
  • UiViewContent::Empty deleted. Its only constructor was UiStepView::new.

Validation

just check and just test green locally (664 lpa-studio-core tests); story bundle builds.

Baselines: 54 committed PNGs deleted, ~30 expected to rebaseline. Nothing was captured locally — validate-stories auto-commits to this branch per docs/adr/2026-07-26-ci-story-auto-commit.md.

Docs

ADR 2026-07-05-studio-pane-grammar (device pane as the grammar's "intended third consumer" + follow-up (a)) superseded; 2026-06-22-studio-device-ux-workflow marked superseded; web src/README.md updated; defect closed and registry row added with a new retired-surface-still-reachable class.

🤖 Generated with Claude Code

Yona-Appletree and others added 4 commits July 28, 2026 02:02
…ing quiesces

The editor's right column has exactly one device surface (D43), but
`lens_device_card()` returned `None` the moment the lens device reported
`DeviceState::Gone` — the gallery's Offline filter fired at lens scale
too. Nothing resets the project on device-gone, so the project stayed
`Ready`, panes kept rendering, and the shell fell through to the RETIRED
step-stack device pane. Stable state, not a transient.

- `device_card_from_live_evidence` is the unfiltered derivation and is
  total; `live_device_card` keeps the Offline filter for the gallery
  roster only (there the registry card is better informed). The lens card
  now fades to "Seen …/Reconnect" instead of vanishing — the lens and the
  project are untouched, so a flaky cable never yanks anyone out of their
  editor.
- Live evidence carries no registry entry, so the offline lens borrows the
  remembered card's sighting rather than reading "Not seen yet".
- `settle_connect_outcome`'s four `remove_kind` calls now quiesce the lens
  first when it sits on that kind. `remove_kind` alone dropped the lens id
  but left the mirror dressed: project `Ready`, panes up, no lens card.

Pins the invariant that had ZERO coverage and made this invisible: panes
non-empty => `view.lens_card.is_some()`, held across Booting / BlankFlash
/ Bootloader / ForeignFirmware / Gone and the sim lens.

Refs docs/defects/2026-07-28-retired-device-pane-still-reachable.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
D43 made the grown device CARD the editor's device surface; with the
device-gone hole closed the pane has no reachable path left. This removes
it, the DTOs it alone used, and its stories/baselines.

Core: DeviceController::view + status/disconnected/connected/firmware
section helpers and the DeviceRuntimeEvidence they read; steps_view.rs
(UiStepsView/UiStepView/UiStepState); UiViewContent::Stack and ::Empty
(the latter's only constructor was UiStepView::new); the apply_activity
StackSection branch and the UxActivityTarget::StackSection variant;
body_actions' stack recursion; the exports.

Web: core/view/stack_view.rs, src/app/device/, the shell's group_panes
split (it existed only to peel the device pane out of the pane list), and
the device story fixtures.

The 16 device_section_target call sites split by what they narrate:

- Six project-facing ones (Opening/Connecting project, Checking running
  projects, Loading demo project) retarget to the PROJECT pane, which is
  where that work is visible and already the target of refresh_project /
  sync_project_after_attach.
- Ten device-link ones are removed. The card derives that narration
  itself — ConnectFlowState via gallery_connect_evidence,
  session.operation_label(), and the card-owned op flow — so the pane
  emissions were a parallel copy that landed nowhere once the gallery was
  showing. management_event_sink loses its UiActivityView mirror
  accordingly; run_device_management now publishes a fresh view before
  the long manage await so the card overlay is up.

Tests rewritten, not deleted: the ladder's soft ending, the incompatible
and no-firmware escalations, and the pane inventory now assert on the
lens CARD and on "project + bus panes, device card". ADRs
2026-07-05-studio-pane-grammar (device pane as "intended third consumer")
and 2026-06-22-studio-device-ux-workflow are marked superseded.

BREAKING (UI): DeviceOp::DisconnectDevice loses its only entry point —
the pane's Disconnect button. The op, handler, and e2e coverage stay; the
card has no disconnect verb yet. Erase is unaffected: the card's Danger
tab dispatches DeployOp::EraseDevice, which runs the same reset_to_blank.

54 baselines deleted; ~30 rebaseline in CI (validate-stories auto-commits
per docs/adr/2026-07-26-ci-story-auto-commit.md — nothing captured
locally). Closes docs/defects/2026-07-28-retired-device-pane-still-reachable.md

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Deleting the shell stories took `studio/layout/studio-shell/simulator-idle`
with them — and that was DEFAULT_STORY_ID. `StoryBook` `.expect()`ed it,
so the storybook rendered an empty body and the capture pipeline reported
"No story links were discovered from the storybook page": a stale constant
surfacing three layers away from its cause, with no console error.

- DEFAULT_STORY_ID → `studio/home/home-gallery/populated`.
- `StoryBook` falls back to the FIRST registered story when the default
  is unknown, so a stale default degrades to "wrong story" rather than
  "no page at all".
- build.rs fails the build when DEFAULT_STORY_ID names no registered
  story, and says why. Verified it fires on the stale value.

Capture discovers 333 stories again (351 before, minus the 18 retired).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

CI refreshed the story baselines on this branch

The validate-stories job detected drift and committed the fresh set: 1 changed
in b2a956c.

Review every PNG in the PR's Files changed view (swipe / onion-skin).
Your local branch is now behind — git pull before pushing again.

Story Before After
base__code-editor__overview__sm.png base__code-editor__overview__sm.png@42eb26b544 base__code-editor__overview__sm.png@b2a956c372

Yona-Appletree and others added 6 commits July 28, 2026 08:24
…pane-2242af

# Conflicts:
#	docs/defects/2026-07-28-retired-device-pane-still-reachable.md
#	docs/defects/README.md
#	lp-app/lpa-studio-web/story-images/studio__readme__studio-hero__lg.png
#	lp-app/lpa-studio-web/story-images/studio__readme__studio-hero__md.png
#	lp-app/lpa-studio-web/story-images/studio__readme__studio-hero__sm.png
…pane-2242af

# Conflicts:
#	lp-app/lpa-studio-core/src/app/device/device_event_adapter.rs
#	lp-app/lpa-studio-core/src/app/studio/studio_controller.rs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant