2026 02 22_workbench_tab_semantics_overlay_and_promotion_plan - mark-ik/graphshell GitHub Wiki
Date: 2026-02-22
Status: Closed / Archived 2026-04-02 โ retained as implementation history; canonical semantic-tab authority now lives in ../../../../../graphshell_docs/implementation_strategy/graph/multi_view_pane_spec.md ยง7
Archived on: 2026-04-02
Reason: Stage 8 rollout landed in runtime code; active authority remains with the semantic contract and persisted format specs, not this execution note
Canonical authority chain:
-
../../../../../graphshell_docs/implementation_strategy/graph/multi_view_pane_spec.md ยง7โ canonical contract forFrameTabSemantics, hoist/unhoist, pane-rest semantics, and simplify-safe invariants -
../../../../../graphshell_docs/implementation_strategy/workbench/2026-03-03_pane_opening_mode_and_simplification_suppressed_plan.mdโ canonical authority forPaneOpeningMode,SimplificationSuppressed, and graph-enrollment promotion semantics -
../../../../../graphshell_docs/implementation_strategy/workbench/pane_chrome_and_promotion_spec.mdโ pane chrome and opening semantics cross-reference only; not the canonical owner ofFrameTabSemantics
Relates to:
-
../../../../checkpoint_2026-02-22/2026-02-22_workbench_workspace_manifest_persistence_plan.mdโ completed manifest migration foundation (archived 2026-02-24);PaneIdandFrameManifesttypes defined there, plus frame membership/routing context lineage -
../../../../../graphshell_docs/implementation_strategy/workbench/frame_persistence_format_spec.mdโ canonical current persisted frame-bundle shape, including the optional additiveframe_tab_semanticsfield -
../../../../../graphshell_docs/implementation_strategy/system/register/workbench_surface_registry_spec.mdโWorkbenchSurfaceRegistryowns layout/interaction policy for tile containers, including simplification options; overlay restore/collapse logic must read those options (the former2026-02-22_registry_layer_plan.mdPhase 3 is now canonicalized here) -
../../../../../graphshell_docs/implementation_strategy/system/2026-03-06_foundational_reset_graphbrowserapp_field_ownership_map.mdโ currentGraphWorkspace/AppServicesfield-ownership status;FrameTabSemanticstarget home after state-ownership migration
This note is retained as the historical execution record for the FrameTabSemantics rollout.
Do not treat it as the canonical active implementation guide; use the active contract and
format specs listed above for ongoing work.
The target remains the same:
- preserve semantic tab membership through structural normalization such as
simplify() - allow pane-rest states to retain tab-aware meaning
- restore tab containers on demand without conflating hoist/unhoist with graph-enrollment promotion
Current reality:
- runtime code now contains a persisted
FrameTabSemanticscarrier on saved frame bundles - save/load paths now derive, validate, and repair semantic tab metadata as frame state
- explicit
RepairFrameTabSemanticsintent plumbing now exists via runtime lifecycle bridge -> app command -> frame persistence repair/resave path - repair paths now emit typed
FrameTabSemanticsRepairReportdata plus one aggregated warning summary per load/restore/repair operation by default - omnibar saved-frame and live local-tab discovery now use overlay-first semantic helper paths
- live workbench tab-aware queries now flow through a dedicated
desktop/workbench/semantic_tabs.rshelper surface, whiletile_groupingremains structural-only fallback/reconciliation logic - restore-time frame loading can now rewrap pane-rest bundles back into visual tabs when saved semantic metadata provides the missing group members
- runtime code now contains reducer-owned
RestorePaneToSemanticTabGroup/CollapseSemanticTabGroupToPaneRestintent carriers, workbench-surface application, and runtime-resident semantic overlay state for the active frame - live collapse-to-pane-rest state now persists through named-frame bundle saves instead of being lost when saving from a structurally collapsed tree
- workbench host pane rows now expose
Tabs/Restaffordances for pane-rest restore and live collapse, backed by the shared semantic-tab query helper - keyboard command wiring now exists through
InputRegistryfor toggling the focused pane between pane-rest and semantic-tab-group form - live tab-range selection order now consults the active semantic overlay before falling back to visual tree order
- post-render drag/drop reconciliation now resynchronizes the touched runtime semantic tab groups after structural tab edits while preserving unrelated collapsed pane-rest groups
- restore/collapse completion now requires explicit post-transition runtime confirmation of the intended semantic tab state
- the concept remains intended architecture and is still referenced by active graph/workbench docs
-
Visual tabs: current
egui_tiles::Container::Tabsshape in the live workbench tree - Semantic tabs: Graphshell tab/group meaning persisted in overlay metadata
-
Pane rest state: a valid pane-only representation of a semantic tab/group after collapse or
simplify() - Hoist / Unhoist: structural workbench tree transforms only (egui_tiles operations)
- Restore Tabs / Collapse to Pane Rest: semantic + structural lifecycle actions in this plan that may trigger hoist/unhoist
-
PaneId: stable pane identity from the manifest-backed frame bundle model (defined in
2026-02-22_workbench_workspace_manifest_persistence_plan.md)
Terminology guardrail:
- Promotion remains reserved for graph-enrollment / graph-citizenship semantics elsewhere in Graphshell and is intentionally not used as the canonical lifecycle term in this plan.
Resolved semantics:
- A semantic tab is any tab/tab-group with saved overlay metadata.
- A single pane with overlay metadata counts for all tab-aware features even when currently unhoisted.
- Graph panes and webview panes are both eligible for semantic tab/group membership.
- A pane belongs to at most one semantic tab group at a time.
- The
egui_tilesworkbench tree is structural state, not semantic truth. - Semantic metadata is optional and additive.
- Restore prioritizes content availability first, semantic exactness second, exact structural shape third.
- Restore/collapse transitions between pane and tab-container forms are first-class behavior, not an exception path.
- Graphshell remains compatible with dependency-native transforms (
simplify()) by persisting semantics explicitly instead of relying on incidental tree shape.
The WorkbenchSurfaceRegistry layout policy section (see ../system/register/workbench_surface_registry_spec.md) owns simplification options and tab container rules. When egui_tiles::simplify() runs, it should consult the registry's SimplificationOptions rather than using hardcoded defaults. The overlay's restore/collapse operations must remain consistent with whatever simplification policy is active.
FrameTabSemantics is pure data and belongs in GraphWorkspace. Until the state-ownership migration in ../system/2026-03-06_foundational_reset_graphbrowserapp_field_ownership_map.md is complete, it lives alongside the frame manifest. The overlay must not depend on runtime handles (AppServices fields) โ it is serializable state only.
- UI/render code captures events only; it must not directly mutate overlay semantics.
- The reducer / app layer is the authority for semantic decisions (restore/collapse intents, repair policy, warning creation).
- The desktop/workbench apply layer mutates tree/runtime state in response to reducer-owned intents.
- Restore/collapse actions are explicit
GraphIntentvariants, not ad hoc tree rewrites at UI callsites.
Minimum planned shape; use Uuid for all IDs to be consistent with the codebase identity model.
pub type TabGroupId = Uuid;
pub struct FrameTabSemantics {
pub version: u32, // schema version for rkyv migration
pub tab_groups: Vec<TabGroupMetadata>,
}
pub struct TabGroupMetadata {
pub group_id: TabGroupId,
pub pane_ids: Vec<PaneId>, // ordered tab membership
pub active_pane_id: Option<PaneId>, // must be a member or repaired to None
}Planned persistence target: serialized with rkyv and stored in the frame bundle as additive frame
state. This is frame state, not graph WAL data โ it must not appear in fjall LogEntry variants.
Optional future additions (schema-additive, not breaking):
- Group-level UI metadata: label, color, collapsed/rest preference
- Pane-level metadata: title override, pin state
- Timestamps:
last_restored_at,last_collapsed_at - Diagnostics:
last_repair_at,last_repair_reason
| Layer | Type | Contents |
|---|---|---|
| Manifest layout | FrameLayout |
Structural egui_tiles tree |
| Manifest identity | FrameManifest |
Pane identity and node membership |
| Semantic overlay | FrameTabSemantics |
Tab group order, active pane |
These three must not overlap. The overlay queries shape only as a fallback when overlay metadata is absent.
For all tab-aware behavior (omnibar saved tabs, pin UI, tab affordances):
- Semantic overlay metadata
- Live workbench tree shape inference
- Pane-only fallback behavior
Implement through shared helper APIs โ not per-feature ad hoc logic.
Landed helper surface:
fn semantic_tab_groups_for_frame(semantics: &FrameTabSemantics) -> &[TabGroupMetadata];
fn saved_tab_nodes_for_frame(semantics: Option<&FrameTabSemantics>, tree: &Tree<TileKind>) -> Vec<NodeKey>;
fn pane_semantic_tab_state(pane_id: PaneId, semantics: Option<&FrameTabSemantics>) -> PaneSemanticState;The exact helper names evolved with the current module layout, but the work is now consolidated under the dedicated desktop/workbench/semantic_tabs.rs query surface. Structural post-render reconciliation remains in tile_grouping on purpose and is not treated as a user-facing semantic-query consumer.
- Persist/refresh overlay metadata before structural change.
- Allow tabs container to be simplified/unhoisted into pane rest state.
- Preserve content visibility (last paint / thumbnail fallback when runtime content suspends).
- Keep pane fully usable while tab chrome is hidden.
- Re-wrap pane into tabs container (egui_tiles structural operation).
- Reload/reapply overlay metadata: group membership, order, active pane.
- Restore normal tab interactions and affordances.
Ordering invariant (must not be violated):
- Semantic decision โ
GraphIntentapplied by reducer - Workbench tree mutation โ desktop layer applies structural rewrap
- Lifecycle/runtime dispatch โ resume/suspend webviews as needed
- UI readiness update โ on runtime confirmation
Both restore and collapse operations must be idempotent. Pane rest state is a valid intermediate state while runtime content is suspended or resuming.
GraphIntent::RestorePaneToSemanticTabGroup {
pane_id: PaneId,
group_id: TabGroupId, // existing group to rejoin, or new
}
GraphIntent::CollapseSemanticTabGroupToPaneRest {
group_id: TabGroupId,
}
GraphIntent::RepairFrameTabSemantics {
frame_name: String,
}These intent variants now exist in runtime code as reducer-owned carriers for the live restore/collapse path.
The desktop apply layer handles tree rewrites, lifecycle dispatch, and UI state updates in response to these intents.
When a semantic tab group has been collapsed to pane rest state, expose a small inverted-tab control:
- Anchored near the pane viewport margin (upper-left, configurable via
WorkbenchSurfaceRegistryinteraction policy). - Hidden by default; revealed when cursor approaches the tab region.
- Click dispatches
RestorePaneToSemanticTabGroupintent. - Keyboard-accessible equivalent command must exist (not mouse-only); registered in
InputRegistry.
- Every
pane_idin overlay metadata exists in the frame manifest. - No pane belongs to more than one semantic tab group at once.
-
active_pane_idis eitherNoneor a member of the same group. - Group
pane_idsordering is deterministic and free of duplicates.
- Auto-repair invalid metadata when safe.
- Preserve visible panes even if some semantic metadata must be dropped or corrected.
- Reapply remaining valid semantics.
- Repair must not depend on runtime webview availability.
- Dispatch
RepairFrameTabSemanticsintent; reducer applies repair; desktop layer updates UI.
- Aggregate all repairs per frame restore/load operation.
- Emit detailed repair events to debug logs.
- Emit at most one user-facing warning per restore/load by default.
- Warning text must include: frame name, affected group/pane IDs, exact repair action, what was preserved, what changed.
Example: Frame 'research-1': repaired tab group g42 (missing active pane p9). Preserved panes [p3,p7]; active tab reset to p3.
Stage 8A (design lock) is complete as documentation only. Stages 8B-8D are now complete in the current runtime slice; Stage 8E remains implementation work.
Status: Complete
Goal: persist optional tab semantics metadata in the frame bundle and validate/repair it on load.
- Extend bundle schema with optional
FrameTabSemanticsfield (landed). - Implement validation helpers: check each invariant in order, collect all violations before repairing (initial load-time repair landed for persisted bundle invariants).
- Implement repair helpers: drop/correct invalid entries; preserve valid entries; return repair log (typed repair reports now landed; explicit repair command path lands repair + resave for named frames).
- Implement
RepairFrameTabSemanticsintent handling in reducer (intent carrier landed through runtime lifecycle bridge and app command path; reducer-owned graph-delta semantics are still not needed here). - Add roundtrip tests: bundle with overlay, bundle without overlay, bundle with invalid overlay (initial save/load and repair coverage landed).
- Add repair invariant tests: duplicate pane, invalid active pane, missing pane (landed).
- Aggregate one warning summary per load/restore/repair operation by default while keeping per-repair detail in typed report data and debug logs (landed).
Done gate met for Stage 8B: persisted frame bundles now have additive semantic-tab state, validation/repair, explicit repair/resave plumbing, typed repair reports, and aggregated warning summaries.
Status: Complete
Goal: route all tab-aware features through shared semantic queries; eliminate direct tree-shape inference from consumers.
- Add overlay-first helper APIs in a current desktop/workbench semantic-query module
(landed via
desktop/workbench/semantic_tabs.rs, with persisted bundle helpers remaining inpersistence_opsand structural fallback/reconciliation remaining intile_grouping). - Update omnibar saved-tab discovery to use
saved_tab_nodes_for_frame()(landed via bundle-level semantic helper path). - Consolidate live tab-group ordering/membership queries onto shared helpers so omnibar, post-render grouping, and tab chrome stop duplicating node-tab membership rules (landed for the active user-facing tab-aware consumers).
- Keep
tile_groupingstructural-only for post-render reconciliation instead of treating it as the semantic-query owner (landed). - Preserve tree-shape fallback in the helpers during rollout; do not require overlay presence.
- No new direct tree-shape inference paths in migrated consumers.
Done gate met for Stage 8C: active tab-aware consumers now route through the shared overlay-first
semantic query surface, while structural tree-shape reconciliation remains isolated in
tile_grouping.
Status: Complete
Goal: implement semantic lifecycle transitions and on-demand rewrap affordance.
- Add
RestorePaneToSemanticTabGroup,CollapseSemanticTabGroupToPaneRestintent variants and reducer handling (landed). - Restore-time pane-rest rewrap from persisted
FrameTabSemanticsmetadata is landed for saved frame bundles, and live-runtime restore/collapse now routes through the same reducer -> workbench-surface boundary (landed). - Desktop apply layer: implement tree rewrap (hoist/unhoist), runtime lifecycle dispatch (resume/suspend), UI readiness update on confirmation (tree rewrap + idempotent semantic sequencing landed; explicit post-transition runtime confirmation now gates success for the current runtime path).
- Implement idempotency: applying restore/collapse twice has same effect as once (landed for the structural runtime path).
- Implement single-pane inverted-tab affordance in
desktop/ui/toolbar/or pane chrome render (current runtime slice landed in the workbench host pane rows asTabs/Restaffordances). - Register keyboard equivalent in
InputRegistry(landed as focused-pane semantic-tab toggle wiring). - Connect lifecycle ordering: restore waits for runtime confirmation before updating UI readiness (landed for the current workbench runtime path).
Done gate met for Stage 8D: live restore/collapse now has reducer-owned intents, structural rewrap, idempotent state transitions, keyboard/UI affordances, and explicit runtime confirmation before success is reported.
Status: Complete
Goal: allow egui_tiles::simplify() to run without losing Graphshell tab semantics.
- Define the structural simplify + semantic reapply pipeline:
- Run
simplify(). - Detect which pane IDs changed container membership.
- For each affected group in overlay, check if members still exist.
- If a group collapsed to a single pane, keep overlay metadata (pane rest state).
- If pane IDs were remapped by simplify (currently not the case with stable PaneId, but guard against it), update overlay membership accordingly.
- Run
- Post-render runtime reconciliation now treats simplify-driven tab-group membership drift like other structural tab edits, and preserves surviving single-pane groups as pane-rest semantic state instead of dropping the overlay outright (landed).
- Add cross-transform roundtrip tests:
save โ restore โ simplify โ reapply โ savepreserves overlay semantics (landed). - Document compatibility guarantees in this plan's Findings section once confirmed (landed).
Done gate: egui_tiles::simplify() no longer conflicts with Graphshell tab semantics. No pane loss
or tab metadata loss under supported transforms.
- Roundtrip tests with/without overlay metadata
- Repair invariant tests: duplicate pane, invalid active pane, missing pane
- Query precedence tests: overlay first, shape fallback, pane-only fallback
- Restore/collapse idempotency tests
- Simplify/reapply equivalence tests: semantic invariants preserved across simplify
- Warning aggregation tests: at most one user-facing warning per restore operation
- Lifecycle ordering tests: restore while runtime is suspended or resuming
Overlay becoming a second layout engine: keep overlay semantic-only (groups/order/active), not a
structural replacement. Clear ownership split with FrameLayout.
Feature code bypassing helpers: shared overlay-first query APIs are the only permitted path for tab-aware queries. Migrate high-risk consumers first (omnibar, pin UI).
Repair warnings creating user confusion: exact aggregated messages with content-preservation-first repair policy. Debug logs for detail.
Async races during restore/collapse: explicit intent ordering, idempotent operations, pane rest state as valid intermediate state.
WorkbenchSurfaceRegistry diverging from overlay assumptions: simplification options live in the
registry; overlay restore/collapse logic reads those options. If simplify policy changes, the
simplify-reapply pipeline (Stage 8E) must be re-validated.
This section absorbs and replaces the 2026-02-24 frame-routing polish plan.
- Emit structured resolver traces from
resolve_frame_open: candidates, recency scores, selected frame, and decision reason (MostRecent,ExplicitTarget,Fallback). - Surface traces through diagnostics/logging for headed validation and bug triage.
- Optional preference strategy remains constrained to resolver policy selection, not alternate UI-side routing logic.
- Badge tooltips should list memberships in recency order and highlight current frame.
- Frame-target actions in command palette should include membership hints.
- Hide badge noise for nodes that belong only to the current frame; keep stronger visual treatment for external membership.
- Route prune/retention operations through intent/request paths (
GraphIntent::PruneEmptyFrames,GraphIntent::RetentionSweep { max_snapshots }) rather than direct maintenance shortcuts. - Keep persistence effects in desktop helper layers, but preserve intent-layer observability.
- Multi-home open emits resolver trace with ranking and decision reason.
- Membership badges follow local-only vs external-membership visibility rules.
- Command palette frame-target entries expose membership hints.
- Batch prune/retention operations are visible in intent/request diagnostics.
- Compatibility confirmed for supported simplify-driven structural collapse: when a semantic tab group loses visual tab-container shape but retains one or more surviving panes, post-render reconciliation preserves the group as pane-rest semantic state instead of dropping it.
- Compatibility confirmed for persisted roundtrip coverage:
save -> simplify -> reapply -> save -> restorepreserves surviving semantic tab membership in saved bundles and restored runtime semantics.
- Plan created. Scope, design principles, and target model established.
- Stage 8A (design lock) declared complete.
- Aligned to registry layer:
WorkbenchSurfaceRegistry(Phase 3, complete) noted as owner of simplification options; overlay must be consistent with active simplification policy. -
TabGroupIdchanged fromu64toUuidfor consistency with the codebase identity model. -
GraphWorkspace/AppServicessplit (Phase 6) noted as future home ofFrameTabSemantics. - Persistence path made explicit: rkyv/redb frame bundle, not fjall WAL.
-
GraphIntentvariants made concrete with field signatures. - Stage 8A declared complete (design document is the output); stages 8Bโ8E are now the implementation work items with explicit done gates.
- Source-of-truth split table added.
-
WorkbenchSurfaceRegistryrisk added to Risks section. - Helper API surface and module location (
desktop/workbench_semantics.rs) made concrete.
- Retitled from the older overlay-and-promotion wording to keep
promotionreserved for graph enrollment only. - Status corrected:
FrameTabSemanticsis now partially implemented in runtime code, but the simplify-safe restore integration still remains planned work. - Canonical authority chain updated to point at
../../../../../graphshell_docs/implementation_strategy/graph/multi_view_pane_spec.mdfor the semantic contract. - Stale ownership wording replaced with current reducer/app-layer and desktop/workbench apply-layer language.
- Runtime gap closed for Stage 8D: restore/collapse now confirms the resulting semantic tab state before reporting success, while Stage 8E remains future work.
- Stage 8E completed: post-render reconciliation now treats simplify-driven structural tab collapse as semantic drift to repair, preserving surviving single-pane groups as pane-rest semantic state.
- Cross-transform regression coverage landed for
save -> simplify -> reapply -> save -> restoreso persisted bundles and restored runtime semantics keep the surviving semantic group intact. - Top-level status updated from in-progress rollout to complete execution note; the plan is now archive-ready.