diff --git a/Plans/2026-11-14-mobius/01a-workspace-prototype.md b/Plans/2026-11-14-mobius/01a-workspace-prototype.md index 0386b84ff..fd59e6bd0 100644 --- a/Plans/2026-11-14-mobius/01a-workspace-prototype.md +++ b/Plans/2026-11-14-mobius/01a-workspace-prototype.md @@ -1,37 +1,104 @@ # 01a — Workspace and remaining-work prototype -- Status: ready +- Status: executing +- Implementation issue: [STU-330](https://linear.app/kve/issue/STU-330/prototype-mobius-review-workspaces). - Depends on: None. - Ordering: Inserted before [01](01-review-state-foundation.md); the [overview](README.md#execution-order) owns execution order. - Shared context: [Overview](README.md). ## Deliverable and investigation -A lightweight interactive mockup for evaluating independent PR workspaces, file-top resumption, and remaining work across phone, tablet, and desktop layouts. The user selected a prototype before durable state work (Q-16), all three layouts together (Q-17), and a lightweight mockup for quick iteration (Q-18). +A lightweight interactive mockup for evaluating logical PR workspaces, their independent presentation as tabs or windows, multiple child views, review resumption, and remaining work across phone, tablet, and desktop layouts. The user selected a prototype before durable state work (Q-16), all three layouts together (Q-17), and a lightweight mockup for quick iteration (Q-18). Investigate whether the navigation and comparison labels make it clear which PR, file, version, and unfinished work the reviewer is seeing. The agreed behavior comes from Q-13–Q-15; layout and navigation details are hypotheses to evaluate, not final native UI decisions. -Bound the first pass to one self-contained browser artifact, two synthetic PR workspaces, two fixture revisions, three viewport layouts, and one feedback round. Record further iterations explicitly rather than expanding the prototype into a production implementation. +The first pass was bounded to one self-contained browser artifact, two synthetic PR workspaces, two fixture revisions, three viewport layouts, and one feedback round. That evaluation identified a material correction: a workspace had been flattened into a document tab group. Iteration 2 retained the same fixture and browser scope and added the ownership/presentation experiment below. Its evaluation requested substantially less stacked chrome. Iteration 3 preserved the corrected ownership model while testing compact controls. Its evaluation requested file-kind grouping, suitable comparison presentations, and explicit PR-scoped skipping. Iteration 4 retains the compact shell and existing scenarios while investigating those decisions with additional synthetic fixtures. None of these passes expands into native implementation or a complete window manager. ## User stories and requirements | Story | Requirement | Evidence from this prototype | | --- | --- | --- | -| US-01, US-04 | R-02, R-05 | Separate PR contexts; reference files and a fixture search remain with their PR. | -| US-02 | R-03 | Returning to a PR restores its last review file at the top. | +| US-01, US-04 | R-02, R-05 | Logical PR workspaces own independently navigable child views; outer tab/window presentation and close/reopen do not copy, merge, or discard their retained contents. | +| US-02 | R-03 | Restore the workspace arrangement and last-focused child. Resuming a review child starts its own selected file at the top. | | US-03 | R-04 | Reviewed files show new edits; unreviewed files show the full PR diff; either can open its full PR diff. | +| US-09, US-10 | R-13, R-14 | Group kinds and evaluate content-specific comparisons with raw fallbacks; separate PR-local skip receipts from review history and resurface changed/new work. | | US-06 | R-01, R-10 | The same interaction is inspectable at phone, tablet, and desktop viewport sizes. This is not native platform acceptance. | The prototype supplies interaction evidence for these requirements; it does not complete their production acceptance. R-06/R-07 and the rest of the release requirements remain in later plans. ## Scope and artifacts -Proposed artifact: `Plans/2026-11-14-mobius/Prototype/index.html`, with embedded styles, scripts, and synthetic fixtures. Use semantic browser controls and no external dependencies or network data. Store the interaction evidence and feedback in this plan's execution record. Read the repository and Plans contracts before implementation. +Current authoring artifact: an Astro route in `Prototype/src/pages/index.astro`, with local browser script, global stylesheet, and synthetic fixtures. Reuse the repository’s pinned development dependencies; the mockup itself makes no account or data requests. The prior standalone artifact is retained unchanged as `Prototype/pre-astro.html`. Store the interaction evidence and feedback in this plan's execution record. Read the repository and Plans contracts before implementation. -Keep session state in memory so fixture behavior is reproducible through an explicit Reset action. Workspace switching within the mockup preserves each PR's documents, last file, draft fixture, and review state. Reload durability, CloudKit, authentication, native menus/windows, a real Git engine, real search indexing, and live GitHub feedback are outside this artifact. Those exclusions do not alter first-release scope. +Keep session state in memory so fixture behavior is reproducible through an explicit Reset action. Workspace switching and close/reopen preserve each PR's child views, their independent navigation and arrangement, the last-focused child, draft fixture, and shared review/skip progress. Closing removes presentation from the current session; it neither deletes the retained workspace nor closes the GitHub PR. Reload durability, CloudKit, authentication, native menus/windows, a real Git engine, real search indexing, and live GitHub feedback are outside this artifact. Those exclusions do not alter first-release scope. The artifact must identify itself as a mockup using sample data. Do not copy its state schema into production automatically; 01 must derive its model from evaluated behavior and repository contracts. +## Iteration 2 decisions and bounded method + +User feedback and Q-19–Q-21 were supplied through the parent planning conversation on 2026-11-14: + +- Q-19: “fork” was a typo for “view.” No editing, cloning, or fork capability is requested. Child views may display existing code, research, reviews, previews, and simulations. +- Q-20: “All of the above if needed” delegates bounded layout exploration. Floating, tiling, docking, and tabs may be used where useful; this is not a requirement to implement every mode on every native platform. +- Q-21: Return restores the workspace arrangement and last-focused child. A non-review child keeps focus. Resuming a review child starts that child's selected file at the top; there is no singleton workspace-wide selected review file. + +Proposed prototype structure, not a production schema: + +| Owner | Session-only responsibility | +| --- | --- | +| Mockup shell | Outer workspace tab/window presentation and active workspace identity. | +| Logical PR workspace | Fixture revision, per-file reviewed versions, draft, per-file skip receipts, child collection, arrangement, and last-focused child. | +| Child view instance | Unique instance identity, kind, selected file/comparison or search query or simulated-preview state, and placement. Multiple children can have the same kind or file. | + +Use tiled children as an exploratory wide-screen default, a bounded freeform move/resize arrangement, and a focus-one-child presentation with a child selector for compact screens. Outer workspace windows remain simulated browser shells. Treat defaults and labels as evaluation hypotheses, not native platform commitments. Showing the same workspace through a different outer presentation must not create another logical workspace or reset its children. + +A New View action can create Review, Source, Search, or Preview children. Review selection and comparison mode belong to each review child; marking reviewed updates the workspace's shared PR/file baseline and all affected child displays. A preview contains explicitly simulated, interactive sample content sufficient to evaluate placement and continuity. It neither executes code nor establishes native preview/simulator feasibility. Native execution remains a later experiment. + +Bound iteration 2 to those four child kinds, the existing two PRs/two revisions, useful arrangement controls, the same three viewport categories, and one further user evaluation. No editing/forking, backend, new account integration, actual OS windows, native execution, or production durability is added. + +## Iteration 3 compact-chrome method + +The user evaluated iteration 2 and approved the compact-chrome proposal (“SGTM”), explicitly requesting another background rebuild on 2026-11-14. This revises presentation, not the Q-19–Q-21 ownership or review rules. Retain iteration-2 artifact revision `e1c1059cf28` and its separate evidence; record new evidence under `Prototype/evidence/iteration-03/`. + +The investigation is whether more of the default viewport can show the actual review, source, research, or preview while all existing capabilities stay understandable and reachable: + +- Keep concise workspace identity (short name/PR number), the active child/file title, truthful current comparison, and immediate review actions visible. Combine workspace heading and tools into a compact row. On compact screens, the child selector can supply the active view title instead of repeating a title bar. +- Replace stacked comparison/file/context bands with a compact view toolbar. A full PR diff must still say **Full PR diff**, including an unreviewed file in Remaining; a reviewed file's new edits must identify its last-reviewed version. Keep file navigation and full/remaining selection reachable without advancing baselines. +- Remove permanent teaching copy and repeated kind/ordinal labels when the title and icon suffice. Preserve accessible names that distinguish same-kind child instances. Full PR metadata, progress detail, outer presentation, and arrangement choices may move into accessible details/menus with predictable focus and dismissal. +- Move Canvas, Reset, and Simulate push into a collapsible prototype-controls panel. Keep a small sample-data indicator and an honest simulated-preview indicator; no real execution is implied. +- Keep readable typography and usable pointer/touch/keyboard targets. The experiment reduces the number of bands and repeated content rather than shrinking labels and controls. Defaults remain exploratory native-layout hypotheses. + +Bound the pass to the existing two PRs/two revisions/four child kinds and state model. Retain multiple views, independent navigation, shared review progress, drafts, add/close/recovery, outer tabs/windows, arrangements, search, simulated preview state, and file-top review resumption. No native, backend, persistence, account, editing/forking, or real execution work is added. + +Before/after evidence uses identical viewports and fixture states, including a review at the initial full comparison and a post-push incremental comparison. Record the content viewport's top position and usable height at phone, tablet, and desktop sizes, plus representative visually inspected captures. Exercise newly disclosed controls by keyboard and pointer, Escape/focus return, and navigation from the compact selector. Repeat the complete previous regression scenario against the final source, since moving controls can affect focus and reachability despite retaining the state model. + +## Iteration 4 file kinds and explicit skip method + +The user requested differentiated diffs/listing for localization, Git LFS files, Markdown, and code. Q-22–Q-24, resolved through the parent conversation on 2026-11-14, establish grouping with quieter kinds collapsed, explicit **Skip for this PR** separate from reviewed state, and resurfacing when a skipped file changes. This pass preserves the compact information hierarchy accepted for iteration 3. Shared requirements R-13 (kind grouping/presentations/fallbacks) and R-14 (PR-local skip/undo/resurfacing) are owned by the parent overview; this file owns the bounded browser method. + +Use the existing two PRs and two prepared revisions. Extend each PR from three code files to the following seven files at v1 and eight at v2; source navigation/search also retain the supporting `Reference.swift` fixture. + +| Group | Fixture | Prepared comparison and v2 behavior | +| --- | --- | --- | +| Code | `Parser.swift`, `Store.swift`, `Stable.swift` | Preserve original line diffs and remaining-work scenario. Parser/Store change at v2; Stable stays unchanged. | +| Documents | `README.md` | Rendered Markdown before/after with source-diff access. A v2 link-target-only edit must remain identifiable even if rendered prose looks the same. | +| Localization | `Localizable.xcstrings` | Changed key/locale/value rows with raw source-diff access. v2 changes a translation and adds a locale; receipts stay file-level. | +| Snapshots/assets | `SearchResults.svg` | Embedded synthetic before/after images, metadata, and SVG source. Mark with an LFS attribute/badge; v2 changes the image. | +| Snapshots/assets | `Design.psd` | Explicitly unavailable binary preview; prepared metadata and LFS pointer fallback. Its v1 PR change is unchanged at v2. Never display a fabricated clean comparison. | +| Snapshots/assets | `EmptyResults.svg` | New file at v2, with explicit absent-before state, synthetic image, metadata, and source. This was not a member of any v1 group-skip snapshot. | + +These are candidate presentations, not native renderers or format parsers. All before/current/rendered/source/pointer data is deterministic and bundled. LFS is an attribute across content types, never a separate content group. No Git/LFS downloads, real parsing, network integration, additional account data, executable previews, or per-key review receipts are added. + +The existing file chooser becomes a grouped list. Code starts open; Documents, Localization, and Snapshots/assets start collapsed. Collapsed headers retain visible remaining/reviewed/skipped counts and explicit group actions. Per-child expansion and rendered/source selection are navigation state. They never advance a review baseline or skip a file. File-review actions retain their underlying PR/file/revision owner; the existing private draft remains PR-scoped. No per-key or fabricated submission anchors are added. + +Skip receipts are separate from review receipts. Individual skip applies only to a currently remaining file. A skip records only that PR/file's current prepared content version; **Skip remaining files** snapshots only currently remaining files present in the group when invoked. It does not configure a category exclusion or affect another PR. Current-file and group undo remove skip receipts without modifying actual review history. A content change invalidates the active skip and returns the file to Remaining; an unchanged skip persists. A new file has no skip receipt. Resurfaced reviewed files still compare from their last actually reviewed version; resurfaced unreviewed files show the full PR diff. + +Count/action policy was reconciled with the parent on 2026-11-14: remaining, currently reviewed, and actively skipped are distinct mutually exclusive dispositions. Already-current reviewed files are not eligible for individual/group skip. A now-changed remaining file may have an older reviewed receipt, which skipping preserves. Undo restores remaining unless actual review independently made it current. Explicit Mark reviewed can clear an active skip only when the actual comparison/content is available and the user deliberately invokes it. Missing binary bytes cannot be marked reviewed through a fabricated preview. Group undo applies to currently active skips in that group; neither group action creates a future category rule. + +Keep the selected file understandable when marking/skipping updates the chooser. A skipped selected file remains reachable with its status and Undo; full context/source remain accessible. When nothing remains but skips exist, say no remaining work and report skipped files separately, never all reviewed. Preview fallback names missing/unsupported content and exposes the raw source, pointer, or metadata that actually exists. Rendered Markdown must not conceal source-level details such as changed link targets or formatting. + +Bound effort to these groups/fixtures, existing four child kinds, the original interaction matrix, and one further evaluation. Retain [iteration 3's published artifact](https://github.com/kyleve/Stuff/blob/58c13ac56f87688548887172fef6f39e818bc819/Plans/2026-11-14-mobius/Prototype/index.html) as a byte-identical runnable archive and leave prior evidence untouched. Store separate captures, exact-source checks, and evaluation in `Prototype/evidence/iteration-04/`. + ## Scenario and state flow Use synthetic PR 42 and PR 43. Each has a distinct workspace even if they share a file path. An optional stack-connection label links the PRs without combining their state. @@ -41,42 +108,59 @@ Within PR 42, version 1 includes `Parser.swift`, `Store.swift`, and `Stable.swif - Remaining work shows Parser's new edits since its last reviewed version and Store's full current PR diff. Stable has no new work and remains reachable through the full PR view. - Opening the full PR diff for Parser shows its complete current PR change. Changing views does not advance a reviewed version. - Marking Parser reviewed at version 2 advances only Parser's baseline. Keep the visible file understandable while updating the remaining-work list; the precise transition is part of the evaluation. -- Open a fixture reference file and search in PR 42, switch to PR 43, then return. Restore PR 42's context and open its last review file at the top. A reference document is not a new review workspace. +- Open multiple child views in PR 42, including two review views with different selected files, independent search views, and a simulated preview. Changing a child selection/query does not navigate a sibling. +- Change outer workspace presentation between tabs and windows. The child identities, contents, arrangement, progress, and focus remain owned by the same workspace. +- Switch from a focused research/preview child in PR 42 to PR 43, then return. Restore PR 42's arrangement and focused child. Separately resume a review child and verify its selected file opens at the top. +- Change the bounded arrangement, focus a child, and inspect compact/wide layouts. A child view is not a new workspace. Review progress remains shared within one PR and isolated from the other PR. ```mermaid flowchart LR - Fixtures["Synthetic PRs and prepared revision diffs"] --> Session["Proposed in-memory mockup session"] - Actions["Switch PR / file / comparison view"] --> Session - Mark["Explicit mark-file-reviewed action"] -->|that PR and file only| Session - Push["Simulate push"] -->|new fixture revision; retain reviewed versions| Session - Session --> Remaining["New edits or full diff for unreviewed file"] - Session --> Full["Full current PR diff"] - Remaining --> Layouts["Phone / tablet / desktop layouts"] - Full --> Layouts - Reset["Reset sample data"] --> Session + Shell["Proposed outer tabs or workspace windows"] -->|presents by identity| Workspace["Logical PR workspace"] + Workspace --> Progress["Shared per-file review baselines and draft"] + Workspace --> Skips["PR/file content-version skip receipts"] + Workspace --> Placement["Child arrangement and last-focused child"] + Workspace --> Children["Unique child view instances"] + Children --> Review["Review: selected file and comparison"] + Children --> Research["Source/search: independent navigation"] + Children --> Preview["Explicitly simulated preview state"] + Review -->|explicit mark only| Progress + Review -->|explicit file/group skip or undo| Skips + Fixtures -->|content change invalidates active skip| Skips + Fixtures["Two synthetic PRs and prepared revisions"] --> Workspace + Reset["Reset sample data"] --> Workspace ``` All components are proposed mockup state. Swift pseudocode does not apply to this browser artifact; the native ownership sketch remains provisional in the overview. Predefined fixture diffs simulate comparisons and do not verify a Git diff algorithm. ## Steps -1. **Build the scenario fixture.** Define two PR identities, independent document collections and last-file selections, per-file reviewed versions, and prepared full/incremental diffs for the two versions. Keep shared-path fixtures isolated by PR. Document the fixture states alongside the artifact. -2. **Create the interactive shell.** Add workspace switching, a review-file list, remaining-work/full-PR views, a full-diff action for the selected file, fixture reference/search navigation, explicit file-review actions, Simulate push, and Reset. Prototype suitable navigation for narrow, medium, and wide viewports using the same state. Treat layout and labels as candidates for feedback. -3. **Exercise the return visit.** Run the scenario above at recorded phone, tablet, and desktop viewport sizes. Confirm a resumed review file starts at the top and that another PR's state is unaffected. Check both mouse/pointer and keyboard operation; inspect narrow-layout touch-target usability. Record what was actually exercised rather than claiming native device validation. -4. **Collect evidence and feedback.** Deliver the artifact with the scenario and representative captures of the three layouts. Ask the user to try workspace switching and the post-push remaining-work view. Record confusing transitions, requested changes, and whether the workflow should proceed, change, or receive another prototype iteration. +1. **Preserve evaluated ownership and history.** Retain the earlier artifact/evidence at `2e3653877`, `e1c1059cf28`, and `58c13ac56`, with their evaluations. Keep PR/file review baselines workspace-owned and unique child instances independently navigable. Retain the prepared fixture revisions. +2. **Add grouped content and independent skip receipts.** Apply the iteration-4 method above while retaining compact workspace/view controls. Add the bounded kind fixtures, grouped chooser, explicit file/group skip/undo, content-version invalidation, truthful per-kind previews, and raw fallbacks. Preserve all earlier workspace, review, draft, navigation, and arrangement capabilities. +3. **Exercise the return visit.** Run the scenario above at recorded phone, tablet, and desktop viewport sizes. Confirm child navigation is independent, shared review progress updates sibling review views, outer presentation preserves ownership, workspace return preserves arrangement/focus, a resumed review child starts its selected file at the top, and another PR's state is unaffected. Check both mouse/pointer and keyboard operation; inspect narrow-layout touch-target usability. Record what was actually exercised rather than claiming native device validation. +4. **Collect evidence and feedback.** Deliver matched grouped-list/type-comparison captures at all three sizes, plus skip/undo/new-push evidence and compact-shell continuity. Ask the user to evaluate group discoverability, skip meaning/resurfacing, comparison usefulness/raw access, and retained workspace return behavior. Record confusing transitions, requested changes, and whether to proceed, change, or run another bounded iteration. 5. **Review and hand off.** Integrate supported feedback into the overview and affected outlines, retaining unresolved decisions. Review the changed artifact and plan through code-review, run relevant checks, then commit/push and publish through github-workflow. Do not refine the durable model until the required prototype feedback is recorded. -For local browser inspection, a loopback-only static server can serve the artifact, for example `python3 -m http.server 8765 --bind 127.0.0.1 --directory Plans/2026-11-14-mobius/Prototype`. Use an available port and stop the owned server after inspection. If browser automation is unavailable, record the missing runtime evidence; source inspection alone does not establish interactive acceptance. +For current browser authoring and inspection, use the [Astro commands](Prototype/README.md#run-the-demo) with LAN binding and automatic updates. The requested evaluation server stays running at handoff with an explicit owner and stop command; stop temporary verification servers. If browser automation is unavailable, record the missing runtime evidence; source inspection alone does not establish interactive acceptance. ## Acceptance and verification | Criterion | Check | Expected evidence | | --- | --- | --- | -| Workspaces stay independent. | Switch PR 42 → PR 43 → PR 42 after opening context and changing review state. | Each retains its own documents, last file, and reviewed versions; a stack link has no shared-state effect. | -| Resume starts at the file top. | Scroll within a review file, leave the PR, and return. | The same review file opens from the top. No reviewed-range state is inferred. | +| Logical ownership survives presentation. | Change outer tabs/windows with multiple children open in both PRs. | Same workspace and child identities, content, focus, arrangement, drafts, and progress. | +| Child navigation is independent. | Open two review or search children; change only one file/comparison/query. | Sibling state is unchanged. Marking reviewed is shared only among review children of that PR. | +| Workspaces stay independent. | Switch PR 42 → PR 43 → PR 42 after changing child and review state. | Each retains its children, arrangement, last focus, draft, and review baselines. | +| Return and review resumption are distinct. | Leave a focused research/preview child, return, then resume a previously scrolled review child. | Preserve non-review focus and arrangement on return; the review child opens its own selected file at the top when resumed. | | Remaining work follows the chosen model. | Mark Parser/Stable reviewed at version 1, leave Store unreviewed, then simulate version 2. | Parser shows new edits; Store shows its full PR diff; Stable has no remaining changes. | | Full context is accessible. | Open the full PR diff for both Parser and Store; switch views and PR workspaces. | Complete current PR diffs remain available and baselines change only through the explicit file-review action. | +| Simulated preview can be evaluated. | Change sample preview controls, switch children/PRs/presentation, and return. | State remains with its child and owner; simulated status is explicit and no code is executed. | | All three layouts can be evaluated. | Execute the scenario at recorded narrow, medium, and wide browser sizes. | Captures plus interaction notes identify each viewport and any usability failures. | +| Compact chrome improves content space. | Compare the same fixture and viewport before/after at all three sizes. | More usable content height without smaller text/targets; workspace, child/file, actual comparison, and immediate review action stay understandable. | +| Disclosed controls stay reachable. | Use metadata/arrangement, outer presentation, prototype controls, and compact child navigation by pointer and keyboard. | Every previous capability remains reachable; Escape/dismissal restores focus and leaves state unchanged unless an explicit action changes it. | +| Groups stay discoverable. | Inspect Code and collapsed quiet groups at all three sizes; expand/collapse independently in two children. | Kind/count/skip status is visible, child navigation is independent, and no receipts change from disclosure. | +| Skip is separate from reviewed. | Skip/undo a current file and group, including a now-changed file with a prior reviewed receipt; check that currently reviewed files are ineligible. | Only PR/file skip receipts change; actual review baselines remain unchanged, counts stay distinct, and undo restores the underlying disposition. | +| New work resurfaces. | Skip assets at v1, push v2 with one changed, one unchanged, and one new asset; repeat with reviewed Parser and unreviewed Store. | Changed/new files return to Remaining; unchanged Design skip persists. Parser compares from actual review; Store remains a full PR diff. | +| Type previews preserve comparison truth. | Compare rendered/source Markdown and localization plus image/metadata before/after under full and incremental modes. | Both representations use the same PR/file/baseline/current revision; link-only changes stay identifiable; receipts remain file-level. | +| Missing previews remain honest. | Open Design and new EmptyResults. | Unavailable binary bytes and absent-before content are explicit; only available pointer/source/metadata is shown, never a fabricated clean diff. | | The experiment produces a decision. | Review the artifact with the user. | Recorded feedback supports proceeding, revising, or another bounded iteration. A supported negative result is valid; pending feedback leaves the experiment incomplete. | Inspect the browser console for runtime errors and verify all artifact resources load locally. Use `git diff --check` and review local plan links after updates. No app test suite or snapshot baseline is implied by this browser mockup; use proportionate browser interaction checks. Do not claim iPhone/iPad/Catalyst runtime, VoiceOver, persistence, provider, or sync validation from viewport captures. @@ -87,17 +171,328 @@ Reset restores the known fixture; reload also starts a fresh session. Keep the p ## Progress and execution record -- [ ] Create fixture and interactive artifact. -- [ ] Exercise all three layouts and capture evidence. -- [ ] Collect and integrate user feedback. -- [ ] Review and publish the artifact and evaluation record. +### First pass + +- [x] Create fixture and interactive artifact. +- [x] Exercise all three layouts and capture evidence. +- [x] Collect first-pass feedback; material correction requires iteration 2. +- [x] Review and publish the artifact and evaluation record. + +Execution started on 2026-11-14 after the user requested the prototype in a background agent. Work is isolated in the `mobius-prototype` worktree on `codex/mobius-prototype`, initially based on `4e70677e7` and advanced to the `047706c26` planning checkpoint. PR #497 had no conversation, review, or inline comments when read at start. The implementation is tracked separately in STU-330; STU-329 remains the planning issue. + +### First-pass artifact and interaction evidence + +The first-pass artifact is preserved at [revision `2e3653877`](https://github.com/kyleve/Stuff/blob/2e3653877bf141964805d417eac0b94c03a24c6a/Plans/2026-11-14-mobius/Prototype/index.html), alongside the retained [first-pass verification record](Prototype/evidence/verification.json) and captures below. This describes first-pass behavior, not iteration 2 acceptance. All data is synthetic and session-only. Two PRs retain independent files, comparison modes, open source/search tabs, queries, drafts, and reviewed versions. Returning to a PR opens its last review file at the top. A marked file remains selected with a caught-up message; this transition is a hypothesis for feedback. + +Browser scenarios passed at the following viewports in Chromium 156.0.8078.4 through repository-pinned Playwright 1.64.1. Captures use light appearance and 1× device scale. + +| Viewport | Capture | Observed behavior | +| --- | --- | --- | +| 1440 × 1000 | [Desktop](Prototype/evidence/desktop.png) | Workspace rail, file list, retained source/search tabs, full PR context. | +| 834 × 1112 | [Tablet](Prototype/evidence/tablet.png) | Workspace picker, persistent file list, Parser's new edits since v1. | +| 390 × 844 | [Phone](Prototype/evidence/phone.png) | Workspace/file drawers, scrollable tabs, Store's full current PR diff; code scroll stays inside the document. | + +At every size, the scenario marked Parser and Stable at v1, left Store unreviewed, advanced PR 42 to v2, and verified Parser's incremental comparison, Store's full comparison, Stable's absence from remaining work, and access to full context. Comparison selection and refresh preserved baselines. Marking Parser at v2 changed only its baseline. Switching PRs retained independent drafts and context; returning restored the same review file at scroll offset zero. PR 43's own reviewed-Store → push comparison was also checked. Reset restored v1 and empty progress. + +Pointer interaction, phone touch taps, keyboard search, keyboard marking, and phone drawer comparison → Escape focus restoration passed. No page/console errors, failed resource loads, external requests, or document-level horizontal overflow occurred. `@axe-core/playwright` 4.14.0 WCAG 2/2.1 A/AA scans of the checked baseline, post-push, and saved-draft states reported no violations. Direct `file://` loading and marking a file also passed, so the artifact does not require a running server. + +These are browser interaction and automated accessibility observations. They do not establish native device, VoiceOver, real Git diff, persistence, provider, or sync acceptance. The repository's default web lint globs do not cover this HTML artifact. Inline JavaScript syntax and `git diff --check` were checked directly; local walkthrough links resolve. `./test`, native snapshots, and SwiftFormat were not run because no native source, build input, or Swift file changed. + +### Independent review + +A fresh subagent reviewed the complete artifact against parent `047706c26`, then rechecked supported corrections. The fixes preserve first-row characters/indentation in prepared diffs; apply PR-specific substitutions to both full and incremental comparisons; restore focus to a surviving control or the current document after rendering and modal dismissal; improve small-text contrast; and keep accessible names consistent with visible workspace, push, and saved-draft labels. No actionable findings remained after recheck. The verification record identifies the final artifact content; retained screenshots are design evidence, not SnapshotKit references. + +### Feedback and publication + +The user evaluated the first pass and found it flattened a logical workspace into a document tab group. That is a material correction, not acceptance of the first-pass workspace model. Q-19–Q-21 above resolve the revised method and authorize another bounded prototype pass. The native state foundation remains an outline. + +Published [PR #500](https://github.com/kyleve/Stuff/pull/500), ready for review, above planning [PR #497](https://github.com/kyleve/Stuff/pull/497) in [stack #501](https://github.com/kyleve/Stuff/stack/501). The branch merges parent `68477fe625`, which includes main `96f5bf0f1`; integration preserves the verified HTML content. The stack reports no rebase needed. STU-330 remains In Review and this experiment remains executing for user feedback. No product acceptance is claimed. + +The owned loopback server is stopped after inspection; the artifact opens directly from disk. Local CUA browser use is disabled in Work settings, so the published PR could not be visually inspected through that UI. Published description/image-link checks use GitHub API and direct image responses; the local captures themselves were visually inspected. + +## Iteration 2 readiness and execution + +- Status transition: `executing` → `draft` on 2026-11-14 after the material first-pass correction; the previous readiness review does not establish readiness for the revised UI. +- Source inspected: `2e3653877`; working tree was clean. Current PR #500 feedback contains only the previously posted screen-evidence comment; the new product feedback comes from the user conversation. +- Q-19–Q-21 are resolved above. Parent owns integration into shared requirements/overview and production outlines; this file owns the browser method and evidence. +- Readiness review, 2026-11-14: inspected the complete revised method against source `2e3653877`, Q-13–Q-21, the root/Plans contracts, and current PR feedback. The existing singleton `lastFile`, `query`, and kind-deduplicated tabs cannot represent the requested child instances. The revised owner table, state flow, steps, and acceptance checks consistently put selection/query/preview state on child instances and review progress on the PR workspace. Q-19 excludes editing/forking; Q-20 delegates bounded layout exploration; Q-21 separates workspace focus restoration from per-review-child file-top resumption. All material choices needed for this browser pass have answers or explicit delegation. Defaults remain exploratory; native/platform/execution exclusions are preserved. No readiness findings remain. Mermaid was source-reviewed, not renderer-validated. +- Readiness disposition: `draft` → `ready` after that review, then `ready` → `executing` under the user's explicit instruction to proceed with iteration 2. Implementation and second-round acceptance evidence were pending at that readiness checkpoint. + +- [x] Review the revised bounded method and record readiness. +- [x] Build independent workspace presentation and multiple child views. +- [x] Exercise both ownership layers and original review behavior across three sizes. +- [x] Record fresh independent review and second-iteration captures. +- [x] Publish the coordinated stack update. +- [x] Collect and integrate second-round user feedback: excessive stacked chrome prompted the approved iteration-3 method above. + +### Iteration 2 implementation and evidence + +The [iteration-2 artifact](Prototype/iteration-02.html) separates outer workspace presentation from owned child views. Review, Source, Research, and explicitly simulated Preview instances have unique IDs and independent navigation. Review baselines and the draft remain shared within one PR. Workspace return restores arrangement and last-focused identity; each resumed review starts its own selected file at the top. Tiled, bounded floating, and focused arrangements are exploratory defaults, with compact view selection retaining the wider arrangement. + +The first-pass [runnable archive](Prototype/iteration-01.html) exactly matches `2e3653877` and its existing evidence remains intact. New captures and [exact-source verification](Prototype/evidence/iteration-02/verification.json) are separate: + +| Viewport | Evidence | +| --- | --- | +| 1440 × 1000 | [Tiled child views](Prototype/evidence/iteration-02/desktop-tiles.png), [outer workspace windows](Prototype/evidence/iteration-02/desktop-windows.png). | +| 834 × 1112 | [Floating child views](Prototype/evidence/iteration-02/tablet-float.png). | +| 390 × 844 | [Restored preview focus](Prototype/evidence/iteration-02/phone-preview.png). | + +Complete three-size scenarios passed through Playwright 1.64.1 / Chromium 156.0.8078.4. They created multiple Review, Source, Research, and Preview instances; verified independent files/queries/sample states and shared PR progress; changed outer presentation without replacing identities; restored arrangement and non-review focus; resumed each review file at its top; and repeated the original per-file remaining/full-diff scenario. Closure checks preserve focus when a background child or an inactive workspace's child closes; closing the last child provides keyboard recovery through New view. Reset restores the initial fixture. + +Pointer and phone touch taps, keyboard search, and wide-layout pointer/keyboard movement and resizing passed. Checked initial, post-push/saved-draft, and reopened-empty-workspace states had zero axe WCAG 2/2.1 A/AA violations. No page/console errors, failed loads, external requests, or document-level horizontal overflow were observed. Direct file loading and mark-reviewed behavior passed. Final inline JavaScript syntax, local links, and diff whitespace were checked. Native tests and SwiftFormat remain outside this browser-only change; default repository web lint globs do not cover the HTML. + +Fresh independent review found and rechecked floating z-order, background/inactive-workspace closure, empty-workspace focus recovery, keyboard scrolling in the preview, and Enter submission. The search change handler was rerendering a text input's form before implicit submission; restricting it to its owned select controls fixes that trigger. Modal dismissal now completes synchronously, preventing queued close callbacks from rerendering or stealing focus after another interaction begins. A final compact-selector correction keeps the focused child visible, including after PR/presentation changes. No actionable review findings remain. These checks do not establish native, VoiceOver, actual execution, persistence, provider, or sync behavior. + +Parent coordination rebased the unchanged first-pass artifact/readiness record onto parent `fcee86b3b0` at child `46d284bbafa` before implementation. The revised artifact and evidence were committed at [`e1c1059cf28`](https://github.com/kyleve/Stuff/commit/e1c1059cf28a2954a0513d2514e7d0b7be9c34dd) and published through `gh stack push` to existing [PR #500](https://github.com/kyleve/Stuff/pull/500). Its description and [existing screen-evidence comment](https://github.com/kyleve/Stuff/pull/500#discussion_r4576427594) now describe iteration 2. GitHub-rendered HTML contains the expected images and captions; all four commit-pinned image responses match the local PNG bytes. Published-PR visual inspection remains unavailable because local CUA browser use is disabled. The owned loopback server is stopped; direct file loading remains usable. STU-330 stays In Review with current evidence. The next decision is the user's evaluation of this corrected workspace model, not readiness to implement native code. + +## Iteration 3 readiness and execution + +- Status transition: `executing` → `draft` for the material presentation revision. +- Source and feedback inspected: clean child `66c7da62331873548f0231c9da666a555bf306fb`, artifact `e1c1059cf28`; current PR #500 feedback contains the existing screen-evidence comment. The new direction is the user's explicit approval and rebuild request in the parent conversation. +- Accepted decisions are recorded in the compact-chrome method above. Parent owns the overview and production-plan implications. No unanswered product question blocks this bounded presentation pass. +- Readiness review, 2026-11-14: inspected the revised method against `66c7da623`, the original remaining-work scenario, Q-19–Q-21, the current overview/production-outline boundaries, root/Plans instructions, and current PR feedback. The change is presentation-only: the existing workspace/child identity and explicit baseline owners remain valid. The method keeps truthful comparison labels, preserves every existing capability through named reachable controls, requires keyboard/dismissal regression checks, and measures content-space improvement at matched fixture states. Earlier evidence is retained as historical, with runtime/visual verification repeated for the changed source. The user explicitly approved compact chrome and background implementation; no missing product decision blocks this bounded pass. No readiness findings remain. The unchanged ownership diagram is source-reviewed, not renderer-validated. +- Readiness disposition: `draft` → `ready` after review, then `ready` → `executing` under the user's explicit rebuild request. Implementation evidence and third-round feedback remain pending. + +- [x] Review the compact-chrome method and record readiness. +- [x] Rebuild compact controls while retaining all existing capabilities. +- [x] Repeat the three-size regression scenario and exercise disclosed controls. +- [x] Record fresh independent review, content-space comparison, and iteration-3 captures. +- [x] Publish the coordinated stack update and current issue evidence. +- [x] Collect and integrate third-round user feedback: Q-22–Q-24 request grouped kinds, suitable previews, and explicit skip/resurfacing. + +### Iteration 3 implementation and evidence + +The revised [iteration-3 artifact](Prototype/iteration-03.html) consolidates workspace identity/actions, removes repeated teaching/status bands, and uses concise child/file titles. Workspace options disclose full metadata, review progress, child navigation, arrangement, and outer presentation. On compact screens the active child selector supplies the title; review controls retain the actual comparison and explicit mark action. File navigation is disclosed. Canvas, Reset, and both simulated pushes live in a collapsible sample-controls panel. The independent workspace/child model, PR baselines, drafts, and all previous capabilities remain intact. + +[Iteration 2's runnable archive](Prototype/iteration-02.html) exactly matches `e1c1059cf28`; both earlier evidence sets remain unchanged. [Iteration-3 verification](Prototype/evidence/iteration-03/verification.json) identifies final HTML SHA256 `f2adc670df7668d0c99d79f3ac0d9abeea3df701f56a53e1373de331c2eb274f`, exact measurements, captures, and observed checks. + +| Viewport | Review pane height, before → after | First code-row top, before → after | Matched evidence | +| --- | --- | --- | --- | +| 1440 × 1000 | 413 → 765 | 525 → 203 | [Before](Prototype/evidence/iteration-03/desktop-before.png), [after](Prototype/evidence/iteration-03/desktop-after.png). | +| 834 × 1112 | 535 → 877 | 515 → 203 | [Before](Prototype/evidence/iteration-03/tablet-before.png), [after](Prototype/evidence/iteration-03/tablet-after.png). | +| 390 × 844 | 216 → 648 | 568 → 195 | [Before](Prototype/evidence/iteration-03/phone-before.png), [after](Prototype/evidence/iteration-03/phone-after.png). | + +Values are CSS pixels rounded to the nearest pixel. Initial Parser full comparisons use identical viewport/fixture/appearance; post-push incremental comparisons were separately measured with the same pane geometry. Scroll-pane top and first-code-row top are distinct measurements in the verification JSON. Code text increases from 10px to 12px, and initial phone buttons measure at least 44 × 44px. Additional captures show [new edits on phone](Prototype/evidence/iteration-03/phone-incremental.png), [outer windows](Prototype/evidence/iteration-03/desktop-windows.png), [tablet float](Prototype/evidence/iteration-03/tablet-float.png), [phone preview](Prototype/evidence/iteration-03/phone-preview.png), and [workspace options](Prototype/evidence/iteration-03/phone-options.png). + +The complete final-source scenario passed at all three sizes through Playwright 1.64.1 / Chromium 156.0.8078.4. It covers same-kind child identity/navigation, PR isolation/shared baselines, drafts, source-to-review, preview state, outer presentation, arrangement/focus return, review file-top resumption, original remaining/full comparisons, background/inactive-workspace closure, empty-workspace recovery, and Reset. Relocated menus and sample controls were exercised by pointer/touch and keyboard, with Escape/focus return and Canvas changes. Five axe WCAG 2/2.1 A/AA scans per size reported zero violations. No page/console/load errors, external requests, or document overflow occurred. Standalone file loading/marking, inline JavaScript syntax, archive identity, local links, and whitespace checks pass. Checks use ad hoc scripts, not retained CI guards; native suites and default HTML-excluding lint do not establish coverage here. + +Fresh independent review confirmed three fixes: final-view dialog dismissal restores visible New view focus; title accessible names retain visible filenames/titles; and queued native close events are ignored while a newly reopened dialog is open. The last failure reproduced when Escape after removing all children was immediately followed by Enter to reopen. Five immediate close → reopen → Research → Enter trials pass after correction. The long tablet scenario also found floating children could cover prototype controls after repeated focus; explicit stacking contexts contain them. The reviewer independently verified controls after 40 view raises, all three sizes and disclosed states, comparison labels, inactive-PR closure, archive identity, and rendered output. No actionable findings remain on the recorded source hash. + +The parent readiness update was coordinated onto parent `4b5873d95` at child `3327973404` before UI edits. The verified artifact/evidence was committed at `ab37aeb347`, then rebased unchanged after the coordinator recorded the delivery checkpoint in parent `2c0926596`. Stable artifact/evidence revision [`58c13ac56f87688548887172fef6f39e818bc819`](https://github.com/kyleve/Stuff/commit/58c13ac56f87688548887172fef6f39e818bc819) is published through `gh stack push`. The artifact and this execution record were verified byte-identical through that rebase. [PR #500](https://github.com/kyleve/Stuff/pull/500), its [existing screenshot comment](https://github.com/kyleve/Stuff/pull/500#discussion_r4576427594), and STU-330 now describe iteration 3. GitHub-rendered HTML has the expected three inline images with descriptive alt text; all eleven pinned PNG responses exactly match the local captures. Published-PR visual browser inspection remains unavailable; local captures were visually inspected. The owned loopback server is stopped and direct file loading passed. Native behavior, VoiceOver, actual execution, provider/durability/sync, and third-round product acceptance remain unverified. + +## Iteration 4 readiness and execution + +- Status transition: `executing` → `draft` for grouped comparisons and separate skip receipts. +- Source inspected: clean child `a45970c322b21d3646031f4ca93d9641625814af`; artifact `58c13ac56f87688548887172fef6f39e818bc819`. PR #500 contains the existing screen-evidence comment; the new product decisions come from the parent conversation. +- Q-22–Q-24, R-13/R-14, and the bounded fixtures/method are integrated above. The parent resolved group skip as **Skip remaining files**, excluding currently reviewed/skipped files, and constrained actual review to available content. No material product question remains for this pass; native implementation remains excluded. +- Readiness review, 2026-11-14: inspected the full revised method against `a45970c322`, the root/Plans contracts, current PR feedback, Q-13–Q-24 and R-13/R-14 supplied by the coordinator. The existing singleton three-file catalog and reviewed-only disposition need separate presence/content-revision and skip state; the method assigns those to the PR workspace while keeping expansion/format navigation child-owned. Prepared before/current/raw presentations share one underlying comparison selection, and unavailable binary bytes cannot imply review completion. New/changed/unchanged fixtures falsify future-category skipping and accidental baseline advancement. Original workspace/draft/focus/compact-chrome checks remain required. The parent owns consistent overview/native-outline integration before the coordinated rebase. All material method choices are answered or bounded prototype hypotheses; no readiness findings remain. The updated ownership diagram is source-reviewed, not renderer-validated. +- Readiness disposition: `draft` → `ready` after review, then `ready` → `executing` under the explicit iteration-4 implementation request. Runtime evidence and fourth evaluation remain pending. + +- [x] Reconcile the bounded skip policy and review readiness. +- [x] Implement grouped fixtures, comparisons, and explicit skip/undo. +- [x] Repeat three-size regressions and skip/group/new-push truth scenarios. +- [x] Record fresh independent review and iteration-4 captures/evidence. +- [x] Publish coordinated PR, existing screenshot comment, and issue updates. +- [ ] Collect and integrate fourth-round user evaluation. + +### Iteration 4 implementation and evidence + +The [iteration-4 artifact](Prototype/iteration-04.html) now groups Code, Documents, Localization, and Snapshots/assets, with quiet groups initially collapsed and visible counts/disclosures/actions. LFS is a badge. Each PR has seven changed files at v1 and eight at v2, plus supporting source. The chooser's Remaining / All filter, expansion, selected file, and rendered/source preference belong to each review child. Shared actual review and separate skip receipts belong to the PR workspace. Individual skip and **Skip N remaining** snapshot eligible current files only; group undo removes active skips. Viewing/disclosure never advances either receipt. + +Rendered Markdown exposes exact changed link targets and a source comparison. Localization presents changed key/locale/value rows with raw access. Assets present bundled before/after SVGs, dimensions, bytes, and LFS metadata where applicable. New EmptyResults explicitly has no before file. Design exposes only prepared pointer/metadata, announces unavailable binary content in both Review and Source, and cannot be marked reviewed. These remain candidate fixture presentations, not parsers or native renderers. + +The [iteration-3 archive](Prototype/iteration-03.html) exactly matches published `58c13ac56`; all previous evidence is retained unchanged. [Iteration-4 verification](Prototype/evidence/iteration-04/verification.json) pins HTML SHA-256 `fe137ea8e41335bbb0c25a203f6b27aac689bcdb2ce725420a63ab5b50dc8b00`. Matching v1 full-comparison captures use light appearance and 1× scale: + +| Viewport | Grouped list | Documents | Localization | Snapshots/assets | +| --- | --- | --- | --- | --- | +| 1440 × 1000 | [Groups](Prototype/evidence/iteration-04/desktop-groups.png) | [Markdown](Prototype/evidence/iteration-04/desktop-documents.png) | [Values](Prototype/evidence/iteration-04/desktop-localization.png) | [Images](Prototype/evidence/iteration-04/desktop-assets.png) | +| 834 × 1112 | [Groups](Prototype/evidence/iteration-04/tablet-groups.png) | [Markdown](Prototype/evidence/iteration-04/tablet-documents.png) | [Values](Prototype/evidence/iteration-04/tablet-localization.png) | [Images](Prototype/evidence/iteration-04/tablet-assets.png) | +| 390 × 844 | [Groups](Prototype/evidence/iteration-04/phone-groups.png) | [Markdown](Prototype/evidence/iteration-04/phone-documents.png) | [Values](Prototype/evidence/iteration-04/phone-localization.png) | [Images](Prototype/evidence/iteration-04/phone-assets.png) | + +Additional captures show [skip then push](Prototype/evidence/iteration-04/desktop-skip-push.png), unavailable binary metadata on [phone](Prototype/evidence/iteration-04/phone-unavailable.png) and [tablet](Prototype/evidence/iteration-04/tablet-unavailable.png), and the [link-only source edit](Prototype/evidence/iteration-04/phone-document-source.png). Every capture was visually inspected. The initial Code pane retains iteration 3's exact top/height: desktop 203/765px, tablet 203/877px, phone 195/648px. The verification records code-table top separately from first-row top (the collapsed border extends one pixel above the table origin), avoiding mixed geometry comparisons. + +Complete original workspace regressions and new feature scenarios passed at all three sizes on the final hash through Playwright 1.64.1 / Chromium 156.0.8078.4. Existing checks cover same-kind IDs and independent files/queries/previews, shared review progress, PR isolation/drafts, outer tabs/windows, arrangement/focus restoration, file-top review resumption, remaining/full comparisons, add/close/inactive/empty recovery, keyboard movement/resize, sample controls, and Reset. New checks cover independent grouping/format/filter, group exclusion of already-current reviews and future files, individual/group undo, changed/new resurfacing, unchanged skip persistence, baseline retention, available explicit review clearing a skip, and distinct zero-remaining counts. Markdown link-only, localization incremental/full, image identity, raw basis agreement, and unavailable/absent-before cases passed. Thirteen selected axe WCAG 2/2.1 A/AA states per size have zero violations; no page/console/load errors, external requests, or document overflow occurred. Direct file loading/marking, inline JavaScript syntax, 84 local links/anchors, Markdown fences, all three archive byte identities, 16 capture hashes, and diff whitespace also pass. + +Evidence distinguishes the fixture limits: the UI proves v1 skip → v2 changed/new return and unchanged skip persistence, plus actual review v1 → skip changed v2 retaining basis v1. A separate seeded policy-only check supplies a later content identity and asserts remaining disposition and actual basis v1. It does not render a third revision or claim that three-step live transition exists in this two-revision artifact. + +Fresh independent review covered the complete artifact/catalog and current contracts, relevant prior interaction fixes, prepared diff reconstruction, SVG bytes/hashes, raw/localization consistency, sibling ownership, group policy, focus recovery, and archive identity. It found: (1) the individual Skip accessible-name override omitted the visible action phrase; removing the override retains the visible label/helper; (2) unavailable metadata called object bytes “Pointer size”; the truthful **Object bytes** label and existing pointer-provenance note fix it. The first longer replacement made the narrow tablet object-ID column only 22px wide; the concise label restores 99px and reduces the ID from 363px to 66px tall. Rechecks passed at all three sizes. Pointer-only Source content now has an explicit unavailable-binary notice/footer; group Skip shows its remaining count with matching accessible whitespace. No actionable findings remain on the final hash. -Not started. No prototype artifact or runtime result exists yet. +Unfiltered axe also reports inherited best-practice heading/landmark notices outside the selected WCAG tags. This is not a complete accessibility or VoiceOver audit. Checks are ad hoc browser evidence, not retained CI guards. Default web lint globs exclude this HTML; native tests/snapshots and SwiftFormat were not run because this slice changes no native source/build inputs. Real Git/LFS, format parsing, provider behavior, durability/sync, code execution, native platforms, and fourth-round user acceptance remain unverified. + +Readiness was coordinated onto parent `b386db979` at child `6e250ab22` before artifact edits. The tested artifact/evidence was committed at `97ba3f963`, then rebased unchanged after the coordinator recorded the delivery checkpoint in parent `ce886cdab`. Stable artifact/evidence revision [`e987835f6a1dd18463eceaf8274673c8445036d5`](https://github.com/kyleve/Stuff/commit/e987835f6a1dd18463eceaf8274673c8445036d5) is published through `gh stack push`. The entire 01a/Prototype tree was verified byte-identical through the cascade; the coordinator independently checked the final HTML/capture hashes and representative final visuals. + +[PR #500](https://github.com/kyleve/Stuff/pull/500), its [existing screenshot comment](https://github.com/kyleve/Stuff/pull/500#discussion_r4576427594), and STU-330 now describe iteration 4 and preserve prior history. GitHub-rendered HTML has the expected three PR images and one comment image with descriptive alt text; the published HTML artifact and all sixteen commit-pinned PNG responses exactly match local evidence. Published-PR browser inspection remains unavailable; captures were visually inspected locally. The owned loopback server is stopped, and direct file loading passed. STU-330 remains In Review and this plan remains executing; fourth-round evaluation is explicitly pending. The worker returns the completed artifact/publication/checks/limits to the coordinator, who owns the user's completion notice and next evaluation. + +## Iteration 4 layout-options correction + +The fourth evaluation reported that selected Float / Tabs did not match the visible layout and that inner Float and outer Windows appeared redundant. This is a focused correction to iteration 4, not another feature expansion. Q-25, answered in the parent conversation on 2026-11-14, requires **honoring explicit Float at narrow widths too**. The optional first diagnostic question does not block this resolved behavior. Workspace presentation and child arrangement remain separate scopes under Q-19–Q-21; selected options must describe what is rendered. + +Source `1058ba3ac` / HTML SHA-256 `fe137ea8…` reproduces the contradiction in an isolated fixture browser. Thirty-six combinations covered three arrangements × two presentations × phone/tablet/desktop/wide and both sides of the existing width boundary. At 1440px, Float + Tabs renders three absolutely positioned PR42 children in a 1394px host. Windows narrows each host to 679px and CSS silently changes it to one relative-positioned child while Float stays selected. At 834px the same transition is 788px/three children → 430px/one; at 390px both presentations force one. Host width 680px forces one, 682px floats three. Windows always retains the same two-button tab-looking PR strip. These observations establish the fixture defect, not the exact contents of the user's unavailable live browser. Earlier state/identity tests did not assert these computed visibility/geometry combinations. + +### Bounded method and readiness + +- Preserve published artifact/evidence `e987835f6` byte-for-byte as an iteration-4 archive; keep existing evidence unchanged and add focused correction evidence separately. +- Make scope visible in the options: **PR workspaces** controls outer Tabs / Windows; **Views in Search #42** (or the named owner) controls Tile / Float / One view. Keep independent stored owners, PR progress, drafts, child IDs/files/queries, and focus unchanged. +- Give Windows distinct workspace-window navigation and visible PR identities rather than retaining a tab-looking strip. It remains a browser simulation, not native OS windows. Tabs presents one PR workspace; Windows presents separate labeled PR containers with reachable navigation. +- Remove the silent width-based arrangement override. Explicit Float renders movable/resizable children at every host width, including hosts narrowed by Windows. Explicit Tile remains a real non-overlapping tile layout; a vertical stack with canvas scrolling is the bounded narrow implementation. Explicit One view shows only the selected child. The initial narrow default may be One view, but resizing or changing outer presentation must not silently change a selected arrangement. +- Keep narrow Float usable through bounded visible frame projection, readable minimum size within available canvas bounds, and reachable move/resize/view-selection controls. Resizing the host changes projected geometry, not the saved arrangement or authored placement. Only explicit movement/resizing changes stored placement. No complete window manager, new persistence, or external execution is added. +- Use one coherent arrangement policy for DOM state, selected controls, frame eligibility, and responsive geometry. Keep compact content chrome; remove misleading choices through correct behavior, not additional permanent teaching bands. +- Repeat the concrete combinations and width boundary with computed display/position/rectangles, non-overlap for tiles, reachability of all children, and menu selection agreement. Exercise narrow pointer/keyboard move/resize, host resizing and outer switches with unchanged saved frames/identities/focus, empty/same-kind child recovery, and the relevant modal/focus paths. Preserve review file-top behavior and existing review/skip/draft data. Capture representative matched before/after states and obtain fresh independent review. Unrelated type fixtures need not repeat unless a changed shared path invalidates them. + +Readiness review, 2026-11-14: `executing` → `draft` for this correction, then `draft` → `ready` after integrating Q-25 and reviewing the method against the observed 36-case matrix, Q-19–Q-21 ownership, compact-chrome constraints, and root/Plans instructions. Explicit modes now have falsifiable rendered criteria; narrow frame projection preserves placement without promising native windowing. The coordinator supplied the user answer and owns overview/native-outline integration. No material product question blocks this focused correction. Implementation resumes `executing` under the user's bug report and explicit Q-25 answer after the coordinated parent cascade. + +- [x] Reproduce selected/rendered mismatch and review the bounded correction method. +- [x] Correct scoped controls and effective arrangement behavior. +- [x] Verify computed combinations, narrow interactions, continuity, and representative renders; obtain fresh independent review. +- [x] Publish coordinated PR/comment/issue updates and a completion handoff. +- [ ] Collect the user's evaluation of the corrected presentation. + +### Layout correction implementation and evidence + +The reviewed method was coordinated onto parent `56a9a3307` at child `8404126bf` before UI edits. Source SHA-256 `93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b` now keeps explicit Float/Tile/One view effective at every host width. Narrow Tile stacks real children; only the initial narrow default chooses One view. Windows uses a distinct PR selector and labeled containers. Options visibly scope PR workspaces separately from views in the named PR. Child container sizing keeps controls/content usable inside narrow floats. + +Saved normalized frames remain unchanged during host resizing. Display projection fits them within the canvas with a bounded 300×210px minimum (limited by available space); pointer and keyboard operations start from the projected frame, and only explicit motion authors placement. The frame observer adjusts geometry without rebuilding navigation/focus state. The previous silent CSS override and width-gated motion handler are removed. + +[Focused verification](Prototype/evidence/iteration-04-layout/verification.json) retains the before/after measurements, source hashes, actual interaction checks, and fresh independent review. Thirty-six author combinations and forty-two reviewer combinations check selected modes against computed display, positioning, fitted bounds, and non-overlapping tiles, including host width 680/682px and viewport 320px. At 1440px Windows still creates 679px hosts, but PR42 now displays all three floating children. Narrow pointer movement of 4px/6px produces exactly 4px/6px with no size jump; keyboard movement, pointer/keyboard resize, actual handle hits, and reachability of obscured/lower views pass at phone/tablet/desktop. Phone move/resize targets measure 44×44px. Resize and presentation round trips preserve authored placement, child IDs/navigation, PR review/skip/draft/query state, and focus. Review-top return, preview return, independent PR frames, and empty recovery pass. The reviewer also exercised narrow touch movement and independently reproduced the old nonfunctional resize trigger. No actionable findings remain. + +Fifteen author and twelve independent selected WCAG scans pass; no page/console/load errors, external requests, or document overflow were observed in the focused scenarios. Direct file loading and narrow Float work. Inline JavaScript syntax, 105 local links/anchors, Markdown fences, all four archive identities, ten capture hashes, and diff whitespace pass. These are isolated Chromium fixtures, not inspection of the unavailable user tab or native/VoiceOver acceptance. The complete prepared catalog and review/skip/comparison function range are byte-identical to the prior artifact; unrelated type-fixture tests were not rerun wholesale. Earlier verification is historical and does not substitute for the new geometry checks. + +Ten [matched/representative captures](Prototype/evidence/iteration-04-layout/) cover [phone before](Prototype/evidence/iteration-04-layout/phone-float-before.png)/[after](Prototype/evidence/iteration-04-layout/phone-float-after.png), [tablet before](Prototype/evidence/iteration-04-layout/tablet-windows-before.png)/[after](Prototype/evidence/iteration-04-layout/tablet-windows-after.png), [desktop before](Prototype/evidence/iteration-04-layout/desktop-windows-before.png)/[after](Prototype/evidence/iteration-04-layout/desktop-windows-after.png), scoped options, narrow tiles, and narrow floating content. They use the same synthetic v1 fixture, viewport, light appearance, and 1× scale, and were visually inspected. The [iteration-4 archive](Prototype/iteration-04.html) exactly matches published `e987835f6`; previous evidence is untouched. The tested correction/evidence was committed at `af9aa242e`, then rebased byte-identically after the coordinator's delivery checkpoint in parent `8021dc5cc`. Stable artifact/evidence revision [`4fa02dfb4b42f98d219747683c6aaf94132e6c97`](https://github.com/kyleve/Stuff/commit/4fa02dfb4b42f98d219747683c6aaf94132e6c97) is published through `gh stack push`. The coordinator independently verified the final HTML/capture hashes, representative visuals, and fresh review disposition. + +PR #500, its existing screen-evidence comment, and STU-330 now describe the correction and retain prior history. GitHub-rendered HTML contains the expected three PR images and one comment image; the published artifact and all ten commit-pinned PNG responses match local evidence. Published-PR browser inspection remains unavailable. The isolated loopback server is stopped; direct file loading passed. STU-330 remains In Review and 01a executing pending evaluation of the corrected presentation. The worker returns the final artifact, receipt, checks, and limits to the coordinator for the requested user completion notice. ## Resume point -After an execution request, read current plan feedback and the latest question resolutions, then begin the bounded artifact. Plan creation and the selection of this deliverable did not authorize its execution. +Close/reopen is reviewed and published. The user now requests Astro authoring with automatic reload and local-network access. The bounded [Astro development follow-up](#astro-implementation-and-evidence) is reviewed and published at `eba910265`, with its final receipt below. Return the live LAN demo and receipt to the coordinator for the completion notice. The intentional native Astro server remains running for evaluation; its URL and stop command accompany the handoff. Keep acceptance open and native refinement gated. ## Outcome -Pending prototype evidence and feedback. [01](01-review-state-foundation.md) remains an outline until those findings are integrated. +Four iterations and the layout-options correction are published with retained evidence. The next user evaluation found the title-bar gesture missing outside the icon. That focused correction is built, verified, independently reviewed, and published. New feedback requests closing/reopening retained PR workspaces; its implementation is verified, independently reviewed and published, with user evaluation next. The next authorized tooling follow-up moves authoring to the existing pinned Astro toolchain with live reload and LAN access; it preserves the evaluated UI and session model. The plan stays executing through delivery and evaluation. [01](01-review-state-foundation.md) remains an outline until the required evidence and user decision are integrated. + + +## Iteration 4 title-bar drag correction + +The next user evaluation reports that dragging a view title such as `Parser.swift` does not move it. At published receipt `7f89c2b5c` (HTML SHA-256 `93018f2f…`), isolated mouse gestures at 390 × 844, 834 × 1112, and 1440 × 1000 confirm an 18px/24px title-text drag produces 0px/0px movement; the adjacent icon moves the view by exactly 18px/24px. The prior movement probe exercised only the icon's `[data-drag]` hook, so it did not cover this expected title-bar affordance. Existing layout/type evidence remains historical and unchanged. + +### Title-bar method and readiness + +Bound this follow-up to the current floating-child pointer gesture. The eligible title bar includes the icon, filename/title, and surrounding header space; independent close, focus-layout, and source-review controls keep their own actions. Use a small named movement threshold to distinguish an intentional drag from stationary/slightly jittered filename clicks. A normal filename click still opens its chooser. A completed drag must not open the chooser or activate a control. Keep the existing keyboard icon/resize behavior, fitted-frame start, PR/child ownership, focus, and narrow-width policy. + +Track the initiating pointer, start capture only as needed without breaking native clicks, and clean up on release, cancellation, lost capture, and rerender. Verify the exact title-text path, header and icon, threshold boundaries, mouse/touch drag, stationary click/tap, excluded controls, cancellation and a subsequent gesture. Check narrow and wide geometry, resizing, keyboard movement, focus/placement continuity, and unchanged sibling/PR state. Keep evidence scoped to these paths; unrelated prepared diff/skip fixtures need not run again. Add focused results/captures under `Prototype/evidence/iteration-04-drag/`, preserve all prior evidence, and use a fresh independent review before a clean tested commit and coordinator review. Publish directly through the existing stack after that review; parent stays `8021dc5cc`. + +Readiness review (2026-11-14): status briefly returned to draft for the method revision, then ready after checking the user trigger, existing gesture/click ordering, ownership and recovery paths, fixture limits, review/publication sequence, and explicit authorization. No product question or execution blocker remains; status returns to executing for this focused correction. The coordinator delegated this branch's overview checkpoint update only; shared requirements and native outlines stay unchanged. User reevaluation remains required after delivery. + +- [x] Reproduce title text versus icon and review the bounded method. +- [x] Implement and verify drag/click separation and cleanup at representative widths. +- [x] Finish fresh independent review; no actionable findings. +- [x] Obtain coordinator review of the clean tested commit. +- [x] Publish the existing PR/evidence/issue; final receipt is ready for the coordinator completion handoff. +- [ ] Obtain user reevaluation; the experiment remains executing. + +Resume point: return this published receipt to the coordinator, then await user reevaluation. The earlier layout-correction publication remains valid historical evidence. + + +### Title-bar implementation and evidence + +HTML SHA-256 `3f86c704db285b85cd504a148236aa464016fb37dd92e005256f27cadc98007d` makes the eligible header, icon, and filename/title share the existing floating-frame gesture. A 5 CSS pixel distance threshold distinguishes movement from click/tap jitter. Capture stays on the original button so a stationary click remains native; a completed drag suppresses its resulting pointer click. Independent action controls and keyboard actions retain their paths. Matching pointer ownership, release/cancel/lost-capture cleanup, rerender teardown, and window blur prevent a stale gesture. Cancellation keeps the last applied placement and stops further movement; it does not synthesize an action. + +[Focused verification](Prototype/evidence/iteration-04-drag/verification.json) pins the final source, before reproduction, measurements, and reviews. Twelve author scenarios per size pass at 390 × 844, 834 × 1112, and 1440 × 1000. The exact `Parser.swift` mouse and touch gestures move +18/+24px with no chooser or size jump; stationary clicks/taps and 4px jitter open the chooser; 5px begins a drag. Header/icon movement, next click/Enter, excluded close/focus/source-review actions, foreign-pointer isolation, lost capture/touch cancellation/rerender, pointer/keyboard resizing, saved placement/focus, and sibling/PR continuity pass. Three selected WCAG scans report no violations and no browser/resource errors or external requests occurred. + +Fresh independent review found no actionable issues after 15 scenarios at each size plus five alternate-path checks, including drag-out-and-back suppression, preview title, narrow outer Windows ownership, and Tile preserving saved frames. The coordinator independently verified the exact filename drag (+32/+24), suppression, subsequent click, and Enter in Chromium 156.0.8078.4 and WebKit 27.2 via direct file loading. These targeted WebKit checks do not establish a full Safari/device matrix. + +Six visually inspected captures apply the same +36/+80px title-text gesture to matching PR42 v1 fixtures, light appearance, 1× scale: [phone before](Prototype/evidence/iteration-04-drag/phone-before.png)/[after](Prototype/evidence/iteration-04-drag/phone-after.png), [tablet before](Prototype/evidence/iteration-04-drag/tablet-before.png)/[after](Prototype/evidence/iteration-04-drag/tablet-after.png), [desktop before](Prototype/evidence/iteration-04-drag/desktop-before.png)/[after](Prototype/evidence/iteration-04-drag/desktop-after.png). Before is exact published source `7f89c2b5c` and stays still; after moves exactly as requested. Prior archives/evidence stay unchanged. The default lint excludes this HTML; native tests/snapshots/SwiftFormat and unrelated type/skip scenarios were not rerun. These are ad hoc synthetic browser checks, not live-user-browser, native/VoiceOver acceptance or retained CI guards. The experiment remains executing pending user reevaluation. + + +Title-bar publication receipt: reviewed artifact/evidence [`f21e01fecffd0f0ecbfa63fbaa6970e7bd3b760c`](https://github.com/kyleve/Stuff/commit/f21e01fecffd0f0ecbfa63fbaa6970e7bd3b760c) is published through `gh stack push`; parent stays `8021dc5cc`. The coordinator reviewed the clean commit, final HTML and six capture hashes, and scoped cross-engine evidence. Inline JavaScript, 214 local links/anchors, fences, archive identities and whitespace passed before that commit. PR #500, its existing screen-evidence comment, and STU-330 now describe this correction. GitHub-rendered HTML has the expected three PR images and one comment image; the published HTML and all six PNG responses match the tested bytes. The owned loopback server is stopped and direct file use passed. No source changed after validation. STU-330 stays In Review under STU-329 and 01a stays executing; user reevaluation is pending. The coordinator owns the final completion notice. + + +## Workspace close/reopen follow-up + +The user reports that PR42/43 remain permanently visible with no dismissal and requests closing and reopening PR workspaces. This extends R-02/R-03 within the same two synthetic PRs and in-memory browser experiment. It does not close a GitHub PR, delete a workspace, add repository browsing, or implement persistence/sync. Cross-device open/closed policy remains under Q-09. Retain the published title-bar artifact/evidence at `f21e01fec` and all earlier records. + +### Close/reopen method and readiness + +Separate retained workspace ownership from current open presentation. Add an explicit open/closed state while preserving the same PR/workspace object, child IDs/routes, saved frames/layout, last-focused child, reviewed/skipped versions, and draft. The active workspace may be absent; no fallback may silently select or reopen PR42/43. Reset deliberately recreates the initial two-open-workspace sample session. + +Use a close control on each outer PR tab/window and a persistent compact **Workspaces** picker listing the two retained PRs with open/closed status and explicit switch/reopen actions. Closed workspaces disappear from the outer tabs, window hosts and active-workspace navigation, but stay in that picker. Closing the last workspace shows an intentional empty state with a reopen entry point. Preserve compact chrome and distinguish workspace close from child-view close. These browser controls are bounded prototype choices, not a native window-menu commitment. + +Closing an inactive workspace preserves the active PR and its focused child; closing the active workspace selects the next remaining workspace in existing order, or the previous one if there is no next. Last closure sets no active workspace. Reopening activates the same retained workspace, once, with its arrangement and focused child; a Review resumes its selected file at the top, while a non-review keeps its focus/state. Reopening an empty-child workspace keeps its existing New view recovery. Recover keyboard focus to the surviving active context or Workspaces control after a close, and to the restored child/context after reopen; Escape returns from the picker predictably. + +Current source `ac4ac4478` renders every retained workspace and dereferences the active owner throughout navigation, render/focus restoration, modal dismissal, observers and events. The current sample-push path also activates its PR. Update those paths coherently: only open workspaces render/observe/accept child actions, global controls tolerate no active owner, and repeated/stale actions cannot duplicate or implicitly reopen a workspace. A sample push may update a retained closed PR's fixture revision without opening it or stealing active focus. Resize/presentation changes preserve open/closed state and saved placement. Reset is the deliberate exception. + +Evidence criteria: exercise tabs and windows at phone/tablet/desktop sizes; close inactive, active, then last workspace; assert actual host/tab visibility, active/focused identity and accessible empty recovery. Reopen repeatedly and verify no duplicate instances, unchanged child IDs/routes/frames/layout, review/skip receipts and drafts, review-file-top versus non-review-focus return, and empty-child recovery. Check picker keyboard/Escape and mouse/touch reachability, closed-workspace sample push, all-closed resize/presentation paths, Reset, and retained title-bar drag/click/resize behavior after reopening. Test relevant shared modal/render boundaries, not unrelated format catalogs. Add exact-source evidence and representative captures under `Prototype/evidence/workspace-close/`; obtain fresh independent review, a clean tested artifact checkpoint and coordinator review before coordinated publication of #500, its existing screen comment and STU-330. + +Readiness review: `executing` → `draft` for this method revision, then `draft` → `ready` after tracing source ownership, implicit-active assumptions, focus recovery, the two-PR fixture, and the user-authorized retain/reopen behavior. No product choice blocks this bounded method. Parent integration of R-02/R-03 and outlines 01/02 is a coordination prerequisite; no UI implementation starts until the coordinator reviews this clean method commit and completes the cascade. The coordinator owns shared overview/native changes and the completion notice; this branch owns 01a/artifact evidence. Resume executing after that release, and keep experiment acceptance pending user evaluation. + +- [x] Inspect current ownership/activation paths and review the bounded method. +- [x] Coordinate parent integration and resume implementation at parent `ecb3c017d` / child `7c0521696`; method and artifact bytes are unchanged by the cascade. +- [x] Implement close/reopen, explicit no-active state, and retained-context recovery. +- [x] Verify focused three-size scenarios/captures and fresh independent review; no actionable findings. +- [x] Publish the coordinated artifact/evidence/receipt; ready for the coordinator completion handoff. +- [ ] Integrate user evaluation before completing the experiment. + + +### Close/reopen implementation and evidence + +Final HTML SHA-256 `c99c3a8670006ca787dd5880ff9e04834b777d682f1dca7515688f94c6cad89b` retains the workspace registry while separately rendering only open PRs. Outer tabs/windows have their own Close controls; Workspaces lists both retained PRs with Switch/Reopen, including when none are open. Active closure picks the next/previous remaining owner; inactive closure keeps the active owner/focus; last closure records `null` without a fallback PR. Reopen restores the same workspace/child objects and context, with Review file-top behavior. Global modal/render/focus paths tolerate no active owner, closed child actions are ignored, and closed sample pushes change revision without opening or focusing the PR. Reset recreates the initial session. + +[Focused verification](Prototype/evidence/workspace-close/verification.json) records eleven author scenarios across three sizes × Tabs/Windows (66 scenario checks), twelve selected WCAG scans, nine capture hashes, independent review and scoped cross-engine evidence. Scenarios cover active/inactive/last closure, actual absent hosts/tabs, retained object identities/routes/frames/layout/receipts/draft, non-review focus and review-top return, repeated reopen, empty-child recovery, keyboard/Escape, closed sample pushes, all-closed width/presentation changes, stale child events, Reset, and retained title-bar move/click/resize. No browser/resource errors, external requests or document overflow occurred. + +Fresh review found no actionable issues after its own eleven scenarios across all six size/presentation cases, six selected WCAG scans, real touch/hit checks at 320/390/834px, and keyboard workspace closure during an active drag. Author target inspection expanded the narrow 44px rule to the new outer window-close button; final-source hit tests confirm 44×44px tab/window close targets at 320/390. Closing during a drag releases capture, avoids a pointer-up action, and permits subsequent reopen/click. The coordinator independently passes close/reopen, stored review/draft/file context, all-closed presentation changes, review-top and title dragging in Chromium 156.0.8078.4 and WebKit 27.2 at phone/desktop widths on this final hash. + +Nine [captures](Prototype/evidence/workspace-close/) show the retained picker, empty state and reopened Store review at [phone](Prototype/evidence/workspace-close/phone-picker.png), [tablet](Prototype/evidence/workspace-close/tablet-picker.png), and [desktop](Prototype/evidence/workspace-close/desktop-picker.png) sizes. They use the same synthetic PR42 v1 context, with Parser reviewed and a saved draft, light appearance, 1× scale; all were inspected after the transient toast cleared naturally. Previous artifacts/evidence stay unchanged. Checks use isolated direct-file fixtures, not the user's unavailable browser. WebKit coverage is scoped, selected WCAG scans are not VoiceOver acceptance, and the probes are not retained CI guards. Default lint excludes this HTML; native tests/snapshots/SwiftFormat and unrelated format catalogs were not rerun. No backend/durability/sync/native work is added, and Q-09 retains the cross-device policy question. User evaluation remains pending; 01a is executing. + + +Close/reopen publication receipt: approved artifact/evidence [`87886b922ca2ba6a578ebac9259d7691e7ad7730`](https://github.com/kyleve/Stuff/commit/87886b922ca2ba6a578ebac9259d7691e7ad7730) is published through `gh stack push`, with parent unchanged at `ecb3c017d`. The coordinator verified the clean commit, final source and nine capture hashes, review disposition and representative visuals. Inline JS, 234 local links/anchors, fences, archive identities and whitespace passed before that commit. PR #500, its existing screenshot comment and STU-330 now describe close/reopen. GitHub-rendered HTML has three PR images and one comment image; published HTML and all nine PNG responses exactly match tested bytes. Direct-file checks needed no server. No source changed after validation. STU-330 remains In Review under STU-329 and 01a executing pending user evaluation; the coordinator owns the completion notice. + + +## Astro development follow-up + +On 2026-11-15, the user requested the repository’s Astro dependency for automatic reload and phone access over the local network, followed by a separate planning-skill PR. This branch owns the prototype migration; the coordinator owns the independent skill change. No native requirement or parent-stack mutation is needed. + +### Astro development method and readiness + +- Preserve the exact published standalone HTML (`c99c3a8670006ca787dd5880ff9e04834b777d682f1dca7515688f94c6cad89b`) as `pre-astro.html` and leave all prior archives/evidence unchanged. Extract the same markup, global CSS and client JavaScript into a real `src/pages/index.astro` route and imported sources. Do not serve a static `public/index.html` bypass. +- Add prototype-local Astro configuration and TypeScript project discovery only. Resolve Astro and its tools from root `package.json`/`package-lock.json` and installed root dependencies; add no second dependency tree, root script, native module, production deployment, or live data integration. Keep generated output/cache ignored and dev filesystem access scoped to this prototype. +- Use the installed CLI’s `dev --root "$PWD/Plans/2026-11-14-mobius/Prototype" --host 0.0.0.0 --port 4321 --background`; use native `dev status`, `dev logs`, and `dev stop` for ownership. Set `ASTRO_TELEMETRY_DISABLED=1` for noninteractive invocation. Verify the actual command before publishing it. +- Prove page, CSS, and client-script changes reach an already-open isolated browser without manual refresh, then restore probes and pin final sources. Distinguish CSS updates from full-page reload; a full reload intentionally resets the in-memory sample session. No persistence is added. +- Run Astro check/build and scoped syntax/lint checks appropriate to the new files. Exercise served phone/tablet/desktop UI, representative retained workspace/review/skip/draft/navigation/drag behavior, and compare matched captures to the preserved standalone artifact. Check console/load errors and the machine’s LAN address. Phone Wi-Fi and native device behavior remain untested. +- Obtain a fresh independent code/behavior review, retain separate evidence under `Prototype/evidence/astro-dev/`, and return the clean tested commit for coordinator review before publication. Update existing #500/comment/STU-330; leave 01a executing pending user evaluation. The final handoff names the running server’s owner, URL, and exact stop command. + +Readiness review (2026-11-15): the tooling revision was drafted and reviewed against the existing experiment scope, root pinned Node/Astro tools and installed CLI help, current session-only behavior, retention rules, and user authorization. The method changes development delivery only; no unresolved product choice blocks it. Status transitioned `executing → draft → ready → executing` before implementation. Parent remains `ecb3c017d`; no rebase/cascade is required. Historical browser evidence remains valid for its old sources; the new packaging needs fresh served/reload evidence. + +- [x] Inspect pinned tools and review this bounded method. +- [x] Create the real Astro route and document its scoped commands. +- [x] Verify automatic updates, LAN serving, retained behavior, and matched renders. +- [x] Complete fresh independent review. +- [x] Return a clean tested commit for coordinator review, then publish. +- [x] Prepare the running demo and ownership/stop information for the coordinator handoff. +- [ ] Integrate user evaluation; do not mark the experiment complete yet. + +### Astro implementation and evidence + +The real Astro route imports a global stylesheet and bundled client script. The script is byte-identical and the CSS differs only by removal of the original closing-block separator blank line from published standalone SHA-256 `c99c3a86…`, preserved as [pre-astro.html](Prototype/pre-astro.html). No root dependencies, lockfile, Tools or skill source changed. The route hash is `06655f89112e163387eab452f15a042e0e7e00a92cab6f172e5dc4b6fcb0d2cd`; [verification.json](Prototype/evidence/astro-dev/verification.json) pins all five source/config hashes and nine captures. + +Actual LAN-browser edits prove CSS HMR preserves the session, while page/client-script edits full-reload and reset the sample without manual refresh. All probes were restored; one Add action creates one child after reload. Native background startup requires an absolute `--root` in pinned Astro 7.4 because it changes the child cwd before forwarding that argument; the initial relative-root attempt timed out with missing pages, and its generated nested cache was removed after the child exited. The documented absolute-root command starts normally. Native status/logs and machine-LAN HTTP succeed; prototype-scoped `@fs` access rejects the repository-root file probe. The owned dev server (PID 7013 on port 4321 at this checkpoint) remains running intentionally; [run/stop commands](Prototype/README.md#run-the-demo) and the live URL are supplied in the handoff. The reviewer’s separate build-preview server was stopped. + +Astro check reports four files and zero errors/warnings/hints; build emits one static route and bundled assets. Explicit Astro/config ESLint, unchanged-client syntax and whitespace pass. Eight observable scenarios at each of 390 × 844, 834 × 1112 and 1440 × 1000 pass, with six selected WCAG scans. Review/skip/draft state, independent child navigation, close/reopen ownership, rich/source previews, actual comparison basis, file-top return and filename drag/click/keyboard movement remain intact. The three matched initial before/after PNG pairs are byte-identical and all new captures were visually inspected. Prior archives and evidence remain unchanged. + +Fresh independent review passes ten Chromium 156 / WebKit 27.2 dev/build cases and finds no actionable migration issue. Its final mechanical recheck verifies removal of only the CSS separator newline; the author’s build/reload/three-size checks and coordinator’s four cases were rerun at the final CSS hash `4dcaeb7e65ffb9469d740184816ed6249cff16f0f5be7753dd5aac9b83241282`. Four additional coordinator localhost/LAN cases pass. WebKit mouse closure of an inactive workspace may move DOM focus from Research input to body while preserving logical child focus; the reviewer reproduced it identically in archive/dev/build and classified it as unchanged browser-focus behavior, not a migration defect. Keyboard recovery and retained context pass. No UI/script behavior was changed to address it. + +Limits: actual phone Wi-Fi/native devices remain untested; full reload remains intentionally destructive to the sample session. Root default lint excludes Prototype, so explicit narrow checks are recorded rather than claiming broad lint coverage. Runtime probes are ad hoc evidence, not new CI guards. The separate [planning workflow PR #503](https://github.com/kyleve/Stuff/pull/503) owns reusable Astro guidance. Experiment acceptance and native refinement still await user evaluation. + + +Astro publication receipt (2026-11-15): coordinator-approved [artifact/evidence `eba910265bc74b8ef858c1d71289ce31745b0132`](https://github.com/kyleve/Stuff/commit/eba910265bc74b8ef858c1d71289ce31745b0132) is published through `gh stack push`; parent remains `ecb3c017d`. Existing PR #500, screenshot discussion `4576427594`, and STU-330 now reference the Astro setup, exact-source checks and separate [workflow PR #503](https://github.com/kyleve/Stuff/pull/503). GitHub-rendered HTML contains three PR images and one updated discussion image; all 17 published source/config/archive/README/evidence/PNG responses exactly match approved bytes. The comment preserves its existing discussion and links the new owning route after the original file became an archive. No user browser was available for publication UI inspection, so verification used rendered GitHub HTML and image responses. + +The dev server remains intentionally running under the prototype task (native background PID 7013, port 4321; LAN and local URLs supplied to the coordinator). Use the README’s project-scoped `astro dev status`/`dev stop` commands; the temporary independent build-preview server is stopped. Sources did not change after final validation. STU-330 remains In Review under STU-329 and 01a executing pending user evaluation. The coordinator owns the requested completion notice. Actual phone Wi-Fi remains untested. + + +LAN handoff clarification (2026-11-15): the machine’s LAN address changed after the successful recorded checks. The unchanged Astro daemon remained bound to `0.0.0.0` on port 4321, but native `dev status` continued printing its startup address. The coordinator inspected the current network interface and verified HTTP 200 from both localhost and the new LAN address, then supplied the corrected URL to the user. Earlier LAN evidence remains valid historical evidence; no enduring IP is promised. The README now requires a current-interface and HTTP check when sharing the demo. This follow-up changes documentation only; source/configuration/captures are unchanged, no broad runtime checks were repeated, and the intentional server remains running. + +### Shared prototype command adoption + +On 2026-11-15 the user reported [#503](https://github.com/kyleve/Stuff/pull/503) merged. `gh stack sync` brought the plan and prototype branches onto main `2193072f6a1c988f797c77c14c3b6cf0923d8ca0`, preserving the two-PR stack. The current [run instructions](Prototype/README.md#run-the-demo) use `./prototype` for start/status/logs/stop/check/build. Earlier raw Astro commands and receipts above remain historical evidence. + +The coordinator verified the synced prototype at `ee959e2dd84ee4018fa3f2779c0ccc6fe437dc95`: `./prototype status Plans/2026-11-14-mobius/Prototype` reports the existing PID 7013 on port 4321 and successful HTTP at the local and current network addresses. Check reports four files with zero errors/warnings/hints; build emits one static route. Source/configuration, archives and captures match the pre-sync artifact; only current instructions/checkpoint changed. Prior interaction and reload evidence is retained rather than claimed as a new browser run. Actual phone connectivity remains untested. + +The review server stays running under the coordinator. From this worktree's root, use `./prototype stop Plans/2026-11-14-mobius/Prototype` to stop it. The tool/skill work is delivered; experiment acceptance still awaits user evaluation, with 01a executing and STU-330 In Review. diff --git a/Plans/2026-11-14-mobius/Prototype/README.md b/Plans/2026-11-14-mobius/Prototype/README.md new file mode 100644 index 000000000..656896bd5 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/README.md @@ -0,0 +1,173 @@ +# Mobius workspace study + +This Astro mockup explores compact PR workspaces with independent review, source, research, and simulated-preview views, grouped file kinds, suitable comparisons, and explicit PR-local skip/undo. PR workspaces close and reopen with their context retained. All fixtures and interaction state are local; no account or backend is used. A full reload or **Reset** restores the sample session. + +## Run the demo + +From the repository root, use the already pinned Node/Astro dependencies. If dependencies are missing, run `mise exec -- npm ci`; do not install another package tree in this directory. + +```sh +./prototype start Plans/2026-11-14-mobius/Prototype --lan +./prototype status Plans/2026-11-14-mobius/Prototype +./prototype logs Plans/2026-11-14-mobius/Prototype +./prototype stop Plans/2026-11-14-mobius/Prototype +``` + +Open the **Local** URL on this Mac or the current **Network** URL on a phone connected to the same network. Run `status` again before sharing: it verifies HTTP responses at the current interface addresses instead of trusting Astro’s cached startup URLs. The command reuses this project's existing server; a new server defaults to port 4321. If that port is occupied, choose another with `--port NUMBER`. + +The merged [prototype command](../../../prototype) owns pinned tooling, absolute project paths, server ownership and lifecycle. See its [tooling guide](../../../Tools/README.md#browser-prototypes) for details. + +The prototype is served through [src/pages/index.astro](src/pages/index.astro), which imports [styles.css](src/styles.css) and the bundled browser [app.js](src/app.js). Edit these sources: CSS hot-updates preserve the sample session; page or script changes automatically reload it and reset in-memory state. There is no `public/index.html` bypass. [astro.config.mjs](astro.config.mjs) scopes development file access and the ignored Vite cache to this directory. `.astro/` and `dist/` are already ignored by the repository. + +Check and build from the same repository root: + +```sh +./prototype check Plans/2026-11-14-mobius/Prototype +./prototype build Plans/2026-11-14-mobius/Prototype +``` + +`dist/` is a local generated build, not a deployment. [pre-astro.html](pre-astro.html) is the byte-identical standalone archive from before this migration; open it directly only for historical comparison. It is not the live authoring entry. + +The evaluation server is intentionally left running by the coordinator for the user’s requested phone access. The handoff provides its current URL and process identity; use the project-scoped `status`/`stop` commands above to inspect or stop that owned server. Machine-LAN HTTP is verified; an actual phone’s Wi-Fi path has not been tested. + +## Astro migration evidence + +The [verification record](evidence/astro-dev/verification.json) pins the route, configuration, CSS and client-script hashes. The prior standalone artifact is retained exactly; the client script is byte-identical and the stylesheet differs only by removal of its closing-block separator blank line. Matched initial screenshots are byte-identical before/after at all three sizes: + +| Viewport | Standalone before | Astro after | Resumed incremental review | +| --- | --- | --- | --- | +| 390 × 844 | [Phone](evidence/astro-dev/phone-before.png) | [Phone](evidence/astro-dev/phone-after.png) | [Phone](evidence/astro-dev/phone-review.png) | +| 834 × 1112 | [Tablet](evidence/astro-dev/tablet-before.png) | [Tablet](evidence/astro-dev/tablet-after.png) | [Tablet](evidence/astro-dev/tablet-review.png) | +| 1440 × 1000 | [Desktop](evidence/astro-dev/desktop-before.png) | [Desktop](evidence/astro-dev/desktop-after.png) | [Desktop](evidence/astro-dev/desktop-review.png) | + +Astro check/build, scoped Astro/config ESLint and unchanged-script syntax checks pass. Actual CSS hot updates and page/script full reloads were observed without manual refresh. Eight observable scenarios at each size cover retained review/skip/draft state, independent views, close/reopen, comparisons, source/rich content, file-top resumption and title-bar drag/click/keyboard movement. Six selected WCAG scans pass. A fresh reviewer passes ten Chromium/WebKit dev/build cases with no actionable migration findings; four coordinator localhost/LAN cases pass. No page errors or document overflow occurred. The reusable command and planning guidance landed in [PR #503](https://github.com/kyleve/Stuff/pull/503); the Mobius stack now includes that merged main revision. + +A pre-existing WebKit mouse-focus observation is retained as a limit: closing an inactive workspace after typing in Research may move DOM focus to the body, while the same logical child remains focused. The archive, dev route and build behave alike; keyboard recovery and context restoration pass. These checks are ad hoc evidence, not native device validation or a complete accessibility audit. Earlier results below remain historical; user evaluation is pending. + +## Find the controls + +- **Workspaces:** the persistent picker lists open and closed sample PR workspaces. **×** on a PR tab or outer window closes that workspace without losing its views, review/skip progress, or draft. **Reopen** restores it; closing the last workspace leaves a deliberate empty state with recovery. This does not close the GitHub PR. +- **Workspace bar:** switch between **Search #42** and **Restore #43** using PR tabs, or the **PR workspaces · Windows** selector when separate workspace windows are shown. The comment icon opens the PR's private review draft; **+** adds another Review, Source, Research, or Preview. +- **Workspace options (…):** inspect full PR metadata and progress, select **Open views**, choose **PR workspaces → Tabs / Windows**, and separately arrange **Views in Search #42 → Tile / Float / One view**. Float stays movable/resizable at every width; narrow Tile stacks views. Narrow sessions initially choose One view. Resizing and changing outer presentation preserve explicit selections and saved placement. +- **Current view:** Tile/Float title bars identify each child file or view. In One view, the title is also the view selector. Use it to switch children; **×** closes the selected view. **Open views** also lets you choose or close any child without activating another one. +- **Review:** in Tile/Float, click the filename to choose another file. In One view, use the folder button. The comparison button states what is actually displayed—**Full PR diff**, **New edits since v1**, or **No remaining changes**—and opens Remaining / Full PR choices. **Mark reviewed** explicitly advances only that PR/file baseline. The chooser groups Code, Documents, Localization, and Snapshots/assets; quiet groups start collapsed. Its Remaining / All filter changes the list without changing the comparison. Counts distinguish remaining, reviewed, and skipped files. +- **Skip:** the comparison menu offers **Skip for this PR** for a remaining file. Group **Skip N remaining** captures only currently remaining members; **Undo** removes their active skips. Already-current reviewed files are excluded. A skipped file stays accessible under All, with Undo; explicit Mark reviewed is also available in its comparison menu when actual content exists. +- **Content previews:** Documents show rendered Markdown plus exact changed link targets; Localization shows changed key/locale/value rows; Snapshots/assets show before/after fixture images and metadata. **Source** reveals the prepared raw diff. LFS is a badge, not a group. `Design.psd` has only pointer/metadata fallback and cannot be marked reviewed. +- **Source:** use the filename control (or One view file selector) to browse sample source. **Review file** opens another review child for changed files. Research queries remain independent and results open new Source children. +- **Float:** drag the title bar, including its filename/title or kind icon, or use its resize corner. A stationary filename click opens the chooser; the separate close/focus actions remain buttons. With the move icon focused, arrow keys move and Shift+arrow keys resize; the resize handle also supports arrow-key resizing. +- **Sample controls:** expand **Sample data · Controls** above the workspace for Canvas width, each PR's **Simulate push**, and **Reset**. A push to a closed workspace updates its fixture without reopening it; Reset deliberately restores both initial workspaces. Escape closes the panel and returns focus. Preview content remains explicitly **Simulated**. + +Dialogs close through Escape or their close button. These controls and layouts are hypotheses to evaluate, not commitments for every native platform. + +## Try the return visit + +1. In PR 42, mark `Parser.swift` and `Stable.swift` reviewed at v1; leave `Store.swift` unreviewed. +2. In sample controls, **Simulate push** for PR 42. Remaining now shows Parser's new edits and Store's full PR diff; unchanged Stable has no remaining work. Full context remains available from the comparison control. +3. Open two Review children with different files/comparisons. Their navigation stays independent; marking a file updates the shared PR baseline in both views. A caught-up view remains on its selected file. +4. Add multiple Research or Preview children, giving each a different query or simulated state. Change outer Tabs / Windows and return between PRs. Child identities, arrangement, progress, drafts, and last-focused view stay with their workspace. +5. Leave while a source, research, or preview is focused, and confirm it returns focused. Separately scroll a review, leave it, and resume it: that child's selected file opens at the top. +6. Close a background child, then the last child. Background closure keeps active focus; an empty workspace retains PR progress and can open another view. + +## Try grouped comparisons and skipping + +1. Reset. Open the file chooser and inspect collapsed quiet groups and their counts. Open Documents → `README.md`, Localization → `Localizable.xcstrings`, and Snapshots/assets → `SearchResults.svg`. Switch Preview / Source without marking anything reviewed. +2. Mark `README.md` reviewed at v1, then simulate a push. Its new edits change only the link target: the rendered prose stays the same, while the target note and source diff expose the edit. Localization and image comparisons also use their own actual reviewed version when available. +3. Reset. Mark `Parser.swift` reviewed, then use Code **Skip 2 remaining** and Snapshots/assets **Skip 2 remaining**. Parser remains reviewed; only Store, Stable, SearchResults, and Design are skipped. +4. Simulate the v2 push. Store and SearchResults return because their contents changed. New `EmptyResults.svg` was never skipped. Unchanged Stable and Design stay skipped. Parser shows edits since its actual v1 review. Counts read **6 remaining · 0 reviewed · 2 skipped**. +5. Undo individual/group skips and confirm they do not create review receipts. Skip the changed Parser at v2: its actual reviewed version stays v1, and Undo restores that incremental comparison. Zero remaining with skips reports the skipped count separately. + +## Close and reopen a workspace + +1. In Search #42, mark a file reviewed, select another review file, save a draft, and open or arrange child views. +2. Use the **×** on Restore #43's outer tab/window. Search keeps its active child. Reopen Restore through **Workspaces**, then switch back to Search. +3. Close Search. Restore becomes active. Close Restore too: the screen has no active workspace and offers **Reopen a workspace**. +4. Reopen Search. Its same child instances, selected files/queries, layout/frames, review/skip receipts, and draft return. The last-focused child returns; a Review starts its selected file at the top. Reopening an already-open entry switches to it without duplication. + +[Exact-source evidence](evidence/workspace-close/verification.json) pins HTML SHA-256 `c99c3a8670006ca787dd5880ff9e04834b777d682f1dca7515688f94c6cad89b`. Eleven focused scenarios pass in each of three sizes × Tabs/Windows; fresh independent review has no findings. Narrow touch/hit and active-drag closure pass; the coordinator also checks Chromium/WebKit at phone/desktop sizes. Twelve author and six independent selected WCAG scans pass. Nine visually inspected captures use PR42 v1 with Parser reviewed, Store selected, a draft saved, and Float; phone uses Tabs, tablet/desktop Windows, light appearance, 1× scale: + +| Viewport | Retained picker | All closed | Reopened context | +| --- | --- | --- | --- | +| 390 × 844 | [Phone picker](evidence/workspace-close/phone-picker.png) | [Empty](evidence/workspace-close/phone-empty.png) | [Store and views](evidence/workspace-close/phone-reopened.png) | +| 834 × 1112 | [Tablet picker](evidence/workspace-close/tablet-picker.png) | [Empty](evidence/workspace-close/tablet-empty.png) | [Store and views](evidence/workspace-close/tablet-reopened.png) | +| 1440 × 1000 | [Desktop picker](evidence/workspace-close/desktop-picker.png) | [Empty](evidence/workspace-close/desktop-empty.png) | [Store and views](evidence/workspace-close/desktop-reopened.png) | + +The workspace remains in memory only; reload/Reset restores the sample. Cross-device open/closed policy is undecided in this experiment. Earlier title-bar/layout/type results below remain historical. User evaluation is pending. + +## Title-bar drag correction + +Drag the filename/title or surrounding header to move a floating view. A stationary click (or less than 5px jitter) keeps the file chooser; a completed drag does not open it. Separate close/focus/source-review buttons retain their actions, as do keyboard movement and resizing. + +The prior handler accepted only the icon. Matching +36/+80px title-text gestures now move the view at all three sizes: [phone before](evidence/iteration-04-drag/phone-before.png)/[after](evidence/iteration-04-drag/phone-after.png), [tablet before](evidence/iteration-04-drag/tablet-before.png)/[after](evidence/iteration-04-drag/tablet-after.png), [desktop before](evidence/iteration-04-drag/desktop-before.png)/[after](evidence/iteration-04-drag/desktop-after.png). Captures use PR42 v1, Float + Tabs, light appearance, 1× scale. Before uses published `7f89c2b5c`; after uses source SHA-256 `3f86c704db285b85cd504a148236aa464016fb37dd92e005256f27cadc98007d`. + +[Focused verification](evidence/iteration-04-drag/verification.json) records three-size pointer/touch, threshold/click, independent-control, cancellation, keyboard/resize, and continuity checks; fresh independent review has no findings. The coordinator's scoped Chromium/WebKit checks also pass. Earlier layout/type evidence below is historical and retained unchanged. User reevaluation remains pending. + +## Layout-options correction + +The user found that selected Float did not match the rendered layout and that outer Windows looked like another form of inner Float. The old width rule silently hid all but one child at 680px or below; switching to Windows created 679px hosts even on a 1440px desktop. Windows also retained the tab-looking PR strip. + +The corrected options distinguish **PR workspaces** from **Views in the named PR**. Explicit Float works at every width, explicit Tile remains non-overlapping (stacked when narrow), and One view is its own selection. Saved normalized placement is fitted for display without rewriting it on a resize; movement starts from the fitted frame so the first drag does not jump. Windows uses separate labeled PR containers and a workspace selector, not a tab strip. These remain simulated browser windows. + +Matched initial PR42 v1 fixtures, light appearance and 1× scale: + +| Case | Before | After | +| --- | --- | --- | +| Phone 390 × 844, Float + Tabs | [One child despite Float](evidence/iteration-04-layout/phone-float-before.png) | [Actual floating views](evidence/iteration-04-layout/phone-float-after.png) | +| Tablet 834 × 1112, Float + Windows | [Silent narrow fallback](evidence/iteration-04-layout/tablet-windows-before.png) | [Distinct PR windows and floating views](evidence/iteration-04-layout/tablet-windows-after.png) | +| Desktop 1440 × 1000, Float + Windows | [Misleading shared tab strip](evidence/iteration-04-layout/desktop-windows-before.png) | [Separate scopes and effective Float](evidence/iteration-04-layout/desktop-windows-after.png) | + +[Scoped options](evidence/iteration-04-layout/desktop-options-after.png), [narrow Tile](evidence/iteration-04-layout/phone-tiles-after.png), and [content in a narrow floating view](evidence/iteration-04-layout/phone-asset-float-after.png) show the other changed states. [Verification](evidence/iteration-04-layout/verification.json) pins source SHA-256 `93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b`. Author checks cover 36 computed combinations; independent review covers 42 including 320px and both sides of the old boundary. Three-size real pointer/keyboard movement, resizing, handle reachability, saved-placement continuity, independent PR frames, focus/review-top return, and empty recovery pass. A requested 4px/6px first drag moved exactly that amount without changing size. The reviewer also exercised narrow touch movement. Fifteen author and twelve independent selected WCAG scans pass with no browser errors. + +This is focused correction evidence. The prior type-fixture matrix below remains historical; its catalog and review/skip/comparison functions are byte-identical, and changed-path continuity/content checks passed. [Iteration 4 before this correction](iteration-04.html) exactly preserves published `e987835f6`. Evaluation of the corrected presentation remains pending. + +## Iteration 4 feature evidence (before layout correction) + +[Verification](evidence/iteration-04/verification.json) pins HTML SHA-256 `fe137ea8e41335bbb0c25a203f6b27aac689bcdb2ce725420a63ab5b50dc8b00`, the checks, capture hashes, and review corrections. Matching v1 full-comparison states use light appearance and 1× scale: + +| Viewport | Grouped list | Documents | Localization | Snapshots/assets | +| --- | --- | --- | --- | --- | +| 1440 × 1000 | [Groups](evidence/iteration-04/desktop-groups.png) | [Markdown](evidence/iteration-04/desktop-documents.png) | [Changed values](evidence/iteration-04/desktop-localization.png) | [Images](evidence/iteration-04/desktop-assets.png) | +| 834 × 1112 | [Groups](evidence/iteration-04/tablet-groups.png) | [Markdown](evidence/iteration-04/tablet-documents.png) | [Changed values](evidence/iteration-04/tablet-localization.png) | [Images](evidence/iteration-04/tablet-assets.png) | +| 390 × 844 | [Groups](evidence/iteration-04/phone-groups.png) | [Markdown](evidence/iteration-04/phone-documents.png) | [Changed values](evidence/iteration-04/phone-localization.png) | [Images](evidence/iteration-04/phone-assets.png) | + +Additional evidence: [skip then push](evidence/iteration-04/desktop-skip-push.png), [unavailable binary](evidence/iteration-04/phone-unavailable.png), and [link-only source edit since review](evidence/iteration-04/phone-document-source.png). The default Code pane retains iteration 3's exact top/height: desktop 203/765px, tablet 203/877px, phone 195/648px. The code-table top is measured separately from the first table row, whose collapsed border extends one pixel above it. + +Complete prior workspace scenarios and new grouping/skip/type scenarios passed at all three sizes with Playwright 1.64.1 / Chromium 156.0.8078.4. Checks cover independent child files/queries/format/expansion, shared PR review and skip receipts, drafts, layout/focus return, review file-top resumption, new/changed/unchanged work, group membership snapshots, raw/rich basis agreement, link-only edits, missing binary content, and explicit absent-before images. Thirteen WCAG 2/2.1 A/AA axe states per size passed; no page/console/load errors, external requests, or document overflow occurred. Standalone file loading also passes. + +Fresh independent review found and rechecked the individual Skip accessible-name mismatch and an object-size field mislabeled as pointer size. The corrected label was shortened to keep narrow tablet metadata readable; source views now explicitly identify pointer-only content. Group action labels include visible counts and “remaining.” No actionable findings remain. Unfiltered axe also reports inherited best-practice heading/landmark warnings outside the selected WCAG tags; these scans are not a complete accessibility or VoiceOver audit. + +The two user-facing revisions prove v1 skip → changed/new v2 return, unchanged skip persistence, and reviewed-v1 → skipped-v2 baseline retention. A separate seeded policy assertion verifies that a later changed content identity selects the actual v1 review basis; it does not render or claim a third UI revision. All checks are ad hoc evidence, not retained CI guards. Default web lint excludes this HTML; native tests/snapshots and SwiftFormat are outside this slice. Fourth-round user evaluation remains pending in [plan 01a](../01a-workspace-prototype.md). + +## Iteration 3 evidence (historical) + +The same initial Parser comparison was rendered before/after at matching viewports, light appearance, and 1× scale. The post-push incremental comparison was measured separately and has the same pane geometry. Measurements below are rounded to the nearest CSS pixel; [verification.json](evidence/iteration-03/verification.json) retains exact scroll-pane top/height and first-code-row top values. + +| Viewport | Review pane height, before → after | First code-row top, before → after | Matched captures | +| --- | --- | --- | --- | +| 1440 × 1000 | 413 → 765 | 525 → 203 | [Before](evidence/iteration-03/desktop-before.png), [after](evidence/iteration-03/desktop-after.png) | +| 834 × 1112 | 535 → 877 | 515 → 203 | [Before](evidence/iteration-03/tablet-before.png), [after](evidence/iteration-03/tablet-after.png) | +| 390 × 844 | 216 → 648 | 568 → 195 | [Before](evidence/iteration-03/phone-before.png), [after](evidence/iteration-03/phone-after.png) | + +Code text increased from 10px to 12px. Visible buttons in the initial phone state measure at least 44 × 44px. The gain comes from removing repeated bands and disclosing secondary controls. + +Additional captures: [phone new edits](evidence/iteration-03/phone-incremental.png), [workspace windows](evidence/iteration-03/desktop-windows.png), [tablet float](evidence/iteration-03/tablet-float.png), [phone preview](evidence/iteration-03/phone-preview.png), and [workspace options](evidence/iteration-03/phone-options.png). + +Complete browser scenarios passed at all three sizes using Playwright 1.64.1 / Chromium 156.0.8078.4. They cover independent child navigation, shared PR progress, outer presentation, arrangement/focus restoration, review file-top resumption, remaining/full comparisons, drafts, source-to-review, preview states, add/close/recovery, and Reset. Relocated controls were exercised by pointer/touch and keyboard, including Escape/focus return and Canvas changes. Five checked states per size had zero axe WCAG 2/2.1 A/AA violations; no page/console/load errors, external requests, or document overflow occurred. + +Fresh independent review rechecked last-child dialog focus recovery, title accessible names, and immediate dialog reopening. The native close event is queued: a stale event must not dismiss a newly opened dialog. Five immediate close → reopen → Research → Enter trials passed. Floating children are contained beneath prototype controls; those controls stayed reachable after 40 view raises. Standalone file loading, inline JavaScript syntax, archive byte identity, local links, and diff whitespace also passed. + +The checks are ad hoc browser evidence, not retained CI tests. Default repository web lint globs do not cover this HTML. Native tests, snapshots, and SwiftFormat are outside this browser-only slice. Automated accessibility scans do not establish VoiceOver or a complete accessibility audit. The third user evaluation requested the grouped-kind and explicit-skip iteration above. + +## Boundaries and retained history + +Two synthetic PRs and two prepared revisions keep the study bounded. Each PR has seven changed files at v1 and eight at v2, plus one supporting source file. Typed previews and diffs are deterministic prepared fixtures; they do not parse real Markdown/catalogs or fetch LFS objects. Reading, navigation, presentation, and view creation never mark files reviewed. Drafts are private session notes; nothing is submitted. “Fork” was clarified as “view,” so there is no editing, cloning, or fork feature. + +Prepared comparisons do not implement Git or compilable app code. There is no authentication, backend, durable storage, real OS windowing, execution, provider integration, or device sync. The mockup state schema is not a production schema. + +- [Iteration 1](iteration-01.html) exactly preserves [revision `2e3653877`](https://github.com/kyleve/Stuff/blob/2e3653877bf141964805d417eac0b94c03a24c6a/Plans/2026-11-14-mobius/Prototype/index.html), its [verification record](evidence/verification.json), and original captures. The user found that it flattened a workspace into a document-tab group. +- [Iteration 2](iteration-02.html) exactly preserves [revision `e1c1059cf28`](https://github.com/kyleve/Stuff/blob/e1c1059cf28a2954a0513d2514e7d0b7be9c34dd/Plans/2026-11-14-mobius/Prototype/index.html) and its [separate evidence](evidence/iteration-02/verification.json). The user found the revised ownership model improved but requested less stacked chrome, leading to iteration 3. + +- [Iteration 3](iteration-03.html) exactly preserves [revision `58c13ac56`](https://github.com/kyleve/Stuff/blob/58c13ac56f87688548887172fef6f39e818bc819/Plans/2026-11-14-mobius/Prototype/index.html) and its [separate evidence](evidence/iteration-03/verification.json). The user then requested grouped kinds and explicit skip/resurfacing, leading to iteration 4. + +- [Iteration 4 before the layout correction](iteration-04.html) preserves [revision `e987835f6`](https://github.com/kyleve/Stuff/blob/e987835f6a1dd18463eceaf8274673c8445036d5/Plans/2026-11-14-mobius/Prototype/index.html) and its grouped-content/skip evidence. User feedback then required selected layouts to match actual rendering, including Float at narrow widths. + +Earlier evidence remains historical; it does not validate the changed controls or establish native product acceptance. diff --git a/Plans/2026-11-14-mobius/Prototype/astro.config.mjs b/Plans/2026-11-14-mobius/Prototype/astro.config.mjs new file mode 100644 index 000000000..93aea7bf1 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/astro.config.mjs @@ -0,0 +1,16 @@ +import { fileURLToPath } from 'node:url'; +import { defineConfig } from 'astro/config'; + +const projectDirectory = fileURLToPath(new URL('.', import.meta.url)); + +export default defineConfig({ + output: 'static', + devToolbar: { enabled: false }, + vite: { + cacheDir: fileURLToPath(new URL('./.astro/vite/', import.meta.url)), + server: { + strictPort: true, + fs: { allow: [projectDirectory] }, + }, + }, +}); diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/desktop-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/desktop-after.png new file mode 100644 index 000000000..d5d2c9c6b Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/desktop-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/desktop-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/desktop-before.png new file mode 100644 index 000000000..d5d2c9c6b Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/desktop-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/desktop-review.png b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/desktop-review.png new file mode 100644 index 000000000..1dfc379af Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/desktop-review.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/phone-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/phone-after.png new file mode 100644 index 000000000..4aa6be95d Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/phone-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/phone-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/phone-before.png new file mode 100644 index 000000000..4aa6be95d Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/phone-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/phone-review.png b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/phone-review.png new file mode 100644 index 000000000..9bbfa85a1 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/phone-review.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/tablet-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/tablet-after.png new file mode 100644 index 000000000..3ea34686e Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/tablet-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/tablet-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/tablet-before.png new file mode 100644 index 000000000..3ea34686e Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/tablet-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/tablet-review.png b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/tablet-review.png new file mode 100644 index 000000000..bdd96327c Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/tablet-review.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/verification.json b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/verification.json new file mode 100644 index 000000000..fd4e0ddd3 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/evidence/astro-dev/verification.json @@ -0,0 +1,523 @@ +{ + "date": "2026-11-15", + "scope": "Astro development delivery of the existing Mobius prototype; no UI/state behavior changes", + "baseCommit": "12e48303ab3d223337ad2ae5d7d132adf81835c3", + "sourceHashes": { + "src/pages/index.astro": "06655f89112e163387eab452f15a042e0e7e00a92cab6f172e5dc4b6fcb0d2cd", + "src/styles.css": "4dcaeb7e65ffb9469d740184816ed6249cff16f0f5be7753dd5aac9b83241282", + "src/app.js": "b408a27a20c30eb906b2fe76b081c73e5e3d58c1f0ae9f5080a299d7d157cf7f", + "astro.config.mjs": "f571509021660dd59178e4e6563c286d35a00effda47d62a2fbd833ba97ad064", + "tsconfig.json": "e4d8f9bd5c6852a50b0dec674d102995d61499fdd66d3ca4995c8e35e0f0299f" + }, + "retention": { + "localLinksAndAnchors": 332, + "markdownFences": "pass", + "archiveMatchesPublishedSHA256": "c99c3a8670006ca787dd5880ff9e04834b777d682f1dca7515688f94c6cad89b", + "extractedClientIdentical": true, + "extractedStylesMatchExceptTrailingBlankLine": true, + "priorArchivesAndEvidenceUntouched": true, + "initialCaptureBytesIdentical": { + "phone": true, + "tablet": true, + "desktop": true + }, + "captureHashes": { + "desktop-after.png": "fa44ce9471319e5f782cfaa0c021bb5d12a930e784ca7af712bb0b8ddbe96e77", + "phone-after.png": "5b8adf25d10c3c39b718fe53ce068b83e49471e7847ebc7fb2bfa95b9fc95637", + "phone-review.png": "1a16bc35749aa776f8430efc23c5a0dc2f3484cccb8a1c586257ea09c038862c", + "phone-before.png": "5b8adf25d10c3c39b718fe53ce068b83e49471e7847ebc7fb2bfa95b9fc95637", + "tablet-review.png": "d1554eaa051a00ded7d8e47493a9f0b7b868fc1268ac980e85da84bcba051a69", + "desktop-review.png": "3c62f5da71aedc493b001f9d3a4c30b5dc1b6c291e935bfcc2b3f32dcabc69c0", + "tablet-after.png": "0a3deb76f44d571484458fffa6df90b239447b54c4545ccc6eb5714138e039a5", + "tablet-before.png": "0a3deb76f44d571484458fffa6df90b239447b54c4545ccc6eb5714138e039a5", + "desktop-before.png": "fa44ce9471319e5f782cfaa0c021bb5d12a930e784ca7af712bb0b8ddbe96e77" + } + }, + "toolchain": { + "node": "24.22.0", + "astro": "7.4.0", + "playwright": "1.64.1", + "axe": "4.14.0" + }, + "commands": { + "root": "prototype_dir=\"$PWD/Plans/2026-11-14-mobius/Prototype\" (from repository root)", + "start": "ASTRO_TELEMETRY_DISABLED=1 mise exec -- node_modules/.bin/astro dev --root \"$prototype_dir\" --host 0.0.0.0 --port 4321 --background", + "status": "ASTRO_TELEMETRY_DISABLED=1 mise exec -- node_modules/.bin/astro dev status --root \"$prototype_dir\"", + "logs": "ASTRO_TELEMETRY_DISABLED=1 mise exec -- node_modules/.bin/astro dev logs --root \"$prototype_dir\"", + "stop": "ASTRO_TELEMETRY_DISABLED=1 mise exec -- node_modules/.bin/astro dev stop --root \"$prototype_dir\"", + "check": "ASTRO_TELEMETRY_DISABLED=1 mise exec -- node_modules/.bin/astro check --root \"$prototype_dir\"", + "build": "ASTRO_TELEMETRY_DISABLED=1 mise exec -- node_modules/.bin/astro build --root \"$prototype_dir\"" + }, + "staticChecks": { + "astroCheck": "4 files; 0 errors/warnings/hints", + "astroBuild": "1 static route; successful bundled JS/CSS output", + "eslint": "Explicit src/pages/index.astro and astro.config.mjs; pass", + "javascriptSyntax": "node --check src/app.js; pass", + "whitespace": "git diff --cached --check after staging all new sources; pass (original inline-style separator blank line removed)", + "devFilesystemBoundary": "request for root AGENTS.md through @fs returns403", + "dependencyAndConfigScope": "No root package/lock/config/Tools changes or added dependency tree; generated .astro/dist ignored" + }, + "liveUpdate": { + "url": "machine LAN IPv4 on port 4321 (tested from host)", + "engine": "156.0.8078.4", + "css": { + "mode": "HMR", + "sessionPreserved": true, + "restored": true + }, + "markup": { + "mode": "full reload", + "sessionReset": true, + "restored": true + }, + "script": { + "mode": "full reload", + "sessionReset": true, + "restored": true + }, + "noDuplicateHandlers": true, + "viteEvents": [ + "connected", + "update", + "update", + "full-reload", + "full-reload", + "connected", + "full-reload", + "full-reload", + "connected", + "full-reload", + "connected", + "full-reload", + "connected" + ], + "errors": [], + "sourceHashes": { + "src/pages/index.astro": "06655f89112e163387eab452f15a042e0e7e00a92cab6f172e5dc4b6fcb0d2cd", + "src/styles.css": "4dcaeb7e65ffb9469d740184816ed6249cff16f0f5be7753dd5aac9b83241282", + "src/app.js": "b408a27a20c30eb906b2fe76b081c73e5e3d58c1f0ae9f5080a299d7d157cf7f" + } + }, + "author": [ + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "checks": [ + "real Astro module/CSS route renders original initial session", + "review/skip/draft plus independently owned new search and second simulated preview", + "inactive and last workspace closure, all-closed presentation changes, same child IDs/layout/focus/queries/draft/skip on reopen", + "push resurfaces skipped unreviewed file with full diff and reviewed file from actual v1; full/remaining does not advance receipt", + "prepared Documents and Localization previews/source remain available through served module", + "exact filename drag and stationary chooser, keyboard move and resize after migration", + "independent child navigation and non-review focus survive PR return", + "resumed review selected file starts at top and keeps its true comparison" + ], + "audits": [ + { + "state": "initial served", + "violations": [] + }, + { + "state": "restored review", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "checks": [ + "real Astro module/CSS route renders original initial session", + "review/skip/draft plus independently owned new search and second simulated preview", + "inactive and last workspace closure, all-closed presentation changes, same child IDs/layout/focus/queries/draft/skip on reopen", + "push resurfaces skipped unreviewed file with full diff and reviewed file from actual v1; full/remaining does not advance receipt", + "prepared Documents and Localization previews/source remain available through served module", + "exact filename drag and stationary chooser, keyboard move and resize after migration", + "independent child navigation and non-review focus survive PR return", + "resumed review selected file starts at top and keeps its true comparison" + ], + "audits": [ + { + "state": "initial served", + "violations": [] + }, + { + "state": "restored review", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "checks": [ + "real Astro module/CSS route renders original initial session", + "review/skip/draft plus independently owned new search and second simulated preview", + "inactive and last workspace closure, all-closed presentation changes, same child IDs/layout/focus/queries/draft/skip on reopen", + "push resurfaces skipped unreviewed file with full diff and reviewed file from actual v1; full/remaining does not advance receipt", + "prepared Documents and Localization previews/source remain available through served module", + "exact filename drag and stationary chooser, keyboard move and resize after migration", + "independent child navigation and non-review focus survive PR return", + "resumed review selected file starts at top and keeps its true comparison" + ], + "audits": [ + { + "state": "initial served", + "violations": [] + }, + { + "state": "restored review", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + } + ], + "independentReview": { + "sourceHashes": { + "src/pages/index.astro": "06655f89112e163387eab452f15a042e0e7e00a92cab6f172e5dc4b6fcb0d2cd", + "src/styles.css": "e459575d9ede85e6d58024ce82f1405cfd76ca97fca10330a1c6bd0f753e7447", + "src/app.js": "b408a27a20c30eb906b2fe76b081c73e5e3d58c1f0ae9f5080a299d7d157cf7f", + "astro.config.mjs": "f571509021660dd59178e4e6563c286d35a00effda47d62a2fbd833ba97ad064", + "tsconfig.json": "e4d8f9bd5c6852a50b0dec674d102995d61499fdd66d3ca4995c8e35e0f0299f" + }, + "reports": [ + { + "engine": "Chromium", + "version": "156.0.8078.4", + "size": { + "name": "phone", + "width": 390, + "height": 844 + }, + "target": "dev", + "checks": [ + "processed client initializes once with correct dev/build assets and no global test state", + "close/reopen retains child identities, research query/focus, Float, review receipt and draft", + "actual reviewed basis, unreviewed full diff, skip/undo remain truthful", + "filename drag moves exact frame and stationary click retains chooser" + ], + "errors": [], + "documentOverflow": false + }, + { + "engine": "Chromium", + "version": "156.0.8078.4", + "size": { + "name": "phone", + "width": 390, + "height": 844 + }, + "target": "build", + "checks": [ + "processed client initializes once with correct dev/build assets and no global test state", + "close/reopen retains child identities, research query/focus, Float, review receipt and draft", + "actual reviewed basis, unreviewed full diff, skip/undo remain truthful", + "filename drag moves exact frame and stationary click retains chooser" + ], + "errors": [], + "documentOverflow": false + }, + { + "engine": "Chromium", + "version": "156.0.8078.4", + "size": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "target": "dev", + "checks": [ + "processed client initializes once with correct dev/build assets and no global test state", + "close/reopen retains child identities, research query/focus, Float, review receipt and draft", + "actual reviewed basis, unreviewed full diff, skip/undo remain truthful", + "filename drag moves exact frame and stationary click retains chooser" + ], + "errors": [], + "documentOverflow": false + }, + { + "engine": "Chromium", + "version": "156.0.8078.4", + "size": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "target": "dev", + "checks": [ + "processed client initializes once with correct dev/build assets and no global test state", + "close/reopen retains child identities, research query/focus, Float, review receipt and draft", + "actual reviewed basis, unreviewed full diff, skip/undo remain truthful", + "filename drag moves exact frame and stationary click retains chooser" + ], + "errors": [], + "documentOverflow": false + }, + { + "engine": "Chromium", + "version": "156.0.8078.4", + "size": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "target": "build", + "checks": [ + "processed client initializes once with correct dev/build assets and no global test state", + "close/reopen retains child identities, research query/focus, Float, review receipt and draft", + "actual reviewed basis, unreviewed full diff, skip/undo remain truthful", + "filename drag moves exact frame and stationary click retains chooser" + ], + "errors": [], + "documentOverflow": false + }, + { + "engine": "WebKit", + "version": "27.2", + "size": { + "name": "phone", + "width": 390, + "height": 844 + }, + "target": "dev", + "checks": [ + "processed client initializes once with correct dev/build assets and no global test state", + "close/reopen retains child identities, research query/focus, Float, review receipt and draft", + "actual reviewed basis, unreviewed full diff, skip/undo remain truthful", + "filename drag moves exact frame and stationary click retains chooser" + ], + "errors": [], + "documentOverflow": false + }, + { + "engine": "WebKit", + "version": "27.2", + "size": { + "name": "phone", + "width": 390, + "height": 844 + }, + "target": "build", + "checks": [ + "processed client initializes once with correct dev/build assets and no global test state", + "close/reopen retains child identities, research query/focus, Float, review receipt and draft", + "actual reviewed basis, unreviewed full diff, skip/undo remain truthful", + "filename drag moves exact frame and stationary click retains chooser" + ], + "errors": [], + "documentOverflow": false + }, + { + "engine": "WebKit", + "version": "27.2", + "size": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "target": "dev", + "checks": [ + "processed client initializes once with correct dev/build assets and no global test state", + "close/reopen retains child identities, research query/focus, Float, review receipt and draft", + "actual reviewed basis, unreviewed full diff, skip/undo remain truthful", + "filename drag moves exact frame and stationary click retains chooser" + ], + "errors": [], + "documentOverflow": false + }, + { + "engine": "WebKit", + "version": "27.2", + "size": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "target": "dev", + "checks": [ + "processed client initializes once with correct dev/build assets and no global test state", + "close/reopen retains child identities, research query/focus, Float, review receipt and draft", + "actual reviewed basis, unreviewed full diff, skip/undo remain truthful", + "filename drag moves exact frame and stationary click retains chooser" + ], + "errors": [], + "documentOverflow": false + }, + { + "engine": "WebKit", + "version": "27.2", + "size": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "target": "build", + "checks": [ + "processed client initializes once with correct dev/build assets and no global test state", + "close/reopen retains child identities, research query/focus, Float, review receipt and draft", + "actual reviewed basis, unreviewed full diff, skip/undo remain truthful", + "filename drag moves exact frame and stationary click retains chooser" + ], + "errors": [], + "documentOverflow": false + } + ], + "reviewedBase": "12e48303ab3d223337ad2ae5d7d132adf81835c3", + "scope": "Uncommitted Astro migration only; inherited prototype behavior preserved", + "findings": [], + "extraction": { + "archiveMatchesBase": true, + "clientJavaScriptByteIdentical": true, + "globalCSSByteIdentical": true, + "pageEqualsMechanicalExtraction": true + }, + "staticChecks": { + "scopedESLint": "pass: Astro route and config", + "clientSyntax": "pass", + "whitespace": "pass", + "ignoredOutputAndCache": "confirmed" + }, + "lifecycle": { + "reviewOwnedPreview": "started on loopback4322 and stopped via native Astro preview stop", + "authorDevServer": "left running PID7013 port4321", + "outsideProjectNonSecretFile": "@fs repository AGENTS.md returns403" + }, + "limits": [ + "Actual phone Wi-Fi path not tested.", + "Astro check has allowJs but not checkJs; root lint scripts do not select the prototype. Client JS receives syntax/build/runtime coverage, not new type-aware lint.", + "No source mutation was performed by reviewer. HMR proof is author-run evidence inspected against unchanged final source hashes.", + "WebKit mouse closure after typing in Research moves DOM focus to body while logical focused child persists. The identical behavior was reproduced in standalone archive, dev and build. Keyboard last-close recovery and explicit reopen focus pass; this is an unchanged browser-focus limit, not an actionable Astro migration regression." + ], + "finalRecheck": { + "sourceHashes": { + "src/pages/index.astro": "06655f89112e163387eab452f15a042e0e7e00a92cab6f172e5dc4b6fcb0d2cd", + "src/styles.css": "4dcaeb7e65ffb9469d740184816ed6249cff16f0f5be7753dd5aac9b83241282", + "src/app.js": "b408a27a20c30eb906b2fe76b081c73e5e3d58c1f0ae9f5080a299d7d157cf7f", + "astro.config.mjs": "f571509021660dd59178e4e6563c286d35a00effda47d62a2fbd833ba97ad064", + "tsconfig.json": "e4d8f9bd5c6852a50b0dec674d102995d61499fdd66d3ca4995c8e35e0f0299f" + }, + "delta": "Removed exactly one trailing newline from extracted styles.css (the old closing-style-block separator); every other reviewed source hash is unchanged.", + "checks": [ + "Direct byte equality: final CSS equals reviewed CSS minus exactly one final newline.", + "CSS declarations and tokenization are unchanged; no runtime path or selector changes.", + "git diff --check passes." + ], + "disposition": "No actionable findings. Prior 10-case runtime record retains its original source hashes; this mechanical-only equivalence recheck establishes applicability to final sources without claiming another broad run." + } + }, + "coordinator": { + "sourceHashes": { + "astro.config.mjs": "f571509021660dd59178e4e6563c286d35a00effda47d62a2fbd833ba97ad064", + "tsconfig.json": "e4d8f9bd5c6852a50b0dec674d102995d61499fdd66d3ca4995c8e35e0f0299f", + "src/pages/index.astro": "06655f89112e163387eab452f15a042e0e7e00a92cab6f172e5dc4b6fcb0d2cd", + "src/styles.css": "4dcaeb7e65ffb9469d740184816ed6249cff16f0f5be7753dd5aac9b83241282", + "src/app.js": "b408a27a20c30eb906b2fe76b081c73e5e3d58c1f0ae9f5080a299d7d157cf7f" + }, + "reports": [ + { + "engine": "Chromium", + "version": "156.0.8078.4", + "name": "phone-lan", + "viewport": { + "width": 390, + "height": 844 + }, + "checks": "HTTP-served initialization, no dev toolbar, reviewed marker, draft and child identity retention, inactive/last closure, all-closed presentation switch, reopening, review file-top, title-text drag and stationary chooser, second PR reopening and active closure", + "errors": [], + "target": "machine LAN IPv4" + }, + { + "engine": "Chromium", + "version": "156.0.8078.4", + "name": "desktop-local", + "viewport": { + "width": 1440, + "height": 1000 + }, + "checks": "HTTP-served initialization, no dev toolbar, reviewed marker, draft and child identity retention, inactive/last closure, all-closed presentation switch, reopening, review file-top, title-text drag and stationary chooser, second PR reopening and active closure", + "errors": [], + "target": "localhost" + }, + { + "engine": "WebKit", + "version": "27.2", + "name": "phone-lan", + "viewport": { + "width": 390, + "height": 844 + }, + "checks": "HTTP-served initialization, no dev toolbar, reviewed marker, draft and child identity retention, inactive/last closure, all-closed presentation switch, reopening, review file-top, title-text drag and stationary chooser, second PR reopening and active closure", + "errors": [], + "target": "machine LAN IPv4" + }, + { + "engine": "WebKit", + "version": "27.2", + "name": "desktop-local", + "viewport": { + "width": 1440, + "height": 1000 + }, + "checks": "HTTP-served initialization, no dev toolbar, reviewed marker, draft and child identity retention, inactive/last closure, all-closed presentation switch, reopening, review file-top, title-text drag and stationary chooser, second PR reopening and active closure", + "errors": [], + "target": "localhost" + } + ], + "limits": [ + "Read-only served UI checks; HMR edit/revert evidence belongs to the implementation worker.", + "LAN address was reached from the host, not a physical phone." + ] + }, + "captures": { + "description": "Initial PR42v1 before/after: light,1x; phone390x844 One view, tablet834x1112 and desktop1440x1000 Tile. Each matched PNG pair is byte-identical. Review captures show post-push v2 Parser incremental from marked v1 in One view with draft retained.", + "visuallyInspected": true, + "hashes": { + "desktop-after.png": "fa44ce9471319e5f782cfaa0c021bb5d12a930e784ca7af712bb0b8ddbe96e77", + "phone-after.png": "5b8adf25d10c3c39b718fe53ce068b83e49471e7847ebc7fb2bfa95b9fc95637", + "phone-review.png": "1a16bc35749aa776f8430efc23c5a0dc2f3484cccb8a1c586257ea09c038862c", + "phone-before.png": "5b8adf25d10c3c39b718fe53ce068b83e49471e7847ebc7fb2bfa95b9fc95637", + "tablet-review.png": "d1554eaa051a00ded7d8e47493a9f0b7b868fc1268ac980e85da84bcba051a69", + "desktop-review.png": "3c62f5da71aedc493b001f9d3a4c30b5dc1b6c291e935bfcc2b3f32dcabc69c0", + "tablet-after.png": "0a3deb76f44d571484458fffa6df90b239447b54c4545ccc6eb5714138e039a5", + "tablet-before.png": "0a3deb76f44d571484458fffa6df90b239447b54c4545ccc6eb5714138e039a5", + "desktop-before.png": "fa44ce9471319e5f782cfaa0c021bb5d12a930e784ca7af712bb0b8ddbe96e77" + } + }, + "serverHandoff": { + "owner": "mobius_prototype task", + "nativeBackgroundPID": 7013, + "port": 4321, + "bind": "0.0.0.0", + "intentionalRunningAtHandoff": true, + "temporaryReviewerPreviewStopped": true, + "actualPhoneWiFiTested": false + }, + "workflowPR": "https://github.com/kyleve/Stuff/pull/503", + "limits": [ + "All runtime probes used isolated synthetic browser contexts; no user browser was controlled.", + "Actual phone Wi-Fi, native iPhone/iPad/macOS and cross-device sync are not validated.", + "Full page reload deliberately resets sample session; CSS HMR preserves it.", + "Root default web lint excludes this prototype; explicit Astro/config lint, check/build, unchanged-script syntax and browser checks were used.", + "Runtime probes are ad hoc evidence, not retained CI guards.", + "WebKit mouse-closing an inactive workspace after typing in Research can move DOM focus to body while logical child focus remains; reproduced identically in archive/dev/build. Keyboard recovery and retained child context pass; this is unchanged behavior, not a migration finding.", + "User evaluation remains pending; this tooling follow-up does not complete experiment acceptance." + ] +} diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/desktop.png b/Plans/2026-11-14-mobius/Prototype/evidence/desktop.png new file mode 100644 index 000000000..045b878d6 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/desktop.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/desktop-tiles.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/desktop-tiles.png new file mode 100644 index 000000000..22623a304 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/desktop-tiles.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/desktop-windows.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/desktop-windows.png new file mode 100644 index 000000000..759efd5d5 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/desktop-windows.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/phone-preview.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/phone-preview.png new file mode 100644 index 000000000..ebe3b298d Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/phone-preview.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/tablet-float.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/tablet-float.png new file mode 100644 index 000000000..48ee75b7a Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/tablet-float.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/verification.json b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/verification.json new file mode 100644 index 000000000..29164955e --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-02/verification.json @@ -0,0 +1,112 @@ +{ + "date": "2026-11-14", + "iteration": 2, + "artifact": "../../index.html", + "sha256": "78aa083a6350417961967a75ef26788c734b9e3f445d39abbb16e262ec9e3a8b", + "firstPass": { + "revision": "2e3653877bf141964805d417eac0b94c03a24c6a", + "archive": "../../iteration-01.html", + "sha256": "9268a1a8fb1207844b305880821fc9dfe3978c6042157383e0cdd81b007cd2d2", + "byteIdentityVerified": true + }, + "tooling": { + "playwright": "1.64.1", + "chromium": "156.0.8078.4", + "axePlaywright": "4.14.0" + }, + "method": "Playwright interactions through visible controls, pointer/touch taps, keyboard and rendered view identity/geometry; synthetic fixtures only.", + "viewports": [ + { + "name": "desktop", + "width": 1440, + "height": 1000, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "initial tiles", + "violations": [] + }, + { + "state": "post-push shared progress and saved draft", + "violations": [] + }, + { + "state": "reopened empty workspace", + "violations": [] + } + ] + }, + { + "name": "tablet", + "width": 834, + "height": 1112, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "initial tiles", + "violations": [] + }, + { + "state": "post-push shared progress and saved draft", + "violations": [] + }, + { + "state": "reopened empty workspace", + "violations": [] + } + ] + }, + { + "name": "phone", + "width": 390, + "height": 844, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "initial tiles", + "violations": [] + }, + { + "state": "post-push shared progress and saved draft", + "violations": [] + }, + { + "state": "reopened empty workspace", + "violations": [] + } + ] + } + ], + "additionalPassedChecks": [ + "Standalone file URL load and mark-reviewed interaction", + "Focused compact child selector remains visible after creation, rendering, PR return and presentation changes (one pixel fractional-scroll tolerance)", + "Fresh independent phone and desktop review, including five immediate Research creation/type/Enter trials", + "Final inline JavaScript syntax, local links/anchors, and diff whitespace" + ], + "independentReview": { + "disposition": "No actionable findings remain", + "sourceSha256": "78aa083a6350417961967a75ef26788c734b9e3f445d39abbb16e262ec9e3a8b", + "correctedFindings": [ + "Focused floating view stays frontmost", + "Closing background and inactive-workspace children preserves active focus", + "Closing the final child focuses New view", + "Simulated preview scroll region is keyboard-focusable", + "Search Enter submission retains its form; text input changes do not trigger select-control rendering", + "Modal dismissal finishes before queued close callbacks", + "Compact selected child stays visible in the selector" + ] + }, + "limits": [ + "Second user evaluation pending", + "Browser shells and previews are simulated", + "No native platform or VoiceOver validation", + "No editing, code execution, persistence, provider, real Git or sync validation", + "Axe scans are not a complete accessibility audit" + ] +} diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/desktop-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/desktop-after.png new file mode 100644 index 000000000..e039a42cc Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/desktop-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/desktop-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/desktop-before.png new file mode 100644 index 000000000..22623a304 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/desktop-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/desktop-windows.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/desktop-windows.png new file mode 100644 index 000000000..785173b96 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/desktop-windows.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-after.png new file mode 100644 index 000000000..ee84ed895 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-before.png new file mode 100644 index 000000000..50cfa3ee4 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-incremental.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-incremental.png new file mode 100644 index 000000000..411b0b828 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-incremental.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-options.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-options.png new file mode 100644 index 000000000..f178c0570 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-options.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-preview.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-preview.png new file mode 100644 index 000000000..53f4cda52 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/phone-preview.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/tablet-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/tablet-after.png new file mode 100644 index 000000000..9065d4b28 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/tablet-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/tablet-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/tablet-before.png new file mode 100644 index 000000000..d11d4be1d Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/tablet-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/tablet-float.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/tablet-float.png new file mode 100644 index 000000000..5ba4413c0 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/tablet-float.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/verification.json b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/verification.json new file mode 100644 index 000000000..40ea789e5 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-03/verification.json @@ -0,0 +1,324 @@ +{ + "iteration": 3, + "verifiedDate": "2026-11-14", + "artifact": "index.html", + "artifactSHA256": "f2adc670df7668d0c99d79f3ac0d9abeea3df701f56a53e1373de331c2eb274f", + "beforeArtifact": { + "path": "iteration-02.html", + "commit": "e1c1059cf28a2954a0513d2514e7d0b7be9c34dd", + "sha256": "78aa083a6350417961967a75ef26788c734b9e3f445d39abbb16e262ec9e3a8b" + }, + "toolchain": { + "playwright": "1.64.1", + "chromium": "156.0.8078.4", + "axe": "4.14.0" + }, + "method": { + "fixtures": "Initial PR42 Parser full comparison and Parser marked v1 followed by simulated v2 push. Matched viewport, light appearance, deviceScaleFactor 1.", + "metrics": "CSS pixels. paneTop/paneHeight measure the scroll container; firstCodeTop measures the code table, separately from earlier iteration metadata inside the pane.", + "checks": "Ad hoc browser automation; scripts are not retained CI guards.", + "commands": [ + "mise exec -- node /tmp/mobius-v3-verify.cjs", + "mise exec -- node /tmp/mobius-v3-before.cjs", + "mise exec -- node /tmp/mobius-v3-captures.cjs", + "mise exec -- node /tmp/mobius-v3-standalone.cjs", + "mise exec -- node --check /tmp/mobius-v3-inline.js" + ] + }, + "before": [ + { + "name": "desktop", + "width": 1440, + "height": 1000, + "initial": { + "paneTop": 490, + "paneHeight": 413, + "firstCodeTop": 525, + "codeFontSize": "10px" + }, + "incremental": { + "paneTop": 490, + "paneHeight": 413, + "firstCodeTop": 525, + "codeFontSize": "10px" + } + }, + { + "name": "tablet", + "width": 834, + "height": 1112, + "initial": { + "paneTop": 480.09375, + "paneHeight": 534.90625, + "firstCodeTop": 515.09375, + "codeFontSize": "10px" + }, + "incremental": { + "paneTop": 480.09375, + "paneHeight": 534.90625, + "firstCodeTop": 515.09375, + "codeFontSize": "10px" + } + }, + { + "name": "phone", + "width": 390, + "height": 844, + "initial": { + "paneTop": 532.59375, + "paneHeight": 216.40625, + "firstCodeTop": 567.59375, + "codeFontSize": "10px" + }, + "incremental": { + "paneTop": 532.59375, + "paneHeight": 216.40625, + "firstCodeTop": 567.59375, + "codeFontSize": "10px" + } + } + ], + "after": [ + { + "name": "desktop", + "width": 1440, + "height": 1000, + "initial": { + "paneTop": 203, + "paneHeight": 765, + "firstCodeTop": 203, + "codeFontSize": "12px" + }, + "incremental": { + "paneTop": 203, + "paneHeight": 765, + "firstCodeTop": 203, + "codeFontSize": "12px" + } + }, + { + "name": "tablet", + "width": 834, + "height": 1112, + "initial": { + "paneTop": 203, + "paneHeight": 877, + "firstCodeTop": 203, + "codeFontSize": "12px" + }, + "incremental": { + "paneTop": 203, + "paneHeight": 877, + "firstCodeTop": 203, + "codeFontSize": "12px" + } + }, + { + "name": "phone", + "width": 390, + "height": 844, + "initial": { + "paneTop": 195, + "paneHeight": 648, + "firstCodeTop": 195, + "codeFontSize": "12px" + }, + "incremental": { + "paneTop": 195, + "paneHeight": 648, + "firstCodeTop": 195, + "codeFontSize": "12px" + } + } + ], + "scenarios": [ + { + "name": "desktop", + "width": 1440, + "height": 1000, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "initial compact chrome", + "violations": [] + }, + { + "state": "workspace disclosure", + "violations": [] + }, + { + "state": "prototype controls", + "violations": [] + }, + { + "state": "post-push shared progress and saved draft", + "violations": [] + }, + { + "state": "reopened empty workspace", + "violations": [] + } + ] + }, + { + "name": "tablet", + "width": 834, + "height": 1112, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "initial compact chrome", + "violations": [] + }, + { + "state": "workspace disclosure", + "violations": [] + }, + { + "state": "prototype controls", + "violations": [] + }, + { + "state": "post-push shared progress and saved draft", + "violations": [] + }, + { + "state": "reopened empty workspace", + "violations": [] + } + ] + }, + { + "name": "phone", + "width": 390, + "height": 844, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "initial compact chrome", + "violations": [] + }, + { + "state": "workspace disclosure", + "violations": [] + }, + { + "state": "prototype controls", + "violations": [] + }, + { + "state": "post-push shared progress and saved draft", + "violations": [] + }, + { + "state": "reopened empty workspace", + "violations": [] + } + ] + } + ], + "additionalChecks": { + "standaloneFileLoadingAndMarkReviewed": "passed", + "inlineJavaScriptSyntax": "passed", + "iteration2ArchiveExactIdentity": "passed", + "initialPhoneVisibleButtonsAtLeast44By44CSSPixels": "passed" + }, + "independentReview": { + "reviewedArtifactSHA256": "f2adc670df7668d0c99d79f3ac0d9abeea3df701f56a53e1373de331c2eb274f", + "result": "No actionable findings remain after recheck", + "fixedFindings": [ + "After closing every view in the Views dialog, dismissal now focuses visible New view.", + "Title button accessible names include the visible filename/title.", + "A queued close event from a dismissed dialog cannot dismiss a newly reopened dialog." + ], + "checks": [ + "Both final-child dialog dismissal paths", + "Five immediate close/reopen/Research/typing/Enter sequences", + "Prototype controls after 40 floating-view raises", + "Initial, workspace options, prototype controls, and Research at all three viewports: zero axe WCAG 2/2.1 A/AA violations, runtime errors, and document overflow", + "Full/incremental labels, retained compact arrangement, inactive-PR menu closure", + "Iteration-2 archive byte identity", + "Rendered layouts/dialogs visually inspected" + ] + }, + "authorCorrection": "Long tablet regression exposed floating-child z-order escaping over the sample-controls popup; explicit stage/lab stacking contexts contain it. Full scenario and independent stress recheck pass.", + "captures": [ + { + "path": "desktop-before.png", + "width": 1440, + "height": 1000, + "sha256": "cf56521f29c046b1cdc11a398a5e7c8f9c845555db6e18f3693c1a483c8ddb0c" + }, + { + "path": "desktop-after.png", + "width": 1440, + "height": 1000, + "sha256": "c20aa8abc8f1c66d32bc8fce755d8352cd4b910f53e90dea60ce329d860fb6f0" + }, + { + "path": "tablet-before.png", + "width": 834, + "height": 1112, + "sha256": "264765dcd889a6630079d900ee96c05c963a868b8dc2e6b1673964515448357d" + }, + { + "path": "tablet-after.png", + "width": 834, + "height": 1112, + "sha256": "0466ea6ef35e4d72f6a76fd7f8dce5ee02f9b62a624b6605f44c2f7089744a86" + }, + { + "path": "phone-before.png", + "width": 390, + "height": 844, + "sha256": "66411b91a259265ced7e08687bebe39909c1d80062047afa0076c89e1ca55298" + }, + { + "path": "phone-after.png", + "width": 390, + "height": 844, + "sha256": "be3412b2986768d6c64a0d1f6a90d15ff3d1ecd86561a96db6a352f529d00d51" + }, + { + "path": "phone-incremental.png", + "width": 390, + "height": 844, + "sha256": "bd0d18334c11c2b102cc52e950346a42ba76cc4e600256a41429b1f707107ef3" + }, + { + "path": "desktop-windows.png", + "width": 1440, + "height": 1000, + "sha256": "3c6da721575d35190f576aea40ad81a84cde7d7edf2d4e488d8e1da38413778c" + }, + { + "path": "tablet-float.png", + "width": 834, + "height": 1112, + "sha256": "e5d25f88641c14ce5ececa774e5684558d3dd677cc970b57d476f707d55da1c8" + }, + { + "path": "phone-preview.png", + "width": 390, + "height": 844, + "sha256": "b45cea126ae806b786c15eac7c30a8ad29d1367c284d6bd68d2950ebf91b93af" + }, + { + "path": "phone-options.png", + "width": 390, + "height": 844, + "sha256": "e5cc09adb0ec05c36ba3252d574a9bc161d08246b8584cc059204c641d10ec85" + } + ], + "limits": [ + "Native runtime, VoiceOver, actual execution, Git comparison, durability, provider, and sync are not exercised.", + "Default repository web lint globs do not cover this HTML. Native tests/snapshots and SwiftFormat were not run for the browser-only slice.", + "Third user evaluation is pending; automated evidence does not complete the experiment." + ] +} diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/desktop-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/desktop-after.png new file mode 100644 index 000000000..d4b876ea4 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/desktop-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/desktop-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/desktop-before.png new file mode 100644 index 000000000..9196f9564 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/desktop-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/phone-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/phone-after.png new file mode 100644 index 000000000..9a264b8e9 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/phone-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/phone-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/phone-before.png new file mode 100644 index 000000000..2ea56b3f0 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/phone-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/tablet-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/tablet-after.png new file mode 100644 index 000000000..496d4afa6 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/tablet-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/tablet-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/tablet-before.png new file mode 100644 index 000000000..13addb90a Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/tablet-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/verification.json b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/verification.json new file mode 100644 index 000000000..c81f3a39a --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-drag/verification.json @@ -0,0 +1,527 @@ +{ + "scope": "Focused iteration-4 title-bar drag correction; historical layout/type evidence is retained unchanged.", + "baseCommit": "7f89c2b5c3a156f193e2941b193fae5292594671", + "parentCommit": "8021dc5ccb5ced066395b6ce2be7073718aabefc", + "sourceSHA256": "3f86c704db285b85cd504a148236aa464016fb37dd92e005256f27cadc98007d", + "contractMap": { + "dragClick": "Title bar/title/icon share pointer gesture; 5 CSS pixel movement threshold separates click/tap jitter. Independent action buttons excluded.", + "ownership": "Initiating pointer owns capture; release/cancel/lost capture/rerender/blur end it. Last applied position survives cancellation; no additional movement or action is synthesized.", + "continuity": "Existing fitted-frame projection, keyboard move/resize and PR/child state retained.", + "guard": "Ad hoc isolated browser evidence; no retained CI guard." + }, + "tools": { + "playwright": "1.64.1", + "chromium": "156.0.8078.4", + "webkit": "27.2 (coordinator focused direct-file check)", + "axe": "4.14.0" + }, + "commands": [ + "mise exec -- node /tmp/mobius-titlebar-reproduce-original.cjs", + "mise exec -- node /tmp/mobius-titlebar-verify.cjs", + "mise exec -- node /tmp/mobius-titlebar-captures.cjs", + "mise exec -- node /tmp/mobius-titlebar-independent.cjs", + "mise exec -- node /tmp/mobius-titlebar-independent-extra.cjs", + "mise exec -- node /tmp/mobius-titlebar-root-check.cjs" + ], + "before": { + "sourceSHA256": "93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b", + "reports": [ + { + "viewport": { + "width": 390, + "height": 844 + }, + "cases": [ + { + "target": ".child-title strong", + "title": "Parser.swift", + "dx": 0, + "dy": 0, + "dialogOpen": false + }, + { + "target": "[data-drag]", + "title": "", + "dx": 18, + "dy": 24, + "dialogOpen": false + } + ] + }, + { + "viewport": { + "width": 834, + "height": 1112 + }, + "cases": [ + { + "target": ".child-title strong", + "title": "Parser.swift", + "dx": 0, + "dy": 0, + "dialogOpen": false + }, + { + "target": "[data-drag]", + "title": "", + "dx": 18, + "dy": 24, + "dialogOpen": false + } + ] + }, + { + "viewport": { + "width": 1440, + "height": 1000 + }, + "cases": [ + { + "target": ".child-title strong", + "title": "Parser.swift", + "dx": 0, + "dy": 0, + "dialogOpen": false + }, + { + "target": "[data-drag]", + "title": "", + "dx": 18, + "dy": 24, + "dialogOpen": false + } + ] + } + ] + }, + "author": { + "sourceSHA256": "3f86c704db285b85cd504a148236aa464016fb37dd92e005256f27cadc98007d", + "reports": [ + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "checks": [ + "stationary title click and 4px jitter open chooser without movement", + "5px threshold moves; completion click suppressed; next intentional click works", + "Parser.swift exact text moves +18/+24 without chooser, size jump, or sibling/PR mutation", + "header padding hit moves +6/+9; keyboard filename activation still works", + "icon mouse/keyboard movement and shift/corner resizing preserved", + "Non-floating filename click behavior unchanged wherever the title bar is rendered", + "narrow/wide and outer-window round trips preserve saved frames, focus and child state", + "close/focus/source-review controls do not drag and retain deliberate click actions", + "foreign pointer ignored; lost capture stops movement/click and next click works", + "rerender tears down captured gesture without residual movement or click", + "stationary touch tap opens chooser; touch title drag +18/+24 suppresses click; touchCancel clears capture and next tap works", + "simulated preview title also drags and clicks to focus" + ], + "titleMovement": { + "x": 18, + "y": 24 + }, + "touchMovement": { + "x": 18, + "y": 24 + }, + "auditViolations": [], + "errors": [], + "externalRequests": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "checks": [ + "stationary title click and 4px jitter open chooser without movement", + "5px threshold moves; completion click suppressed; next intentional click works", + "Parser.swift exact text moves +18/+24 without chooser, size jump, or sibling/PR mutation", + "header padding hit moves +6/+9; keyboard filename activation still works", + "icon mouse/keyboard movement and shift/corner resizing preserved", + "Non-floating filename click behavior unchanged wherever the title bar is rendered", + "narrow/wide and outer-window round trips preserve saved frames, focus and child state", + "close/focus/source-review controls do not drag and retain deliberate click actions", + "foreign pointer ignored; lost capture stops movement/click and next click works", + "rerender tears down captured gesture without residual movement or click", + "stationary touch tap opens chooser; touch title drag +18/+24 suppresses click; touchCancel clears capture and next tap works", + "simulated preview title also drags and clicks to focus" + ], + "titleMovement": { + "x": 18, + "y": 24 + }, + "touchMovement": { + "x": 18, + "y": 24 + }, + "auditViolations": [], + "errors": [], + "externalRequests": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "checks": [ + "stationary title click and 4px jitter open chooser without movement", + "5px threshold moves; completion click suppressed; next intentional click works", + "Parser.swift exact text moves +18/+24 without chooser, size jump, or sibling/PR mutation", + "header padding hit moves +6/+9; keyboard filename activation still works", + "icon mouse/keyboard movement and shift/corner resizing preserved", + "Non-floating filename click behavior unchanged wherever the title bar is rendered", + "narrow/wide and outer-window round trips preserve saved frames, focus and child state", + "close/focus/source-review controls do not drag and retain deliberate click actions", + "foreign pointer ignored; lost capture stops movement/click and next click works", + "rerender tears down captured gesture without residual movement or click", + "stationary touch tap opens chooser; touch title drag +18/+24 suppresses click; touchCancel clears capture and next tap works", + "simulated preview title also drags and clicks to focus" + ], + "titleMovement": { + "x": 18, + "y": 24 + }, + "touchMovement": { + "x": 18, + "y": 24 + }, + "auditViolations": [], + "errors": [], + "externalRequests": [] + } + ] + }, + "independent": { + "disposition": "No actionable findings", + "threeSizes": { + "sourceSHA256": "3f86c704db285b85cd504a148236aa464016fb37dd92e005256f27cadc98007d", + "reports": [ + { + "viewport": { + "width": 390, + "height": 844 + }, + "checks": [ + "actual filename text drag +20/+22 and no chooser; navigation/PR state unchanged", + "stationary filename click after drag opens chooser", + "3px jitter clicks with no move", + "5px threshold moves and suppresses click", + "cross threshold then return suppresses click", + "header gap moves", + "lost capture ends movement; release has no chooser; next click works", + "rerender ends capture and movement", + "keyboard icon move and resize", + "resize remains immediate below title threshold", + "resize round trip preserves authored frame", + "touch title drag and stationary next tap", + "touch cancellation clears capture; next tap works", + "separate focus action remains a click", + "source review and close actions excluded from dragging" + ], + "errors": [] + }, + { + "viewport": { + "width": 834, + "height": 1112 + }, + "checks": [ + "actual filename text drag +20/+22 and no chooser; navigation/PR state unchanged", + "stationary filename click after drag opens chooser", + "3px jitter clicks with no move", + "5px threshold moves and suppresses click", + "cross threshold then return suppresses click", + "header gap moves", + "lost capture ends movement; release has no chooser; next click works", + "rerender ends capture and movement", + "keyboard icon move and resize", + "resize remains immediate below title threshold", + "resize round trip preserves authored frame", + "touch title drag and stationary next tap", + "touch cancellation clears capture; next tap works", + "separate focus action remains a click", + "source review and close actions excluded from dragging" + ], + "errors": [] + }, + { + "viewport": { + "width": 1440, + "height": 1000 + }, + "checks": [ + "actual filename text drag +20/+22 and no chooser; navigation/PR state unchanged", + "stationary filename click after drag opens chooser", + "3px jitter clicks with no move", + "5px threshold moves and suppresses click", + "cross threshold then return suppresses click", + "header gap moves", + "lost capture ends movement; release has no chooser; next click works", + "rerender ends capture and movement", + "keyboard icon move and resize", + "resize remains immediate below title threshold", + "resize round trip preserves authored frame", + "touch title drag and stationary next tap", + "touch cancellation clears capture; next tap works", + "separate focus action remains a click", + "source review and close actions excluded from dragging" + ], + "errors": [] + } + ] + }, + "alternatePaths": { + "sourceSHA256": "3f86c704db285b85cd504a148236aa464016fb37dd92e005256f27cadc98007d", + "checks": [ + "preview title drags; stationary title focuses without chooser", + "dragging separate action outside target does not move or invoke layout", + "title drag in narrower outer Windows host changes only owner", + "foreign pointer move/up cannot move or end owned gesture (event-boundary probe)", + "Tile title does not author a floating frame" + ], + "errors": [] + } + }, + "coordinatorCrossEngine": { + "sha256": "3f86c704db285b85cd504a148236aa464016fb37dd92e005256f27cadc98007d", + "reports": [ + { + "engine": "Chromium", + "version": "156.0.8078.4", + "titleDrag": { + "x": 32, + "y": 24 + }, + "chooserAfterDrag": false, + "stationaryClick": "passed", + "keyboardEnter": "passed", + "errors": [] + }, + { + "engine": "WebKit", + "version": "27.2", + "titleDrag": { + "x": 32, + "y": 24 + }, + "chooserAfterDrag": false, + "stationaryClick": "passed", + "keyboardEnter": "passed", + "errors": [] + } + ] + }, + "captures": [ + { + "name": "phone-before.png", + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "version": "before", + "sourceSHA256": "93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b", + "sha256": "43441c3d08dcacc32053fcc955ed8908ebf5c589a504c0960dbb728196d32542", + "title": "Parser.swift", + "requestedMovement": { + "x": 36, + "y": 80 + }, + "actualMovement": { + "x": 0, + "y": 0 + }, + "beforeFrame": { + "x": 22.09375, + "y": 126.046875, + "width": 299.984375, + "height": 519.828125 + }, + "afterFrame": { + "x": 22.09375, + "y": 126.046875, + "width": 299.984375, + "height": 519.828125 + }, + "chooserOpen": false + }, + { + "name": "phone-after.png", + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "version": "after", + "sourceSHA256": "3f86c704db285b85cd504a148236aa464016fb37dd92e005256f27cadc98007d", + "sha256": "5072c882912b584127126afb414801cf93aa5831309fbe6eb56c473c2ba4d613", + "title": "Parser.swift", + "requestedMovement": { + "x": 36, + "y": 80 + }, + "actualMovement": { + "x": 36, + "y": 80 + }, + "beforeFrame": { + "x": 22.09375, + "y": 126.046875, + "width": 299.984375, + "height": 519.828125 + }, + "afterFrame": { + "x": 58.09375, + "y": 206.046875, + "width": 299.984375, + "height": 519.828125 + }, + "chooserOpen": false + }, + { + "name": "tablet-before.png", + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "version": "before", + "sourceSHA256": "93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b", + "sha256": "ad2b14ceb72b1e39e61281053d555113098691649f24005e277bec89ec43e28d", + "title": "Parser.swift", + "requestedMovement": { + "x": 36, + "y": 80 + }, + "actualMovement": { + "x": 0, + "y": 0 + }, + "beforeFrame": { + "x": 55.046875, + "y": 136.1875, + "width": 487.671875, + "height": 696.953125 + }, + "afterFrame": { + "x": 55.046875, + "y": 136.1875, + "width": 487.671875, + "height": 696.953125 + }, + "chooserOpen": false + }, + { + "name": "tablet-after.png", + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "version": "after", + "sourceSHA256": "3f86c704db285b85cd504a148236aa464016fb37dd92e005256f27cadc98007d", + "sha256": "ecb3001dca47a9e3771368b2f48a30b59734379249974a87e3e0223356be69a6", + "title": "Parser.swift", + "requestedMovement": { + "x": 36, + "y": 80 + }, + "actualMovement": { + "x": 36, + "y": 80 + }, + "beforeFrame": { + "x": 55.046875, + "y": 136.1875, + "width": 487.671875, + "height": 696.953125 + }, + "afterFrame": { + "x": 91.046875, + "y": 216.1875, + "width": 487.671875, + "height": 696.953125 + }, + "chooserOpen": false + }, + { + "name": "desktop-before.png", + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "version": "before", + "sourceSHA256": "93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b", + "sha256": "9817bd4ddc57cb567aa0e195a20bf27b0ae2bf72cad0a1eb6ffefc13da4a1d3c", + "title": "Parser.swift", + "requestedMovement": { + "x": 36, + "y": 80 + }, + "actualMovement": { + "x": 0, + "y": 0 + }, + "beforeFrame": { + "x": 70.1875, + "y": 133.390625, + "width": 875.515625, + "height": 616.3125 + }, + "afterFrame": { + "x": 70.1875, + "y": 133.390625, + "width": 875.515625, + "height": 616.3125 + }, + "chooserOpen": false + }, + { + "name": "desktop-after.png", + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "version": "after", + "sourceSHA256": "3f86c704db285b85cd504a148236aa464016fb37dd92e005256f27cadc98007d", + "sha256": "5aa3b55d30f75de44caeebe790447394b86a3eda0782929f66b3031d54ba5cf2", + "title": "Parser.swift", + "requestedMovement": { + "x": 36, + "y": 80 + }, + "actualMovement": { + "x": 36, + "y": 80 + }, + "beforeFrame": { + "x": 70.1875, + "y": 133.390625, + "width": 875.515625, + "height": 616.3125 + }, + "afterFrame": { + "x": 106.1875, + "y": 213.390625, + "width": 875.515625, + "height": 616.3125 + }, + "chooserOpen": false + } + ], + "captureSetup": "Matching initial PR42 v1, Float + Tabs, Review 1 focused; light, 1x. Same +36/+80 pointer gesture on Parser.swift text. Before uses exact published source 7f89c2b5c; after uses final source. All six visually inspected.", + "limits": [ + "Synthetic isolated fixtures, not the unavailable user browser.", + "WebKit check covers desktop filename drag/click/Enter, not a full Safari/device matrix.", + "No native device, VoiceOver or complete accessibility audit. Three selected WCAG scans passed.", + "No unrelated type/skip matrix rerun; fixture and review/comparison code is unchanged.", + "Default web lint excludes HTML; native tests/snapshots/SwiftFormat cannot exercise this change.", + "Experiment remains executing pending user reevaluation." + ] +} diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-options-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-options-after.png new file mode 100644 index 000000000..996ec92ff Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-options-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-options-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-options-before.png new file mode 100644 index 000000000..1b999bb82 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-options-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-windows-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-windows-after.png new file mode 100644 index 000000000..7441918ca Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-windows-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-windows-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-windows-before.png new file mode 100644 index 000000000..c3d860141 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/desktop-windows-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-asset-float-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-asset-float-after.png new file mode 100644 index 000000000..26441a8ca Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-asset-float-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-float-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-float-after.png new file mode 100644 index 000000000..2ea56b3f0 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-float-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-float-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-float-before.png new file mode 100644 index 000000000..89e177259 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-float-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-tiles-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-tiles-after.png new file mode 100644 index 000000000..fc6706b19 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/phone-tiles-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/tablet-windows-after.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/tablet-windows-after.png new file mode 100644 index 000000000..84f73b0ac Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/tablet-windows-after.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/tablet-windows-before.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/tablet-windows-before.png new file mode 100644 index 000000000..975d65c81 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/tablet-windows-before.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/verification.json b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/verification.json new file mode 100644 index 000000000..88738bab5 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04-layout/verification.json @@ -0,0 +1,5351 @@ +{ + "correction": "Iteration4 selected/rendered layout truth and visible workspace/child scopes", + "verifiedDate": "2026-11-14", + "baseCommit": "8404126bf89bfbca88d9a766401ee929e7d46e33", + "artifact": "index.html", + "artifactSHA256": "93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b", + "archive": { + "path": "iteration-04.html", + "commit": "e987835f6a1dd18463eceaf8274673c8445036d5", + "sha256": "fe137ea8e41335bbb0c25a203f6b27aac689bcdb2ce725420a63ab5b50dc8b00", + "byteIdentity": "passed" + }, + "toolchain": { + "playwright": "1.64.1", + "chromium": "156.0.8078.4", + "axe": "4.14.0" + }, + "method": { + "source": "User bug report and Q25: Honor Float at narrow widths too.", + "scope": "Computed layout and selected-mode agreement, narrow movement/resize and visibility, owner continuity, representative presentation captures.", + "commands": [ + "mise exec -- node /tmp/mobius-layout-investigation.cjs", + "mise exec -- node /tmp/mobius-layout-after.cjs", + "mise exec -- node /tmp/mobius-layout-verify.cjs", + "mise exec -- node /tmp/mobius-layout-captures.cjs", + "mise exec -- node --check /tmp/mobius-layout-inline.js", + "git diff --check" + ], + "checks": "Ad hoc isolated browser checks, not retained CI guards. No access to the user live browser.", + "unrelatedScope": "Prepared catalog and complete review/skip/comparison-rendering function range are byte-identical to the iteration4 archive. Prior feature matrix remains historical; new layout/continuity checks exercise changed shared paths." + }, + "before": [ + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Float", + " Tabs" + ], + "visibleTabButtons": 2, + "hostWidth": 390, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "relative", + "x": 0, + "y": 144, + "width": 390, + "height": 699, + "moveHandleVisible": false, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Float", + " Windows" + ], + "visibleTabButtons": 2, + "hostWidth": 376, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "relative", + "x": 8, + "y": 203, + "width": 374, + "height": 632, + "moveHandleVisible": false, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Float", + " Tabs" + ], + "visibleTabButtons": 2, + "hostWidth": 788, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 55.046875, + "y": 136.1875, + "width": 487.671875, + "height": 696.953125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 146.484375, + "y": 242.671875, + "width": 487.671875, + "height": 696.953125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 237.921875, + "y": 349.15625, + "width": 487.671875, + "height": 696.953125, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Float", + " Windows" + ], + "visibleTabButtons": 2, + "hostWidth": 430, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "relative", + "x": 36, + "y": 212, + "width": 428, + "height": 868, + "moveHandleVisible": false, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Float", + " Tabs" + ], + "visibleTabButtons": 2, + "hostWidth": 1394, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 70.1875, + "y": 133.390625, + "width": 875.515625, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 234.359375, + "y": 227.546875, + "width": 875.515625, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 398.515625, + "y": 321.71875, + "width": 875.515625, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Float", + " Windows" + ], + "visibleTabButtons": 2, + "hostWidth": 679, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "relative", + "x": 36, + "y": 212, + "width": 677, + "height": 756, + "moveHandleVisible": false, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Float", + " Tabs" + ], + "visibleTabButtons": 2, + "hostWidth": 1554, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 124.1875, + "y": 135.890625, + "width": 977.90625, + "height": 688.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 307.546875, + "y": 241.046875, + "width": 977.90625, + "height": 688.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 490.90625, + "y": 346.21875, + "width": 977.90625, + "height": 688.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Float", + " Windows" + ], + "visibleTabButtons": 2, + "hostWidth": 759, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 117.265625, + "y": 192.125, + "width": 467.828125, + "height": 637.1875, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 204.984375, + "y": 289.46875, + "width": 467.828125, + "height": 637.1875, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 292.703125, + "y": 386.8125, + "width": 467.828125, + "height": 637.1875, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Float", + " Tabs" + ], + "visibleTabButtons": 2, + "hostWidth": 680, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "relative", + "x": 23, + "y": 148, + "width": 680, + "height": 833, + "moveHandleVisible": false, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Float", + " Windows" + ], + "visibleTabButtons": 2, + "hostWidth": 430, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "relative", + "x": 36, + "y": 212, + "width": 428, + "height": 756, + "moveHandleVisible": false, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Float", + " Tabs" + ], + "visibleTabButtons": 2, + "hostWidth": 682, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 52.390625, + "y": 133.390625, + "width": 419.828125, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 131.109375, + "y": 227.546875, + "width": 419.828125, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 209.828125, + "y": 321.71875, + "width": 419.828125, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Float", + " Windows" + ], + "visibleTabButtons": 2, + "hostWidth": 430, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "relative", + "x": 36, + "y": 212, + "width": 428, + "height": 756, + "moveHandleVisible": false, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "relative", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + } + ], + "after": [ + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "selected": [ + " Tabs", + " Tile" + ], + "visibleTabButtons": 2, + "hostWidth": 390, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 12, + "y": 107, + "width": 366, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 12, + "y": 439, + "width": 366, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 12, + "y": 771, + "width": 366, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Tabs", + " Float" + ], + "visibleTabButtons": 2, + "hostWidth": 390, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 22.09375, + "y": 126.046875, + "width": 299.984375, + "height": 519.828125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 65.765625, + "y": 205.46875, + "width": 299.984375, + "height": 519.828125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 77, + "y": 284.875, + "width": 299.984375, + "height": 519.828125, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "selected": [ + " Tabs", + " One view" + ], + "visibleTabButtons": 2, + "hostWidth": 390, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 0, + "y": 144, + "width": 390, + "height": 699, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "selected": [ + " Windows", + " Tile" + ], + "visibleTabButtons": 0, + "hostWidth": 376, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 20, + "y": 166, + "width": 350, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 20, + "y": 498, + "width": 350, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 20, + "y": 830, + "width": 350, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Windows", + " Float" + ], + "visibleTabButtons": 0, + "hostWidth": 376, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 29.6875, + "y": 183.375, + "width": 300, + "height": 471.59375, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 69, + "y": 255.421875, + "width": 300, + "height": 471.59375, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 69, + "y": 327.46875, + "width": 300, + "height": 471.59375, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "selected": [ + " Windows", + " One view" + ], + "visibleTabButtons": 0, + "hostWidth": 376, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 8, + "y": 203, + "width": 374, + "height": 632, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "selected": [ + " Tabs", + " Tile" + ], + "visibleTabButtons": 2, + "hostWidth": 788, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 35, + "y": 111, + "width": 445.046875, + "height": 970, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 492.046875, + "y": 111, + "width": 306.953125, + "height": 479, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 492.046875, + "y": 602, + "width": 306.953125, + "height": 479, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Tabs", + " Float" + ], + "visibleTabButtons": 2, + "hostWidth": 788, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 55.046875, + "y": 136.1875, + "width": 487.671875, + "height": 696.953125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 146.484375, + "y": 242.671875, + "width": 487.671875, + "height": 696.953125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 237.921875, + "y": 349.15625, + "width": 487.671875, + "height": 696.953125, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "selected": [ + " Tabs", + " One view" + ], + "visibleTabButtons": 2, + "hostWidth": 788, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 23, + "y": 145, + "width": 788, + "height": 948, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "selected": [ + " Windows", + " Tile" + ], + "visibleTabButtons": 0, + "hostWidth": 430, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 48, + "y": 175, + "width": 404, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 48, + "y": 507, + "width": 404, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 48, + "y": 839, + "width": 404, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Windows", + " Float" + ], + "visibleTabButtons": 0, + "hostWidth": 430, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 59.046875, + "y": 198.265625, + "width": 300, + "height": 641.515625, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 107.28125, + "y": 296.28125, + "width": 300, + "height": 641.515625, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 151, + "y": 394.28125, + "width": 300, + "height": 641.515625, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "selected": [ + " Windows", + " One view" + ], + "visibleTabButtons": 0, + "hostWidth": 430, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 36, + "y": 212, + "width": 428, + "height": 868, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "selected": [ + " Tabs", + " Tile" + ], + "visibleTabButtons": 2, + "hostWidth": 1394, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 35, + "y": 111, + "width": 803.703125, + "height": 858, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 850.703125, + "y": 111, + "width": 554.296875, + "height": 423, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 850.703125, + "y": 546, + "width": 554.296875, + "height": 423, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Tabs", + " Float" + ], + "visibleTabButtons": 2, + "hostWidth": 1394, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 70.1875, + "y": 133.390625, + "width": 875.515625, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 234.359375, + "y": 227.546875, + "width": 875.515625, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 398.515625, + "y": 321.71875, + "width": 875.515625, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "selected": [ + " Tabs", + " One view" + ], + "visibleTabButtons": 2, + "hostWidth": 1394, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 23, + "y": 145, + "width": 1394, + "height": 836, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "selected": [ + " Windows", + " Tile" + ], + "visibleTabButtons": 0, + "hostWidth": 679, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 48, + "y": 175, + "width": 653, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 48, + "y": 507, + "width": 653, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 48, + "y": 839, + "width": 653, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Windows", + " Float" + ], + "visibleTabButtons": 0, + "hostWidth": 679, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 65.265625, + "y": 195.46875, + "width": 416.625, + "height": 560.875, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 143.390625, + "y": 281.15625, + "width": 416.625, + "height": 560.875, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 221.5, + "y": 366.84375, + "width": 416.625, + "height": 560.875, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "selected": [ + " Windows", + " One view" + ], + "visibleTabButtons": 0, + "hostWidth": 679, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 36, + "y": 212, + "width": 677, + "height": 756, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "selected": [ + " Tabs", + " Tile" + ], + "visibleTabButtons": 2, + "hostWidth": 1554, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 85, + "y": 111, + "width": 898.40625, + "height": 958, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 995.40625, + "y": 111, + "width": 619.578125, + "height": 473, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 995.40625, + "y": 596, + "width": 619.578125, + "height": 473, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Tabs", + " Float" + ], + "visibleTabButtons": 2, + "hostWidth": 1554, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 124.1875, + "y": 135.890625, + "width": 977.90625, + "height": 688.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 307.546875, + "y": 241.046875, + "width": 977.90625, + "height": 688.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 490.90625, + "y": 346.21875, + "width": 977.90625, + "height": 688.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "selected": [ + " Tabs", + " One view" + ], + "visibleTabButtons": 2, + "hostWidth": 1554, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 73, + "y": 145, + "width": 1554, + "height": 936, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "selected": [ + " Windows", + " Tile" + ], + "visibleTabButtons": 0, + "hostWidth": 759, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 98, + "y": 169, + "width": 426.703125, + "height": 887, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 536.703125, + "y": 169, + "width": 294.296875, + "height": 437.5, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 536.703125, + "y": 618.5, + "width": 294.296875, + "height": 437.5, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Windows", + " Float" + ], + "visibleTabButtons": 0, + "hostWidth": 759, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 117.265625, + "y": 192.125, + "width": 467.828125, + "height": 637.1875, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 204.984375, + "y": 289.46875, + "width": 467.828125, + "height": 637.1875, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 292.703125, + "y": 386.8125, + "width": 467.828125, + "height": 637.1875, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "selected": [ + " Windows", + " One view" + ], + "visibleTabButtons": 0, + "hostWidth": 759, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 86, + "y": 203, + "width": 757, + "height": 865, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "selected": [ + " Tabs", + " Tile" + ], + "visibleTabButtons": 2, + "hostWidth": 680, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 35, + "y": 111, + "width": 656, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 35, + "y": 443, + "width": 656, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 35, + "y": 775, + "width": 656, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Tabs", + " Float" + ], + "visibleTabButtons": 2, + "hostWidth": 680, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 52.34375, + "y": 133.390625, + "width": 418.546875, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 130.828125, + "y": 227.546875, + "width": 418.546875, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 209.296875, + "y": 321.71875, + "width": 418.546875, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "selected": [ + " Tabs", + " One view" + ], + "visibleTabButtons": 2, + "hostWidth": 680, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 23, + "y": 148, + "width": 680, + "height": 833, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "selected": [ + " Windows", + " Tile" + ], + "visibleTabButtons": 0, + "hostWidth": 430, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 48, + "y": 175, + "width": 404, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 48, + "y": 507, + "width": 404, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 48, + "y": 839, + "width": 404, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Windows", + " Float" + ], + "visibleTabButtons": 0, + "hostWidth": 430, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 59.046875, + "y": 195.46875, + "width": 300, + "height": 560.875, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 107.28125, + "y": 281.15625, + "width": 300, + "height": 560.875, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 151, + "y": 366.84375, + "width": 300, + "height": 560.875, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "selected": [ + " Windows", + " One view" + ], + "visibleTabButtons": 0, + "hostWidth": 430, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 36, + "y": 212, + "width": 428, + "height": 756, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "selected": [ + " Tabs", + " Tile" + ], + "visibleTabButtons": 2, + "hostWidth": 682, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 35, + "y": 111, + "width": 382.3125, + "height": 858, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 429.3125, + "y": 111, + "width": 263.6875, + "height": 423, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 429.3125, + "y": 546, + "width": 263.6875, + "height": 423, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "selected": [ + " Tabs", + " Float" + ], + "visibleTabButtons": 2, + "hostWidth": 682, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 52.390625, + "y": 133.390625, + "width": 419.828125, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 131.109375, + "y": 227.546875, + "width": 419.828125, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 209.828125, + "y": 321.71875, + "width": 419.828125, + "height": 616.3125, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "selected": [ + " Tabs", + " One view" + ], + "visibleTabButtons": 2, + "hostWidth": 682, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 23, + "y": 145, + "width": 682, + "height": 836, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "selected": [ + " Windows", + " Tile" + ], + "visibleTabButtons": 0, + "hostWidth": 430, + "canvasDisplay": "grid", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 48, + "y": 175, + "width": 404, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "flex", + "position": "static", + "x": 48, + "y": 507, + "width": 404, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "flex", + "position": "static", + "x": 48, + "y": 839, + "width": 404, + "height": 320, + "moveHandleVisible": true, + "resizeHandleVisible": false + } + ], + "errors": [] + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "selected": [ + " Windows", + " Float" + ], + "visibleTabButtons": 0, + "hostWidth": 430, + "canvasDisplay": "block", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "absolute", + "x": 59.046875, + "y": 195.46875, + "width": 300, + "height": 560.875, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-2", + "display": "flex", + "position": "absolute", + "x": 107.28125, + "y": 281.15625, + "width": 300, + "height": 560.875, + "moveHandleVisible": true, + "resizeHandleVisible": true + }, + { + "view": "42-3", + "display": "flex", + "position": "absolute", + "x": 151, + "y": 366.84375, + "width": 300, + "height": 560.875, + "moveHandleVisible": true, + "resizeHandleVisible": true + } + ], + "errors": [] + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "selected": [ + " Windows", + " One view" + ], + "visibleTabButtons": 0, + "hostWidth": 430, + "canvasDisplay": "flex", + "children": [ + { + "view": "42-1", + "display": "flex", + "position": "static", + "x": 36, + "y": 212, + "width": 428, + "height": 756, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-2", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + }, + { + "view": "42-3", + "display": "none", + "position": "static", + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "moveHandleVisible": false, + "resizeHandleVisible": false + } + ], + "errors": [] + } + ], + "computedAssertions": { + "sourceSHA256": "93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b", + "cases": [ + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "wide", + "width": 1700, + "height": 1100 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "below-boundary", + "width": 726, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "tabs", + "layout": "focus" + }, + "result": "passed" + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "tiles" + }, + "result": "passed" + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "float" + }, + "result": "passed" + }, + { + "viewport": { + "name": "above-boundary", + "width": 728, + "height": 1000 + }, + "requested": { + "presentation": "windows", + "layout": "focus" + }, + "result": "passed" + } + ] + }, + "interactions": { + "sourceSHA256": "93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b", + "reports": [ + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "checks": "passed", + "pointerDelta": { + "x": 4, + "y": 6, + "width": 0, + "height": 0 + }, + "handleSize": { + "move": { + "width": 44, + "height": 44 + }, + "resize": { + "width": 44, + "height": 44 + } + }, + "audits": [ + { + "state": "narrow-capable float", + "violations": [] + }, + { + "state": "workspace windows navigation", + "violations": [] + }, + { + "state": "real narrow tiles", + "violations": [] + }, + { + "state": "scoped options", + "violations": [] + }, + { + "state": "recovered float workspace", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "checks": "passed", + "pointerDelta": { + "x": 4, + "y": 6, + "width": 0, + "height": 0 + }, + "handleSize": { + "move": { + "width": 44, + "height": 44 + }, + "resize": { + "width": 44, + "height": 44 + } + }, + "audits": [ + { + "state": "narrow-capable float", + "violations": [] + }, + { + "state": "workspace windows navigation", + "violations": [] + }, + { + "state": "real narrow tiles", + "violations": [] + }, + { + "state": "scoped options", + "violations": [] + }, + { + "state": "recovered float workspace", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "checks": "passed", + "pointerDelta": { + "x": 4, + "y": 6, + "width": 0, + "height": 0 + }, + "handleSize": { + "move": { + "width": 36, + "height": 36 + }, + "resize": { + "width": 28, + "height": 28 + } + }, + "audits": [ + { + "state": "narrow-capable float", + "violations": [] + }, + { + "state": "workspace windows navigation", + "violations": [] + }, + { + "state": "real narrow tiles", + "violations": [] + }, + { + "state": "scoped options", + "violations": [] + }, + { + "state": "recovered float workspace", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + } + ] + }, + "independentReview": { + "disposition": "No actionable findings remain", + "results": { + "sha256": "93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b", + "report": [ + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "checks": "float handles and projected pointer delta; non-destructive resize and outer switches; picker PR return; tiles disjoint/reachable; One view visibility", + "audits": [ + { + "state": "tabs options", + "violations": [] + }, + { + "state": "tabs canvas", + "violations": [] + }, + { + "state": "windows options", + "violations": [] + }, + { + "state": "windows canvas", + "violations": [] + } + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "checks": "float handles and projected pointer delta; non-destructive resize and outer switches; picker PR return; tiles disjoint/reachable; One view visibility", + "audits": [ + { + "state": "tabs options", + "violations": [] + }, + { + "state": "tabs canvas", + "violations": [] + }, + { + "state": "windows options", + "violations": [] + }, + { + "state": "windows canvas", + "violations": [] + } + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "checks": "float handles and projected pointer delta; non-destructive resize and outer switches; picker PR return; tiles disjoint/reachable; One view visibility", + "audits": [ + { + "state": "tabs options", + "violations": [] + }, + { + "state": "tabs canvas", + "violations": [] + }, + { + "state": "windows options", + "violations": [] + }, + { + "state": "windows canvas", + "violations": [] + } + ], + "errors": [] + } + ] + }, + "boundaries": { + "sha256": "93018f2fb35d28edb72daab1089a28dd849727658259bd177aa248f68a2e5f5b", + "matrix": [ + { + "width": 320, + "outer": "tabs", + "arrangement": "tiles", + "actual": { + "hostWidth": 320, + "canvas": { + "x": 0, + "y": 95, + "width": 320, + "height": 904, + "scrollHeight": 1008, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 12, + "y": 107, + "width": 296, + "height": 320 + }, + { + "id": "42-2", + "position": "static", + "x": 12, + "y": 439, + "width": 296, + "height": 320 + }, + { + "id": "42-3", + "position": "static", + "x": 12, + "y": 771, + "width": 296, + "height": 320 + } + ] + }, + "errors": [] + }, + { + "width": 320, + "outer": "tabs", + "arrangement": "float", + "actual": { + "hostWidth": 320, + "canvas": { + "x": 13, + "y": 108, + "width": 294, + "height": 878, + "scrollHeight": 878, + "display": "block" + }, + "arrangement": "float", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 13, + "y": 129.9375, + "width": 294, + "height": 632.15625 + }, + { + "id": "42-2", + "position": "absolute", + "x": 13, + "y": 226.515625, + "width": 294, + "height": 632.15625 + }, + { + "id": "42-3", + "position": "absolute", + "x": 13, + "y": 323.109375, + "width": 294, + "height": 632.15625 + } + ] + }, + "errors": [] + }, + { + "width": 320, + "outer": "tabs", + "arrangement": "focus", + "actual": { + "hostWidth": 320, + "canvas": { + "x": 0, + "y": 144, + "width": 320, + "height": 855, + "scrollHeight": 855, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 0, + "y": 144, + "width": 320, + "height": 855 + } + ] + }, + "errors": [] + }, + { + "width": 320, + "outer": "windows", + "arrangement": "tiles", + "actual": { + "hostWidth": 306, + "canvas": { + "x": 8, + "y": 154, + "width": 304, + "height": 837, + "scrollHeight": 1008, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 20, + "y": 166, + "width": 280, + "height": 320 + }, + { + "id": "42-2", + "position": "static", + "x": 20, + "y": 498, + "width": 280, + "height": 320 + }, + { + "id": "42-3", + "position": "static", + "x": 20, + "y": 830, + "width": 280, + "height": 320 + } + ] + }, + "errors": [] + }, + { + "width": 320, + "outer": "windows", + "arrangement": "float", + "actual": { + "hostWidth": 306, + "canvas": { + "x": 21, + "y": 167, + "width": 278, + "height": 811, + "scrollHeight": 811, + "display": "block" + }, + "arrangement": "float", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 21, + "y": 187.265625, + "width": 278, + "height": 583.90625 + }, + { + "id": "42-2", + "position": "absolute", + "x": 21, + "y": 276.484375, + "width": 278, + "height": 583.90625 + }, + { + "id": "42-3", + "position": "absolute", + "x": 21, + "y": 365.6875, + "width": 278, + "height": 583.90625 + } + ] + }, + "errors": [] + }, + { + "width": 320, + "outer": "windows", + "arrangement": "focus", + "actual": { + "hostWidth": 306, + "canvas": { + "x": 8, + "y": 203, + "width": 304, + "height": 788, + "scrollHeight": 788, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 8, + "y": 203, + "width": 304, + "height": 788 + } + ] + }, + "errors": [] + }, + { + "width": 390, + "outer": "tabs", + "arrangement": "tiles", + "actual": { + "hostWidth": 390, + "canvas": { + "x": 0, + "y": 95, + "width": 390, + "height": 904, + "scrollHeight": 1008, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 12, + "y": 107, + "width": 366, + "height": 320 + }, + { + "id": "42-2", + "position": "static", + "x": 12, + "y": 439, + "width": 366, + "height": 320 + }, + { + "id": "42-3", + "position": "static", + "x": 12, + "y": 771, + "width": 366, + "height": 320 + } + ] + }, + "errors": [] + }, + { + "width": 390, + "outer": "tabs", + "arrangement": "float", + "actual": { + "hostWidth": 390, + "canvas": { + "x": 13, + "y": 108, + "width": 364, + "height": 878, + "scrollHeight": 878, + "display": "block" + }, + "arrangement": "float", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 22.09375, + "y": 129.9375, + "width": 299.984375, + "height": 632.15625 + }, + { + "id": "42-2", + "position": "absolute", + "x": 65.765625, + "y": 226.515625, + "width": 299.984375, + "height": 632.15625 + }, + { + "id": "42-3", + "position": "absolute", + "x": 77, + "y": 323.109375, + "width": 299.984375, + "height": 632.15625 + } + ] + }, + "errors": [] + }, + { + "width": 390, + "outer": "tabs", + "arrangement": "focus", + "actual": { + "hostWidth": 390, + "canvas": { + "x": 0, + "y": 144, + "width": 390, + "height": 855, + "scrollHeight": 855, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 0, + "y": 144, + "width": 390, + "height": 855 + } + ] + }, + "errors": [] + }, + { + "width": 390, + "outer": "windows", + "arrangement": "tiles", + "actual": { + "hostWidth": 376, + "canvas": { + "x": 8, + "y": 154, + "width": 374, + "height": 837, + "scrollHeight": 1008, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 20, + "y": 166, + "width": 350, + "height": 320 + }, + { + "id": "42-2", + "position": "static", + "x": 20, + "y": 498, + "width": 350, + "height": 320 + }, + { + "id": "42-3", + "position": "static", + "x": 20, + "y": 830, + "width": 350, + "height": 320 + } + ] + }, + "errors": [] + }, + { + "width": 390, + "outer": "windows", + "arrangement": "float", + "actual": { + "hostWidth": 376, + "canvas": { + "x": 21, + "y": 167, + "width": 348, + "height": 811, + "scrollHeight": 811, + "display": "block" + }, + "arrangement": "float", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 29.6875, + "y": 187.265625, + "width": 300, + "height": 583.90625 + }, + { + "id": "42-2", + "position": "absolute", + "x": 69, + "y": 276.484375, + "width": 300, + "height": 583.90625 + }, + { + "id": "42-3", + "position": "absolute", + "x": 69, + "y": 365.6875, + "width": 300, + "height": 583.90625 + } + ] + }, + "errors": [] + }, + { + "width": 390, + "outer": "windows", + "arrangement": "focus", + "actual": { + "hostWidth": 376, + "canvas": { + "x": 8, + "y": 203, + "width": 374, + "height": 788, + "scrollHeight": 788, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 8, + "y": 203, + "width": 374, + "height": 788 + } + ] + }, + "errors": [] + }, + { + "width": 726, + "outer": "tabs", + "arrangement": "tiles", + "actual": { + "hostWidth": 680, + "canvas": { + "x": 23, + "y": 99, + "width": 680, + "height": 882, + "scrollHeight": 1008, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 35, + "y": 111, + "width": 656, + "height": 320 + }, + { + "id": "42-2", + "position": "static", + "x": 35, + "y": 443, + "width": 656, + "height": 320 + }, + { + "id": "42-3", + "position": "static", + "x": 35, + "y": 775, + "width": 656, + "height": 320 + } + ] + }, + "errors": [] + }, + { + "width": 726, + "outer": "tabs", + "arrangement": "float", + "actual": { + "hostWidth": 680, + "canvas": { + "x": 36, + "y": 112, + "width": 654, + "height": 856, + "scrollHeight": 856, + "display": "block" + }, + "arrangement": "float", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 52.34375, + "y": 133.390625, + "width": 418.546875, + "height": 616.3125 + }, + { + "id": "42-2", + "position": "absolute", + "x": 130.828125, + "y": 227.546875, + "width": 418.546875, + "height": 616.3125 + }, + { + "id": "42-3", + "position": "absolute", + "x": 209.296875, + "y": 321.71875, + "width": 418.546875, + "height": 616.3125 + } + ] + }, + "errors": [] + }, + { + "width": 726, + "outer": "tabs", + "arrangement": "focus", + "actual": { + "hostWidth": 680, + "canvas": { + "x": 23, + "y": 148, + "width": 680, + "height": 833, + "scrollHeight": 833, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 23, + "y": 148, + "width": 680, + "height": 833 + } + ] + }, + "errors": [] + }, + { + "width": 726, + "outer": "windows", + "arrangement": "tiles", + "actual": { + "hostWidth": 430, + "canvas": { + "x": 36, + "y": 163, + "width": 428, + "height": 805, + "scrollHeight": 1008, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 48, + "y": 175, + "width": 404, + "height": 320 + }, + { + "id": "42-2", + "position": "static", + "x": 48, + "y": 507, + "width": 404, + "height": 320 + }, + { + "id": "42-3", + "position": "static", + "x": 48, + "y": 839, + "width": 404, + "height": 320 + } + ] + }, + "errors": [] + }, + { + "width": 726, + "outer": "windows", + "arrangement": "float", + "actual": { + "hostWidth": 430, + "canvas": { + "x": 49, + "y": 176, + "width": 402, + "height": 779, + "scrollHeight": 779, + "display": "block" + }, + "arrangement": "float", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 59.046875, + "y": 195.46875, + "width": 300, + "height": 560.875 + }, + { + "id": "42-2", + "position": "absolute", + "x": 107.28125, + "y": 281.15625, + "width": 300, + "height": 560.875 + }, + { + "id": "42-3", + "position": "absolute", + "x": 151, + "y": 366.84375, + "width": 300, + "height": 560.875 + } + ] + }, + "errors": [] + }, + { + "width": 726, + "outer": "windows", + "arrangement": "focus", + "actual": { + "hostWidth": 430, + "canvas": { + "x": 36, + "y": 212, + "width": 428, + "height": 756, + "scrollHeight": 756, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 36, + "y": 212, + "width": 428, + "height": 756 + } + ] + }, + "errors": [] + }, + { + "width": 728, + "outer": "tabs", + "arrangement": "tiles", + "actual": { + "hostWidth": 682, + "canvas": { + "x": 23, + "y": 99, + "width": 682, + "height": 882, + "scrollHeight": 882, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 35, + "y": 111, + "width": 382.3125, + "height": 858 + }, + { + "id": "42-2", + "position": "static", + "x": 429.3125, + "y": 111, + "width": 263.6875, + "height": 423 + }, + { + "id": "42-3", + "position": "static", + "x": 429.3125, + "y": 546, + "width": 263.6875, + "height": 423 + } + ] + }, + "errors": [] + }, + { + "width": 728, + "outer": "tabs", + "arrangement": "float", + "actual": { + "hostWidth": 682, + "canvas": { + "x": 36, + "y": 112, + "width": 656, + "height": 856, + "scrollHeight": 856, + "display": "block" + }, + "arrangement": "float", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 52.390625, + "y": 133.390625, + "width": 419.828125, + "height": 616.3125 + }, + { + "id": "42-2", + "position": "absolute", + "x": 131.109375, + "y": 227.546875, + "width": 419.828125, + "height": 616.3125 + }, + { + "id": "42-3", + "position": "absolute", + "x": 209.828125, + "y": 321.71875, + "width": 419.828125, + "height": 616.3125 + } + ] + }, + "errors": [] + }, + { + "width": 728, + "outer": "tabs", + "arrangement": "focus", + "actual": { + "hostWidth": 682, + "canvas": { + "x": 23, + "y": 145, + "width": 682, + "height": 836, + "scrollHeight": 836, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 23, + "y": 145, + "width": 682, + "height": 836 + } + ] + }, + "errors": [] + }, + { + "width": 728, + "outer": "windows", + "arrangement": "tiles", + "actual": { + "hostWidth": 430, + "canvas": { + "x": 36, + "y": 163, + "width": 428, + "height": 805, + "scrollHeight": 1008, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 48, + "y": 175, + "width": 404, + "height": 320 + }, + { + "id": "42-2", + "position": "static", + "x": 48, + "y": 507, + "width": 404, + "height": 320 + }, + { + "id": "42-3", + "position": "static", + "x": 48, + "y": 839, + "width": 404, + "height": 320 + } + ] + }, + "errors": [] + }, + { + "width": 728, + "outer": "windows", + "arrangement": "float", + "actual": { + "hostWidth": 430, + "canvas": { + "x": 49, + "y": 176, + "width": 402, + "height": 779, + "scrollHeight": 779, + "display": "block" + }, + "arrangement": "float", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 59.046875, + "y": 195.46875, + "width": 300, + "height": 560.875 + }, + { + "id": "42-2", + "position": "absolute", + "x": 107.28125, + "y": 281.15625, + "width": 300, + "height": 560.875 + }, + { + "id": "42-3", + "position": "absolute", + "x": 151, + "y": 366.84375, + "width": 300, + "height": 560.875 + } + ] + }, + "errors": [] + }, + { + "width": 728, + "outer": "windows", + "arrangement": "focus", + "actual": { + "hostWidth": 430, + "canvas": { + "x": 36, + "y": 212, + "width": 428, + "height": 756, + "scrollHeight": 756, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 36, + "y": 212, + "width": 428, + "height": 756 + } + ] + }, + "errors": [] + }, + { + "width": 834, + "outer": "tabs", + "arrangement": "tiles", + "actual": { + "hostWidth": 788, + "canvas": { + "x": 23, + "y": 99, + "width": 788, + "height": 882, + "scrollHeight": 882, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 35, + "y": 111, + "width": 445.046875, + "height": 858 + }, + { + "id": "42-2", + "position": "static", + "x": 492.046875, + "y": 111, + "width": 306.953125, + "height": 423 + }, + { + "id": "42-3", + "position": "static", + "x": 492.046875, + "y": 546, + "width": 306.953125, + "height": 423 + } + ] + }, + "errors": [] + }, + { + "width": 834, + "outer": "tabs", + "arrangement": "float", + "actual": { + "hostWidth": 788, + "canvas": { + "x": 36, + "y": 112, + "width": 762, + "height": 856, + "scrollHeight": 856, + "display": "block" + }, + "arrangement": "float", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 55.046875, + "y": 133.390625, + "width": 487.671875, + "height": 616.3125 + }, + { + "id": "42-2", + "position": "absolute", + "x": 146.484375, + "y": 227.546875, + "width": 487.671875, + "height": 616.3125 + }, + { + "id": "42-3", + "position": "absolute", + "x": 237.921875, + "y": 321.71875, + "width": 487.671875, + "height": 616.3125 + } + ] + }, + "errors": [] + }, + { + "width": 834, + "outer": "tabs", + "arrangement": "focus", + "actual": { + "hostWidth": 788, + "canvas": { + "x": 23, + "y": 145, + "width": 788, + "height": 836, + "scrollHeight": 836, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 23, + "y": 145, + "width": 788, + "height": 836 + } + ] + }, + "errors": [] + }, + { + "width": 834, + "outer": "windows", + "arrangement": "tiles", + "actual": { + "hostWidth": 430, + "canvas": { + "x": 36, + "y": 163, + "width": 428, + "height": 805, + "scrollHeight": 1008, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 48, + "y": 175, + "width": 404, + "height": 320 + }, + { + "id": "42-2", + "position": "static", + "x": 48, + "y": 507, + "width": 404, + "height": 320 + }, + { + "id": "42-3", + "position": "static", + "x": 48, + "y": 839, + "width": 404, + "height": 320 + } + ] + }, + "errors": [] + }, + { + "width": 834, + "outer": "windows", + "arrangement": "float", + "actual": { + "hostWidth": 430, + "canvas": { + "x": 49, + "y": 176, + "width": 402, + "height": 779, + "scrollHeight": 779, + "display": "block" + }, + "arrangement": "float", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 59.046875, + "y": 195.46875, + "width": 300, + "height": 560.875 + }, + { + "id": "42-2", + "position": "absolute", + "x": 107.28125, + "y": 281.15625, + "width": 300, + "height": 560.875 + }, + { + "id": "42-3", + "position": "absolute", + "x": 151, + "y": 366.84375, + "width": 300, + "height": 560.875 + } + ] + }, + "errors": [] + }, + { + "width": 834, + "outer": "windows", + "arrangement": "focus", + "actual": { + "hostWidth": 430, + "canvas": { + "x": 36, + "y": 212, + "width": 428, + "height": 756, + "scrollHeight": 756, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 36, + "y": 212, + "width": 428, + "height": 756 + } + ] + }, + "errors": [] + }, + { + "width": 1440, + "outer": "tabs", + "arrangement": "tiles", + "actual": { + "hostWidth": 1394, + "canvas": { + "x": 23, + "y": 99, + "width": 1394, + "height": 882, + "scrollHeight": 882, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 35, + "y": 111, + "width": 803.703125, + "height": 858 + }, + { + "id": "42-2", + "position": "static", + "x": 850.703125, + "y": 111, + "width": 554.296875, + "height": 423 + }, + { + "id": "42-3", + "position": "static", + "x": 850.703125, + "y": 546, + "width": 554.296875, + "height": 423 + } + ] + }, + "errors": [] + }, + { + "width": 1440, + "outer": "tabs", + "arrangement": "float", + "actual": { + "hostWidth": 1394, + "canvas": { + "x": 36, + "y": 112, + "width": 1368, + "height": 856, + "scrollHeight": 856, + "display": "block" + }, + "arrangement": "float", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 70.1875, + "y": 133.390625, + "width": 875.515625, + "height": 616.3125 + }, + { + "id": "42-2", + "position": "absolute", + "x": 234.359375, + "y": 227.546875, + "width": 875.515625, + "height": 616.3125 + }, + { + "id": "42-3", + "position": "absolute", + "x": 398.515625, + "y": 321.71875, + "width": 875.515625, + "height": 616.3125 + } + ] + }, + "errors": [] + }, + { + "width": 1440, + "outer": "tabs", + "arrangement": "focus", + "actual": { + "hostWidth": 1394, + "canvas": { + "x": 23, + "y": 145, + "width": 1394, + "height": 836, + "scrollHeight": 836, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 23, + "y": 145, + "width": 1394, + "height": 836 + } + ] + }, + "errors": [] + }, + { + "width": 1440, + "outer": "windows", + "arrangement": "tiles", + "actual": { + "hostWidth": 679, + "canvas": { + "x": 36, + "y": 163, + "width": 677, + "height": 805, + "scrollHeight": 1008, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 48, + "y": 175, + "width": 653, + "height": 320 + }, + { + "id": "42-2", + "position": "static", + "x": 48, + "y": 507, + "width": 653, + "height": 320 + }, + { + "id": "42-3", + "position": "static", + "x": 48, + "y": 839, + "width": 653, + "height": 320 + } + ] + }, + "errors": [] + }, + { + "width": 1440, + "outer": "windows", + "arrangement": "float", + "actual": { + "hostWidth": 679, + "canvas": { + "x": 49, + "y": 176, + "width": 651, + "height": 779, + "scrollHeight": 779, + "display": "block" + }, + "arrangement": "float", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 65.265625, + "y": 195.46875, + "width": 416.625, + "height": 560.875 + }, + { + "id": "42-2", + "position": "absolute", + "x": 143.390625, + "y": 281.15625, + "width": 416.625, + "height": 560.875 + }, + { + "id": "42-3", + "position": "absolute", + "x": 221.5, + "y": 366.84375, + "width": 416.625, + "height": 560.875 + } + ] + }, + "errors": [] + }, + { + "width": 1440, + "outer": "windows", + "arrangement": "focus", + "actual": { + "hostWidth": 679, + "canvas": { + "x": 36, + "y": 212, + "width": 677, + "height": 756, + "scrollHeight": 756, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 36, + "y": 212, + "width": 677, + "height": 756 + } + ] + }, + "errors": [] + }, + { + "width": 1700, + "outer": "tabs", + "arrangement": "tiles", + "actual": { + "hostWidth": 1554, + "canvas": { + "x": 73, + "y": 99, + "width": 1554, + "height": 882, + "scrollHeight": 882, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 85, + "y": 111, + "width": 898.40625, + "height": 858 + }, + { + "id": "42-2", + "position": "static", + "x": 995.40625, + "y": 111, + "width": 619.578125, + "height": 423 + }, + { + "id": "42-3", + "position": "static", + "x": 995.40625, + "y": 546, + "width": 619.578125, + "height": 423 + } + ] + }, + "errors": [] + }, + { + "width": 1700, + "outer": "tabs", + "arrangement": "float", + "actual": { + "hostWidth": 1554, + "canvas": { + "x": 86, + "y": 112, + "width": 1528, + "height": 856, + "scrollHeight": 856, + "display": "block" + }, + "arrangement": "float", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 124.1875, + "y": 133.390625, + "width": 977.90625, + "height": 616.3125 + }, + { + "id": "42-2", + "position": "absolute", + "x": 307.546875, + "y": 227.546875, + "width": 977.90625, + "height": 616.3125 + }, + { + "id": "42-3", + "position": "absolute", + "x": 490.90625, + "y": 321.71875, + "width": 977.90625, + "height": 616.3125 + } + ] + }, + "errors": [] + }, + { + "width": 1700, + "outer": "tabs", + "arrangement": "focus", + "actual": { + "hostWidth": 1554, + "canvas": { + "x": 73, + "y": 145, + "width": 1554, + "height": 836, + "scrollHeight": 836, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "tabs", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 73, + "y": 145, + "width": 1554, + "height": 836 + } + ] + }, + "errors": [] + }, + { + "width": 1700, + "outer": "windows", + "arrangement": "tiles", + "actual": { + "hostWidth": 759, + "canvas": { + "x": 86, + "y": 157, + "width": 757, + "height": 811, + "scrollHeight": 811, + "display": "grid" + }, + "arrangement": "tiles", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 98, + "y": 169, + "width": 426.703125, + "height": 787 + }, + { + "id": "42-2", + "position": "static", + "x": 536.703125, + "y": 169, + "width": 294.296875, + "height": 387.5 + }, + { + "id": "42-3", + "position": "static", + "x": 536.703125, + "y": 568.5, + "width": 294.296875, + "height": 387.5 + } + ] + }, + "errors": [] + }, + { + "width": 1700, + "outer": "windows", + "arrangement": "float", + "actual": { + "hostWidth": 759, + "canvas": { + "x": 99, + "y": 170, + "width": 731, + "height": 785, + "scrollHeight": 785, + "display": "block" + }, + "arrangement": "float", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "absolute", + "x": 117.265625, + "y": 189.625, + "width": 467.828125, + "height": 565.1875 + }, + { + "id": "42-2", + "position": "absolute", + "x": 204.984375, + "y": 275.96875, + "width": 467.828125, + "height": 565.1875 + }, + { + "id": "42-3", + "position": "absolute", + "x": 292.703125, + "y": 362.3125, + "width": 467.828125, + "height": 565.1875 + } + ] + }, + "errors": [] + }, + { + "width": 1700, + "outer": "windows", + "arrangement": "focus", + "actual": { + "hostWidth": 759, + "canvas": { + "x": 86, + "y": 203, + "width": 757, + "height": 765, + "scrollHeight": 765, + "display": "flex" + }, + "arrangement": "focus", + "presentation": "windows", + "ids": [ + "42-1", + "42-2", + "42-3" + ], + "children": [ + { + "id": "42-1", + "position": "static", + "x": 86, + "y": 203, + "width": 757, + "height": 765 + } + ] + }, + "errors": [] + } + ], + "touchPointer": { + "before": { + "x": 29.6875, + "y": 183.375, + "width": 300, + "height": 471.59375 + }, + "moved": { + "x": 41.6875, + "y": 199.375, + "width": 300, + "height": 471.59375 + }, + "resized": { + "x": 41.6875, + "y": 199.375, + "width": 304, + "height": 466.59375 + }, + "outerScrollUnchanged": true + }, + "emptyRecovery": "passed", + "archivedBug": { + "hostWidth": 679, + "stored": "float", + "frameBounds": null + } + }, + "return": [ + { + "width": 390, + "checks": "Both PRs float independently; only the moved owner frame changes; new window picker restores review at file top and non-review focus/state", + "errors": [] + }, + { + "width": 834, + "checks": "Both PRs float independently; only the moved owner frame changes; new window picker restores review at file top and non-review focus/state", + "errors": [] + }, + { + "width": 1440, + "checks": "Both PRs float independently; only the moved owner frame changes; new window picker restores review at file top and non-review focus/state", + "errors": [] + } + ], + "extraChecks": "Narrow Windows touch move, real handle hit tests, pointer resize without jumps, empty workspace with retained progress/draft, archive identity and original679px failure reproduction." + }, + "captures": [ + { + "name": "phone-float-before.png", + "viewport": { + "width": 390, + "height": 844 + }, + "phase": "before", + "scenario": "PR42 float, outer tabs; same initial synthetic v1 files and children.", + "sha256": "40ee0f9690e5c3adf1f00ac3f6145382d44748e1b72b0929f596339211f4fed8" + }, + { + "name": "phone-float-after.png", + "viewport": { + "width": 390, + "height": 844 + }, + "phase": "after", + "scenario": "PR42 float, outer tabs; same initial synthetic v1 files and children.", + "sha256": "43441c3d08dcacc32053fcc955ed8908ebf5c589a504c0960dbb728196d32542" + }, + { + "name": "phone-tiles-after.png", + "viewport": { + "width": 390, + "height": 844 + }, + "phase": "after", + "scenario": "Explicit Tile at390px: separate vertically stacked child views, all retained/reachable.", + "sha256": "bbe6b4e1c66c49f57b44d1be147fb0e2e54228c87f7fe9b3106f14d044e22a8b" + }, + { + "name": "phone-asset-float-after.png", + "viewport": { + "width": 390, + "height": 844 + }, + "phase": "after", + "scenario": "Synthetic image comparison adapts to a300px floating child, with source and metadata accessible.", + "sha256": "28b6801a98301f753ee36e28a12f6612bd5c029d29b80c35d0b793b19fbc76c4" + }, + { + "name": "tablet-windows-before.png", + "viewport": { + "width": 834, + "height": 1112 + }, + "phase": "before", + "scenario": "PR42 float, outer windows; same initial synthetic v1 files and children.", + "sha256": "fa35583d79cffb4afcd3f3cd4d6c968ede5d15665b31fe5fac7c5f63fc9b06c1" + }, + { + "name": "tablet-windows-after.png", + "viewport": { + "width": 834, + "height": 1112 + }, + "phase": "after", + "scenario": "PR42 float, outer windows; same initial synthetic v1 files and children.", + "sha256": "341e39377f80298045094e39da26ad275ac5b5f3fa85de8e18739fafeb659d1b" + }, + { + "name": "desktop-windows-before.png", + "viewport": { + "width": 1440, + "height": 1000 + }, + "phase": "before", + "scenario": "PR42 float, outer windows; same initial synthetic v1 files and children.", + "sha256": "e7760e12f820e45a336dce268a09443bf414e5d2e6b53b9b0d0a66a60028e31d" + }, + { + "name": "desktop-options-before.png", + "viewport": { + "width": 1440, + "height": 1000 + }, + "phase": "before", + "scenario": "PR42 float, outer windows; same initial synthetic v1 files and children.", + "sha256": "3a35692159947096da0b343dc12b3a039d0b06e400b42cf72b3fdcbf9daf70b1" + }, + { + "name": "desktop-windows-after.png", + "viewport": { + "width": 1440, + "height": 1000 + }, + "phase": "after", + "scenario": "PR42 float, outer windows; same initial synthetic v1 files and children.", + "sha256": "d24e1f26f42c4239a2600b59f452fb1b9689cc7078ab6c62cd8b53bfd5930cd9" + }, + { + "name": "desktop-options-after.png", + "viewport": { + "width": 1440, + "height": 1000 + }, + "phase": "after", + "scenario": "PR42 float, outer windows; same initial synthetic v1 files and children.", + "sha256": "c9d82b10b2f1ef1047823ab662df7b19d0c098f193fedd69c88a290386208b99" + } + ], + "directFileFloat": "passed", + "limits": [ + "Isolated Chromium fixture, not user live tab or native/VoiceOver validation.", + "Simulated PR windows remain browser containers; no OS windows or complete window manager.", + "Unrelated type fixtures were not rerun wholesale; source identity plus changed-path checks are recorded.", + "Default web lint excludes this HTML; native suites and SwiftFormat do not cover this browser-only slice.", + "User evaluation of the corrected layout remains pending." + ], + "staticChecks": { + "localLinksAndAnchors": 105, + "fences": "passed", + "artifactAnd10CaptureHashes": "passed", + "archiveByteIdentities": 4, + "priorEvidenceUnchanged": true, + "inlineJavaScriptSyntax": "passed", + "diffWhitespace": "passed" + } +} diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-assets.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-assets.png new file mode 100644 index 000000000..65f27675f Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-assets.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-documents.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-documents.png new file mode 100644 index 000000000..cdc4f2b30 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-documents.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-groups.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-groups.png new file mode 100644 index 000000000..ffd668aac Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-groups.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-localization.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-localization.png new file mode 100644 index 000000000..ba95e85d8 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-localization.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-skip-push.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-skip-push.png new file mode 100644 index 000000000..c8d6834a7 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/desktop-skip-push.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-assets.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-assets.png new file mode 100644 index 000000000..d68dd0ef0 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-assets.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-document-source.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-document-source.png new file mode 100644 index 000000000..5e7f71c9d Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-document-source.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-documents.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-documents.png new file mode 100644 index 000000000..7002d62dc Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-documents.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-groups.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-groups.png new file mode 100644 index 000000000..9f1918012 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-groups.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-localization.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-localization.png new file mode 100644 index 000000000..959b83a09 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-localization.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-unavailable.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-unavailable.png new file mode 100644 index 000000000..045e4ba4a Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/phone-unavailable.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-assets.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-assets.png new file mode 100644 index 000000000..d361335bc Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-assets.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-documents.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-documents.png new file mode 100644 index 000000000..cdb63024d Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-documents.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-groups.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-groups.png new file mode 100644 index 000000000..585de7ceb Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-groups.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-localization.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-localization.png new file mode 100644 index 000000000..907466246 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-localization.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-unavailable.png b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-unavailable.png new file mode 100644 index 000000000..76b487805 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/tablet-unavailable.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/verification.json b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/verification.json new file mode 100644 index 000000000..4f21cbff2 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/evidence/iteration-04/verification.json @@ -0,0 +1,657 @@ +{ + "iteration": 4, + "verifiedDate": "2026-11-14", + "artifact": "index.html", + "artifactSHA256": "fe137ea8e41335bbb0c25a203f6b27aac689bcdb2ce725420a63ab5b50dc8b00", + "reviewBaseCommit": "6e250ab22bad4b2929bf6d9e0d06e337eef45ea2", + "toolchain": { + "playwright": "1.64.1", + "chromium": "156.0.8078.4", + "axe": "4.14.0" + }, + "method": { + "fixture": "Two synthetic PRs, user-facing v1/v2; 7/8 changed files plus Reference.swift. Matched v1 full previews, light appearance, deviceScaleFactor 1.", + "metrics": "paneTop/paneHeight measure the scroll container. firstCodeTableTop matches iteration3 firstCodeTop. firstCodeRowTop is separately measured; collapsed table borders place it 1px above table origin.", + "checks": "Ad hoc scripts, not retained CI guards. Browser launch used approved macOS process access after the filesystem sandbox blocked Chromium MachPort registration.", + "commands": [ + "mise exec -- node /tmp/mobius-v4-regression.cjs", + "mise exec -- node /tmp/mobius-v4-features.cjs", + "mise exec -- node /tmp/mobius-v4-captures.cjs", + "mise exec -- node --check /tmp/mobius-v4-inline.js", + "git diff --check" + ] + }, + "workspaceRegression": [ + { + "name": "desktop", + "width": 1440, + "height": 1000, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "initial compact chrome", + "violations": [] + }, + { + "state": "workspace disclosure", + "violations": [] + }, + { + "state": "prototype controls", + "violations": [] + }, + { + "state": "post-push shared progress and saved draft", + "violations": [] + }, + { + "state": "reopened empty workspace", + "violations": [] + } + ] + }, + { + "name": "tablet", + "width": 834, + "height": 1112, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "initial compact chrome", + "violations": [] + }, + { + "state": "workspace disclosure", + "violations": [] + }, + { + "state": "prototype controls", + "violations": [] + }, + { + "state": "post-push shared progress and saved draft", + "violations": [] + }, + { + "state": "reopened empty workspace", + "violations": [] + } + ] + }, + { + "name": "phone", + "width": 390, + "height": 844, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "initial compact chrome", + "violations": [] + }, + { + "state": "workspace disclosure", + "violations": [] + }, + { + "state": "prototype controls", + "violations": [] + }, + { + "state": "post-push shared progress and saved draft", + "violations": [] + }, + { + "state": "reopened empty workspace", + "violations": [] + } + ] + } + ], + "featureScenarios": [ + { + "name": "desktop", + "width": 1440, + "height": 1000, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "grouped chooser", + "violations": [] + }, + { + "state": "individual skip action", + "violations": [] + }, + { + "state": "Markdown full preview", + "violations": [] + }, + { + "state": "unavailable pointer comparison", + "violations": [] + }, + { + "state": "localization since reviewed", + "violations": [] + }, + { + "state": "image since reviewed", + "violations": [] + }, + { + "state": "new image absent-before", + "violations": [] + }, + { + "state": "zero remaining with explicit skips", + "violations": [] + } + ], + "seededLaterHeadPolicy": { + "disposition": "remaining", + "comparisonFrom": 1, + "reviewed": 1, + "limit": "Only content-identity/disposition/basis selection asserted. No v3 content or UI comparison was rendered." + } + }, + { + "name": "tablet", + "width": 834, + "height": 1112, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "grouped chooser", + "violations": [] + }, + { + "state": "individual skip action", + "violations": [] + }, + { + "state": "Markdown full preview", + "violations": [] + }, + { + "state": "unavailable pointer comparison", + "violations": [] + }, + { + "state": "localization since reviewed", + "violations": [] + }, + { + "state": "image since reviewed", + "violations": [] + }, + { + "state": "new image absent-before", + "violations": [] + }, + { + "state": "zero remaining with explicit skips", + "violations": [] + } + ], + "seededLaterHeadPolicy": { + "disposition": "remaining", + "comparisonFrom": 1, + "reviewed": 1, + "limit": "Only content-identity/disposition/basis selection asserted. No v3 content or UI comparison was rendered." + } + }, + { + "name": "phone", + "width": 390, + "height": 844, + "result": "passed", + "errors": [], + "externalRequests": [], + "axe": [ + { + "state": "grouped chooser", + "violations": [] + }, + { + "state": "individual skip action", + "violations": [] + }, + { + "state": "Markdown full preview", + "violations": [] + }, + { + "state": "unavailable pointer comparison", + "violations": [] + }, + { + "state": "localization since reviewed", + "violations": [] + }, + { + "state": "image since reviewed", + "violations": [] + }, + { + "state": "new image absent-before", + "violations": [] + }, + { + "state": "zero remaining with explicit skips", + "violations": [] + } + ], + "seededLaterHeadPolicy": { + "disposition": "remaining", + "comparisonFrom": 1, + "reviewed": 1, + "limit": "Only content-identity/disposition/basis selection asserted. No v3 content or UI comparison was rendered." + } + } + ], + "captures": [ + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "name": "desktop-groups.png", + "scenario": "Initial PR42 v1: Code open; Documents, Localization, Snapshots/assets collapsed; seven remaining.", + "sha256": "5f4fd4ca17fe659ae5129320e5e19fef13890616fe7d3c3b83ff4244b8f6e2ec" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "name": "desktop-documents.png", + "scenario": "PR42 v1 README.md, full PR comparison, rendered preview, no review/skip receipts.", + "sha256": "021c268d9b59d64af22223738b0111fec7ef8c5cf050ab68c9c70d33a510673d" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "name": "desktop-localization.png", + "scenario": "PR42 v1 Localizable.xcstrings, full PR comparison, rendered preview, no review/skip receipts.", + "sha256": "80c38c25a024b7590dc3f0058d8a37aa385ef9f58e6c50c33a31c8f38191d492" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "name": "desktop-assets.png", + "scenario": "PR42 v1 SearchResults.svg, full PR comparison, rendered preview, no review/skip receipts.", + "sha256": "b1bf3e1e63485daf2e5ce9c95a53c3a8746144eb1830b2264a467b20fef43250" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "name": "desktop-skip-push.png", + "scenario": "PR42 v2 after v1 Parser review, Code remaining skip and Assets skip: Parser changed review basis1; Store/Search return; new Empty unskipped; Stable/Design stay skipped.", + "sha256": "5caaf312234e5967a8af4d8ad521672ae71a1c82d1669043522d5830d5aca7d9" + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "initialCodeMetrics": { + "paneTop": 203, + "paneHeight": 765, + "firstCodeRowTop": 202, + "firstCodeTableTop": 203 + }, + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "name": "tablet-groups.png", + "scenario": "Initial PR42 v1: Code open; Documents, Localization, Snapshots/assets collapsed; seven remaining.", + "sha256": "bb12700caeaf83f3fb5ab2623b12b2c2e9f421781bbbe98992e786783886ddad" + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "name": "tablet-documents.png", + "scenario": "PR42 v1 README.md, full PR comparison, rendered preview, no review/skip receipts.", + "sha256": "7ae58fcfdbd8f1648b28f27c3a42cf4e1b9d5b8ad2bb2496af20b9a9749ee727" + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "name": "tablet-localization.png", + "scenario": "PR42 v1 Localizable.xcstrings, full PR comparison, rendered preview, no review/skip receipts.", + "sha256": "acce7faed5001f84aef396534641b8dddc5efc8af56e2ef84b605c7d2235bfca" + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "name": "tablet-assets.png", + "scenario": "PR42 v1 SearchResults.svg, full PR comparison, rendered preview, no review/skip receipts.", + "sha256": "b6a4db6551c031b5802b645e6240aaf2a1a332acdaeb632302934bfc6695a814" + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "initialCodeMetrics": { + "paneTop": 203, + "paneHeight": 877, + "firstCodeRowTop": 202, + "firstCodeTableTop": 203 + }, + "errors": [] + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "name": "phone-groups.png", + "scenario": "Initial PR42 v1: Code open; Documents, Localization, Snapshots/assets collapsed; seven remaining.", + "sha256": "59a91aeab4bb5f435b60b33254a82d1925760bf6c23bc274817d7c0ed0a1bea3" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "name": "phone-documents.png", + "scenario": "PR42 v1 README.md, full PR comparison, rendered preview, no review/skip receipts.", + "sha256": "bc60e953bc2fd1736d20351ae6ea8a5584b02c9c31f02e308e374ebee1f88ec6" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "name": "phone-localization.png", + "scenario": "PR42 v1 Localizable.xcstrings, full PR comparison, rendered preview, no review/skip receipts.", + "sha256": "6f7d78d9a657116625951fd7b347570ed0833cc6c120f03c16c3c955ce6b38fb" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "name": "phone-assets.png", + "scenario": "PR42 v1 SearchResults.svg, full PR comparison, rendered preview, no review/skip receipts.", + "sha256": "c11100edf4eb00956a9efacebcc77f96872079b5af989cebd19a77dcc621b953" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "name": "phone-unavailable.png", + "scenario": "PR42 v1 Design.psd: absent binary preview, truthful object sizes from pointer, no Mark reviewed.", + "sha256": "d81ff6f4954ea7621ebdc7b7c46ef3dbc4191774400238a04cc322e6e02de340" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "name": "phone-document-source.png", + "scenario": "PR42 README reviewed at v1 then v2 link-target-only edit. Source comparison is v1 \u2192 v2, horizontally scrolled to reveal the changed URL suffix.", + "sha256": "98c873cc34cebc601d92d93b065a8ec9d13f6866e8b1101b7908f013f0eea7ac" + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "initialCodeMetrics": { + "paneTop": 195, + "paneHeight": 648, + "firstCodeRowTop": 194, + "firstCodeTableTop": 195 + }, + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "name": "tablet-unavailable.png", + "scenario": "Independent reviewer final Design.psd unavailable metadata inspection; concise Object bytes label preserves readable object-ID column.", + "sha256": "283abf7279df64f23137e019818465de6b56ce2dc3983dac0de130fe5c807283" + } + ], + "directFileLoadAndMark": "passed", + "archives": [ + { + "path": "iteration-01.html", + "commit": "2e3653877bf141964805d417eac0b94c03a24c6a", + "sha256": "9268a1a8fb1207844b305880821fc9dfe3978c6042157383e0cdd81b007cd2d2", + "byteIdentity": "passed" + }, + { + "path": "iteration-02.html", + "commit": "e1c1059cf28a2954a0513d2514e7d0b7be9c34dd", + "sha256": "78aa083a6350417961967a75ef26788c734b9e3f445d39abbb16e262ec9e3a8b", + "byteIdentity": "passed" + }, + { + "path": "iteration-03.html", + "commit": "58c13ac56f87688548887172fef6f39e818bc819", + "sha256": "f2adc670df7668d0c99d79f3ac0d9abeea3df701f56a53e1373de331c2eb274f", + "byteIdentity": "passed" + } + ], + "independentReview": { + "conclusion": "No actionable findings remain", + "finalHTMLSHA256": "fe137ea8e41335bbb0c25a203f6b27aac689bcdb2ce725420a63ab5b50dc8b00", + "initialSourceSHA256": "54e72c65497f2edf1ce215d6ad57a56496077ae4cbb38938937a317d8dcf5f50", + "scope": "Complete implementation/catalog/current plan contracts and prior fix history; three-size policy/type/sibling/focus checks, prepared diffs, SVG metadata, raw localization, archive identity.", + "findings": [ + { + "trigger": "Comparison menu on a remaining file", + "failure": "Skip aria-label did not contain its visible action phrase; axe label-content-name-mismatch.", + "correction": "Use visible label/helper as accessible name; group labels include count, remaining and separating whitespace.", + "verification": "Individual and grouped menus pass all three widths; final feature WCAG scans pass." + }, + { + "trigger": "Unavailable Design.psd metadata", + "failure": "Referenced binary size was labelled Pointer size.", + "correction": "Label Object bytes; existing warning identifies pointer provenance. Source explicitly identifies pointer-only content.", + "verification": "Metadata and source reviewed at all three sizes; Mark reviewed unavailable." + }, + { + "trigger": "First corrected size label in tablet tiled card", + "failure": "Long provenance label squeezed object ID into a 22px-wide, 363px-tall column.", + "correction": "Concise Object bytes preserves truth while warning supplies provenance.", + "verification": "Final tablet object ID is 99px wide / 66px tall, visually reviewed." + } + ], + "siblingChecks": [ + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "checks": [ + "independent review child file/expansion/format/comparison", + "shared actual review and skip receipts with distinct comparison bases", + "zero remaining reports skips separately", + "explicit review clears available skip only", + "group undo no receipt creation", + "last-child close/Escape/reopen/Research Enter", + "search/source/Review unavailable fallback" + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "checks": [ + "independent review child file/expansion/format/comparison", + "shared actual review and skip receipts with distinct comparison bases", + "zero remaining reports skips separately", + "explicit review clears available skip only", + "group undo no receipt creation", + "last-child close/Escape/reopen/Research Enter", + "search/source/Review unavailable fallback" + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "checks": [ + "independent review child file/expansion/format/comparison", + "shared actual review and skip receipts with distinct comparison bases", + "zero remaining reports skips separately", + "explicit review clears available skip only", + "group undo no receipt creation", + "last-child close/Escape/reopen/Research Enter", + "search/source/Review unavailable fallback" + ], + "errors": [] + } + ], + "finalMetadataChecks": [ + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "hash": "fe137ea8e41335bbb0c25a203f6b27aac689bcdb2ce725420a63ab5b50dc8b00", + "metadataMetrics": [ + { + "width": 364, + "grid": "66.8438px 263.156px", + "objectIdWidth": 263, + "objectIdHeight": 33 + }, + { + "width": 364, + "grid": "66.8438px 263.156px", + "objectIdWidth": 263, + "objectIdHeight": 33 + } + ], + "errors": [] + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "hash": "fe137ea8e41335bbb0c25a203f6b27aac689bcdb2ce725420a63ab5b50dc8b00", + "metadataMetrics": [ + { + "width": 200, + "grid": "66.8438px 98.6719px", + "objectIdWidth": 99, + "objectIdHeight": 66 + }, + { + "width": 200, + "grid": "66.8438px 98.6875px", + "objectIdWidth": 99, + "objectIdHeight": 66 + } + ], + "errors": [] + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "hash": "fe137ea8e41335bbb0c25a203f6b27aac689bcdb2ce725420a63ab5b50dc8b00", + "metadataMetrics": [ + { + "width": 379, + "grid": "66.8438px 278px", + "objectIdWidth": 278, + "objectIdHeight": 33 + }, + { + "width": 379, + "grid": "66.8438px 278.016px", + "objectIdWidth": 278, + "objectIdHeight": 33 + } + ], + "errors": [] + } + ], + "unfilteredAuditLimits": [ + "page-has-heading-one", + "region (#arrange-help outside landmark)" + ], + "unfilteredAuditLimitNote": "Inherited best-practice notices outside selected WCAG tags; not introduced findings or a complete accessibility audit." + }, + "limits": [ + "Two UI revisions cannot exercise a third live push after reviewing v1 and skipping v2. Later-head selection was a separate seeded content-identity/disposition/basis assertion; no third revision rendering.", + "Prepared fixtures do not establish Git, Markdown/catalog parsing, LFS/provider/network integration, native windows/execution, persistence or sync.", + "Viewport checks do not establish native device or VoiceOver acceptance.", + "Default web lint globs exclude this HTML. Native suites, image snapshots and SwiftFormat were not run for this browser-only slice.", + "Fourth user evaluation remains pending; experiment status executing and issue In Review." + ], + "staticChecks": { + "inlineJavaScriptSyntax": "passed", + "localLinksAndAnchors": 84, + "markdownFences": "passed", + "captureHashes": 16, + "archiveByteIdentities": 3, + "diffWhitespace": "passed" + } +} diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/phone.png b/Plans/2026-11-14-mobius/Prototype/evidence/phone.png new file mode 100644 index 000000000..77197512a Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/phone.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/tablet.png b/Plans/2026-11-14-mobius/Prototype/evidence/tablet.png new file mode 100644 index 000000000..2f2c5eb18 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/tablet.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/verification.json b/Plans/2026-11-14-mobius/Prototype/evidence/verification.json new file mode 100644 index 000000000..03c6da8ee --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/evidence/verification.json @@ -0,0 +1,55 @@ +{ + "date": "2026-11-14", + "artifact": "index.html", + "sha256": "9268a1a8fb1207844b305880821fc9dfe3978c6042157383e0cdd81b007cd2d2", + "tooling": { + "playwright": "1.64.1", + "axePlaywright": "4.14.0", + "chromium": "156.0.8078.4" + }, + "method": "Ad hoc Playwright browser interaction through visible controls; prepared fixtures, not Git algorithm tests.", + "viewports": [ + { + "name": "desktop", + "width": 1440, + "height": 1000, + "errors": [], + "externalRequests": [], + "violations": [], + "result": "scenario passed" + }, + { + "name": "tablet", + "width": 834, + "height": 1112, + "errors": [], + "externalRequests": [], + "violations": [], + "result": "scenario passed" + }, + { + "name": "phone", + "width": 390, + "height": 844, + "errors": [], + "externalRequests": [], + "violations": [], + "result": "scenario passed" + } + ], + "additionalPassedChecks": [ + "PR43 reviewed Store v1 to v2 uses savedSearches in incremental and full comparisons", + "Post-push and saved-draft axe WCAG 2/2.1 A/AA scans at all three viewports", + "Keyboard Enter on Mark reviewed focuses the resulting document", + "Phone drawer comparison change followed by Escape restores the file-list opener", + "Standalone file URL load and mark-reviewed interaction", + "No document-level horizontal overflow; long code scrolls inside its pane" + ], + "review": "Fresh independent subagent review; supported parsing, fixture consistency, focus, contrast and accessible-name findings corrected and rechecked.", + "limits": [ + "User evaluation pending", + "No native or VoiceOver testing", + "No persistence, provider, Git algorithm or sync validation", + "Automated accessibility scans are not a complete accessibility audit" + ] +} diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/desktop-empty.png b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/desktop-empty.png new file mode 100644 index 000000000..7e941ad8a Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/desktop-empty.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/desktop-picker.png b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/desktop-picker.png new file mode 100644 index 000000000..cf4651bde Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/desktop-picker.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/desktop-reopened.png b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/desktop-reopened.png new file mode 100644 index 000000000..8e4420576 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/desktop-reopened.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/phone-empty.png b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/phone-empty.png new file mode 100644 index 000000000..26d495f54 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/phone-empty.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/phone-picker.png b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/phone-picker.png new file mode 100644 index 000000000..e6c6bf5c1 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/phone-picker.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/phone-reopened.png b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/phone-reopened.png new file mode 100644 index 000000000..0a08da5e7 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/phone-reopened.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/tablet-empty.png b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/tablet-empty.png new file mode 100644 index 000000000..10c125472 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/tablet-empty.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/tablet-picker.png b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/tablet-picker.png new file mode 100644 index 000000000..2cb6b5b7b Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/tablet-picker.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/tablet-reopened.png b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/tablet-reopened.png new file mode 100644 index 000000000..e6ef570a6 Binary files /dev/null and b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/tablet-reopened.png differ diff --git a/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/verification.json b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/verification.json new file mode 100644 index 000000000..7227f1fb2 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/evidence/workspace-close/verification.json @@ -0,0 +1,897 @@ +{ + "scope": "Retained workspace close/reopen follow-up; prior evidence remains historical and unchanged.", + "baseCommit": "7c052169683ebc4bd6ee4ff22495365d74fc81a6", + "parentCommit": "ecb3c017da2a1b812df1a3f5235e460448ee2bcd", + "sourceSHA256": "c99c3a8670006ca787dd5880ff9e04834b777d682f1dca7515688f94c6cad89b", + "contractMap": { + "ownership": "Open presentation is separate from retained workspace and child identity/state.", + "activation": "Inactive close preserves active/focus; active close chooses next then previous; last close has active=null. Only explicit reopen and Reset open closed workspaces.", + "resumption": "Same child/layout/routes/receipts/draft; Review returns to its own file top, non-review retains focus.", + "events": "Global controls tolerate no active owner; closed child events are ignored; sample push may update closed revision without activation.", + "guards": "Ad hoc isolated fixture evidence, not retained CI tests." + }, + "tools": { + "playwright": "1.64.1", + "chromium": "156.0.8078.4", + "webkit": "27.2 (scoped coordinator checks)", + "axe": "4.14.0" + }, + "commands": [ + "mise exec -- node /tmp/mobius-close-verify.cjs", + "mise exec -- node /tmp/mobius-close-captures.cjs", + "mise exec -- node /tmp/mobius-workspace-close-review.cjs", + "mise exec -- node /tmp/mobius-workspace-close-review-extra.cjs", + "mise exec -- node /tmp/mobius-close-root-check.cjs" + ], + "author": { + "sourceSHA256": "c99c3a8670006ca787dd5880ff9e04834b777d682f1dca7515688f94c6cad89b", + "reports": [ + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "presentation": "tabs", + "checks": [ + "inactive closure preserves active PR/focused research, state and reachable outer close", + "active closure selects remaining neighbor without changing retained workspace", + "closed fixture push changes revision only, preserving active PR and review/skip baselines", + "keyboard last closure has explicit no-active state, no hosts/tabs, focused Workspaces recovery", + "all-closed viewport/presentation changes and stale child events cannot reopen or mutate retained state", + "picker keyboard/Escape and reopen restore same workspace/children, non-review focus, frames, draft and routes", + "repeated switch/reopen entry does not duplicate identities or lose context", + "Review reopen retains selected file/comparison and receipt, resumes at file top", + "titlebar drag/click and keyboard movement/resize retained after reopen", + "workspace with no children reopens empty and creates one new child", + "Reset deliberately restores the initial two-open-workspace session" + ], + "audits": [ + { + "state": "two open workspaces", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + }, + { + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "presentation": "windows", + "checks": [ + "inactive closure preserves active PR/focused research, state and reachable outer close", + "active closure selects remaining neighbor without changing retained workspace", + "closed fixture push changes revision only, preserving active PR and review/skip baselines", + "keyboard last closure has explicit no-active state, no hosts/tabs, focused Workspaces recovery", + "all-closed viewport/presentation changes and stale child events cannot reopen or mutate retained state", + "picker keyboard/Escape and reopen restore same workspace/children, non-review focus, frames, draft and routes", + "repeated switch/reopen entry does not duplicate identities or lose context", + "Review reopen retains selected file/comparison and receipt, resumes at file top", + "titlebar drag/click and keyboard movement/resize retained after reopen", + "workspace with no children reopens empty and creates one new child", + "Reset deliberately restores the initial two-open-workspace session" + ], + "audits": [ + { + "state": "all closed", + "violations": [] + }, + { + "state": "retained-workspace picker", + "violations": [] + }, + { + "state": "reopened floating review", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "presentation": "tabs", + "checks": [ + "inactive closure preserves active PR/focused research, state and reachable outer close", + "active closure selects remaining neighbor without changing retained workspace", + "closed fixture push changes revision only, preserving active PR and review/skip baselines", + "keyboard last closure has explicit no-active state, no hosts/tabs, focused Workspaces recovery", + "all-closed viewport/presentation changes and stale child events cannot reopen or mutate retained state", + "picker keyboard/Escape and reopen restore same workspace/children, non-review focus, frames, draft and routes", + "repeated switch/reopen entry does not duplicate identities or lose context", + "Review reopen retains selected file/comparison and receipt, resumes at file top", + "titlebar drag/click and keyboard movement/resize retained after reopen", + "workspace with no children reopens empty and creates one new child", + "Reset deliberately restores the initial two-open-workspace session" + ], + "audits": [ + { + "state": "two open workspaces", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + }, + { + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "presentation": "windows", + "checks": [ + "inactive closure preserves active PR/focused research, state and reachable outer close", + "active closure selects remaining neighbor without changing retained workspace", + "closed fixture push changes revision only, preserving active PR and review/skip baselines", + "keyboard last closure has explicit no-active state, no hosts/tabs, focused Workspaces recovery", + "all-closed viewport/presentation changes and stale child events cannot reopen or mutate retained state", + "picker keyboard/Escape and reopen restore same workspace/children, non-review focus, frames, draft and routes", + "repeated switch/reopen entry does not duplicate identities or lose context", + "Review reopen retains selected file/comparison and receipt, resumes at file top", + "titlebar drag/click and keyboard movement/resize retained after reopen", + "workspace with no children reopens empty and creates one new child", + "Reset deliberately restores the initial two-open-workspace session" + ], + "audits": [ + { + "state": "all closed", + "violations": [] + }, + { + "state": "retained-workspace picker", + "violations": [] + }, + { + "state": "reopened floating review", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "presentation": "tabs", + "checks": [ + "inactive closure preserves active PR/focused research, state and reachable outer close", + "active closure selects remaining neighbor without changing retained workspace", + "closed fixture push changes revision only, preserving active PR and review/skip baselines", + "keyboard last closure has explicit no-active state, no hosts/tabs, focused Workspaces recovery", + "all-closed viewport/presentation changes and stale child events cannot reopen or mutate retained state", + "picker keyboard/Escape and reopen restore same workspace/children, non-review focus, frames, draft and routes", + "repeated switch/reopen entry does not duplicate identities or lose context", + "Review reopen retains selected file/comparison and receipt, resumes at file top", + "titlebar drag/click and keyboard movement/resize retained after reopen", + "workspace with no children reopens empty and creates one new child", + "Reset deliberately restores the initial two-open-workspace session" + ], + "audits": [ + { + "state": "two open workspaces", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + }, + { + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "presentation": "windows", + "checks": [ + "inactive closure preserves active PR/focused research, state and reachable outer close", + "active closure selects remaining neighbor without changing retained workspace", + "closed fixture push changes revision only, preserving active PR and review/skip baselines", + "keyboard last closure has explicit no-active state, no hosts/tabs, focused Workspaces recovery", + "all-closed viewport/presentation changes and stale child events cannot reopen or mutate retained state", + "picker keyboard/Escape and reopen restore same workspace/children, non-review focus, frames, draft and routes", + "repeated switch/reopen entry does not duplicate identities or lose context", + "Review reopen retains selected file/comparison and receipt, resumes at file top", + "titlebar drag/click and keyboard movement/resize retained after reopen", + "workspace with no children reopens empty and creates one new child", + "Reset deliberately restores the initial two-open-workspace session" + ], + "audits": [ + { + "state": "all closed", + "violations": [] + }, + { + "state": "retained-workspace picker", + "violations": [] + }, + { + "state": "reopened floating review", + "violations": [] + } + ], + "errors": [], + "externalRequests": [], + "documentOverflow": false + } + ] + }, + "independent": { + "disposition": "No actionable findings", + "lifecycle": { + "sourceSHA256": "c99c3a8670006ca787dd5880ff9e04834b777d682f1dca7515688f94c6cad89b", + "reports": [ + { + "viewport": { + "width": 390, + "height": 844 + }, + "mode": "tabs", + "checks": [ + "inactive closure removes presentation and preserves active Research/data", + "reopen and repeated Switch preserve retained data and child counts", + "active closure selects deterministic previous/next neighbor", + "closed sample push updates revision only", + "last closure has explicit empty/no-active state and keyboard/Escape recovery", + "all-closed width/presentation changes do not reopen or mutate context", + "stale closed child/selector actions do not reopen or author data", + "reopen restores Research query/focus and Review selected-file/top; receipts/draft intact", + "reopened title text still drags +8/+12 and stationary click opens chooser", + "empty-child close/reopen preserves collection and New view recovery", + "Reset deliberately recreates the initial session" + ], + "errors": [], + "auditViolations": [] + }, + { + "viewport": { + "width": 390, + "height": 844 + }, + "mode": "windows", + "checks": [ + "inactive closure removes presentation and preserves active Research/data", + "reopen and repeated Switch preserve retained data and child counts", + "active closure selects deterministic previous/next neighbor", + "closed sample push updates revision only", + "last closure has explicit empty/no-active state and keyboard/Escape recovery", + "all-closed width/presentation changes do not reopen or mutate context", + "stale closed child/selector actions do not reopen or author data", + "reopen restores Research query/focus and Review selected-file/top; receipts/draft intact", + "reopened title text still drags +8/+12 and stationary click opens chooser", + "empty-child close/reopen preserves collection and New view recovery", + "Reset deliberately recreates the initial session" + ], + "errors": [], + "auditViolations": [] + }, + { + "viewport": { + "width": 834, + "height": 1112 + }, + "mode": "tabs", + "checks": [ + "inactive closure removes presentation and preserves active Research/data", + "reopen and repeated Switch preserve retained data and child counts", + "active closure selects deterministic previous/next neighbor", + "closed sample push updates revision only", + "last closure has explicit empty/no-active state and keyboard/Escape recovery", + "all-closed width/presentation changes do not reopen or mutate context", + "stale closed child/selector actions do not reopen or author data", + "reopen restores Research query/focus and Review selected-file/top; receipts/draft intact", + "reopened title text still drags +8/+12 and stationary click opens chooser", + "empty-child close/reopen preserves collection and New view recovery", + "Reset deliberately recreates the initial session" + ], + "errors": [], + "auditViolations": [] + }, + { + "viewport": { + "width": 834, + "height": 1112 + }, + "mode": "windows", + "checks": [ + "inactive closure removes presentation and preserves active Research/data", + "reopen and repeated Switch preserve retained data and child counts", + "active closure selects deterministic previous/next neighbor", + "closed sample push updates revision only", + "last closure has explicit empty/no-active state and keyboard/Escape recovery", + "all-closed width/presentation changes do not reopen or mutate context", + "stale closed child/selector actions do not reopen or author data", + "reopen restores Research query/focus and Review selected-file/top; receipts/draft intact", + "reopened title text still drags +8/+12 and stationary click opens chooser", + "empty-child close/reopen preserves collection and New view recovery", + "Reset deliberately recreates the initial session" + ], + "errors": [], + "auditViolations": [] + }, + { + "viewport": { + "width": 1440, + "height": 1000 + }, + "mode": "tabs", + "checks": [ + "inactive closure removes presentation and preserves active Research/data", + "reopen and repeated Switch preserve retained data and child counts", + "active closure selects deterministic previous/next neighbor", + "closed sample push updates revision only", + "last closure has explicit empty/no-active state and keyboard/Escape recovery", + "all-closed width/presentation changes do not reopen or mutate context", + "stale closed child/selector actions do not reopen or author data", + "reopen restores Research query/focus and Review selected-file/top; receipts/draft intact", + "reopened title text still drags +8/+12 and stationary click opens chooser", + "empty-child close/reopen preserves collection and New view recovery", + "Reset deliberately recreates the initial session" + ], + "errors": [], + "auditViolations": [] + }, + { + "viewport": { + "width": 1440, + "height": 1000 + }, + "mode": "windows", + "checks": [ + "inactive closure removes presentation and preserves active Research/data", + "reopen and repeated Switch preserve retained data and child counts", + "active closure selects deterministic previous/next neighbor", + "closed sample push updates revision only", + "last closure has explicit empty/no-active state and keyboard/Escape recovery", + "all-closed width/presentation changes do not reopen or mutate context", + "stale closed child/selector actions do not reopen or author data", + "reopen restores Research query/focus and Review selected-file/top; receipts/draft intact", + "reopened title text still drags +8/+12 and stationary click opens chooser", + "empty-child close/reopen preserves collection and New view recovery", + "Reset deliberately recreates the initial session" + ], + "errors": [], + "auditViolations": [] + } + ] + }, + "touchAndBoundary": { + "sourceSHA256": "c99c3a8670006ca787dd5880ff9e04834b777d682f1dca7515688f94c6cad89b", + "reports": [ + { + "viewport": { + "width": 320, + "height": 700 + }, + "windowCloseSize": { + "width": 44, + "height": 44 + }, + "tabCloseSize": { + "width": 44, + "height": 44 + }, + "checks": [ + "real touch close/reopen in Windows and Tabs", + "close center hit-tested", + "all-closed sample pushes do not reopen; v2 appears on explicit reopen" + ], + "errors": [] + }, + { + "viewport": { + "width": 390, + "height": 844 + }, + "windowCloseSize": { + "width": 44, + "height": 44 + }, + "tabCloseSize": { + "width": 44, + "height": 44 + }, + "checks": [ + "real touch close/reopen in Windows and Tabs", + "close center hit-tested", + "all-closed sample pushes do not reopen; v2 appears on explicit reopen" + ], + "errors": [] + }, + { + "viewport": { + "width": 834, + "height": 1112 + }, + "windowCloseSize": { + "width": 44, + "height": 44 + }, + "tabCloseSize": { + "width": 36, + "height": 36 + }, + "checks": [ + "real touch close/reopen in Windows and Tabs", + "close center hit-tested", + "all-closed sample pushes do not reopen; v2 appears on explicit reopen" + ], + "errors": [] + }, + { + "viewport": { + "width": 1440, + "height": 1000 + }, + "checks": [ + "keyboard workspace close during active title drag releases capture; pointer-up cannot reopen/activate; subsequent reopen/click works" + ], + "errors": [] + } + ] + } + }, + "coordinatorCrossEngine": { + "sourceSHA256": "c99c3a8670006ca787dd5880ff9e04834b777d682f1dca7515688f94c6cad89b", + "reports": [ + { + "engine": "Chromium", + "version": "156.0.8078.4", + "viewport": { + "width": 390, + "height": 844 + }, + "checks": "Inactive/last closure, all-closed presentation switch, same-state reopening, review-top return, title-bar drag, reopening second PR and active close", + "errors": [] + }, + { + "engine": "Chromium", + "version": "156.0.8078.4", + "viewport": { + "width": 1440, + "height": 1000 + }, + "checks": "Inactive/last closure, all-closed presentation switch, same-state reopening, review-top return, title-bar drag, reopening second PR and active close", + "errors": [] + }, + { + "engine": "WebKit", + "version": "27.2", + "viewport": { + "width": 390, + "height": 844 + }, + "checks": "Inactive/last closure, all-closed presentation switch, same-state reopening, review-top return, title-bar drag, reopening second PR and active close", + "errors": [] + }, + { + "engine": "WebKit", + "version": "27.2", + "viewport": { + "width": 1440, + "height": 1000 + }, + "checks": "Inactive/last closure, all-closed presentation switch, same-state reopening, review-top return, title-bar drag, reopening second PR and active close", + "errors": [] + } + ] + }, + "captures": { + "sourceSHA256": "c99c3a8670006ca787dd5880ff9e04834b777d682f1dca7515688f94c6cad89b", + "captures": [ + { + "name": "phone-picker.png", + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "presentation": "tabs", + "state": "picker", + "sha256": "3da87e0cd94f7e63818e38bf1acb521228dc103e6df7512e0c39921c0336c2f8", + "activeWorkspace": 43, + "workspaces": [ + { + "number": 42, + "open": false, + "focused": "42-1", + "layout": "float", + "childIDs": [ + "42-1", + "42-2", + "42-3" + ], + "selectedReviewFiles": [ + "Store.swift" + ], + "draftRetained": true + }, + { + "number": 43, + "open": true, + "focused": "43-1", + "layout": "focus", + "childIDs": [ + "43-1", + "43-2" + ], + "selectedReviewFiles": [ + "Parser.swift" + ], + "draftRetained": false + } + ] + }, + { + "name": "phone-empty.png", + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "presentation": "tabs", + "state": "empty", + "sha256": "8ea94aff1f37109fa54acbbe3c3e7b5b5191d8efe3b47d6a6f93e5ba3fa51ca7", + "activeWorkspace": null, + "workspaces": [ + { + "number": 42, + "open": false, + "focused": "42-1", + "layout": "float", + "childIDs": [ + "42-1", + "42-2", + "42-3" + ], + "selectedReviewFiles": [ + "Store.swift" + ], + "draftRetained": true + }, + { + "number": 43, + "open": false, + "focused": "43-1", + "layout": "focus", + "childIDs": [ + "43-1", + "43-2" + ], + "selectedReviewFiles": [ + "Parser.swift" + ], + "draftRetained": false + } + ] + }, + { + "name": "phone-reopened.png", + "viewport": { + "name": "phone", + "width": 390, + "height": 844 + }, + "presentation": "tabs", + "state": "reopened", + "sha256": "15a109848cbfbf9562c1ccf26eb63dd8a038e12e64d561e16c08f5d394d5011b", + "activeWorkspace": 42, + "workspaces": [ + { + "number": 42, + "open": true, + "focused": "42-1", + "layout": "float", + "childIDs": [ + "42-1", + "42-2", + "42-3" + ], + "selectedReviewFiles": [ + "Store.swift" + ], + "draftRetained": true + }, + { + "number": 43, + "open": false, + "focused": "43-1", + "layout": "focus", + "childIDs": [ + "43-1", + "43-2" + ], + "selectedReviewFiles": [ + "Parser.swift" + ], + "draftRetained": false + } + ] + }, + { + "name": "tablet-picker.png", + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "presentation": "windows", + "state": "picker", + "sha256": "12cd6a1896667d20855fc4007a58fbd9cdd2fca8e367336547057f526c8178a2", + "activeWorkspace": 43, + "workspaces": [ + { + "number": 42, + "open": false, + "focused": "42-1", + "layout": "float", + "childIDs": [ + "42-1", + "42-2", + "42-3" + ], + "selectedReviewFiles": [ + "Store.swift" + ], + "draftRetained": true + }, + { + "number": 43, + "open": true, + "focused": "43-1", + "layout": "tiles", + "childIDs": [ + "43-1", + "43-2" + ], + "selectedReviewFiles": [ + "Parser.swift" + ], + "draftRetained": false + } + ] + }, + { + "name": "tablet-empty.png", + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "presentation": "windows", + "state": "empty", + "sha256": "e93b18830d29e7ba40842d5e71826d5d343e60a8abe324f6aa01a5d2b8d99230", + "activeWorkspace": null, + "workspaces": [ + { + "number": 42, + "open": false, + "focused": "42-1", + "layout": "float", + "childIDs": [ + "42-1", + "42-2", + "42-3" + ], + "selectedReviewFiles": [ + "Store.swift" + ], + "draftRetained": true + }, + { + "number": 43, + "open": false, + "focused": "43-1", + "layout": "tiles", + "childIDs": [ + "43-1", + "43-2" + ], + "selectedReviewFiles": [ + "Parser.swift" + ], + "draftRetained": false + } + ] + }, + { + "name": "tablet-reopened.png", + "viewport": { + "name": "tablet", + "width": 834, + "height": 1112 + }, + "presentation": "windows", + "state": "reopened", + "sha256": "cbf669e6d35d716a69f68a78c8d5014d5925a26d3ad158018c5e7f6d1c8f5b4b", + "activeWorkspace": 42, + "workspaces": [ + { + "number": 42, + "open": true, + "focused": "42-1", + "layout": "float", + "childIDs": [ + "42-1", + "42-2", + "42-3" + ], + "selectedReviewFiles": [ + "Store.swift" + ], + "draftRetained": true + }, + { + "number": 43, + "open": false, + "focused": "43-1", + "layout": "tiles", + "childIDs": [ + "43-1", + "43-2" + ], + "selectedReviewFiles": [ + "Parser.swift" + ], + "draftRetained": false + } + ] + }, + { + "name": "desktop-picker.png", + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "presentation": "windows", + "state": "picker", + "sha256": "218edcfaf2223078409af81d4ad780e2d2ee4f03a132f03882d0458375ed733f", + "activeWorkspace": 43, + "workspaces": [ + { + "number": 42, + "open": false, + "focused": "42-1", + "layout": "float", + "childIDs": [ + "42-1", + "42-2", + "42-3" + ], + "selectedReviewFiles": [ + "Store.swift" + ], + "draftRetained": true + }, + { + "number": 43, + "open": true, + "focused": "43-1", + "layout": "tiles", + "childIDs": [ + "43-1", + "43-2" + ], + "selectedReviewFiles": [ + "Parser.swift" + ], + "draftRetained": false + } + ] + }, + { + "name": "desktop-empty.png", + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "presentation": "windows", + "state": "empty", + "sha256": "1e151d3cebedf70edc0e4c1c6776a4bec7e900255bcb8898aeae11afa8b5821b", + "activeWorkspace": null, + "workspaces": [ + { + "number": 42, + "open": false, + "focused": "42-1", + "layout": "float", + "childIDs": [ + "42-1", + "42-2", + "42-3" + ], + "selectedReviewFiles": [ + "Store.swift" + ], + "draftRetained": true + }, + { + "number": 43, + "open": false, + "focused": "43-1", + "layout": "tiles", + "childIDs": [ + "43-1", + "43-2" + ], + "selectedReviewFiles": [ + "Parser.swift" + ], + "draftRetained": false + } + ] + }, + { + "name": "desktop-reopened.png", + "viewport": { + "name": "desktop", + "width": 1440, + "height": 1000 + }, + "presentation": "windows", + "state": "reopened", + "sha256": "f5bc6625a61dd3708b11aeb407bdc4c6200349f4e8cc947608af59d1f8aaa66a", + "activeWorkspace": 42, + "workspaces": [ + { + "number": 42, + "open": true, + "focused": "42-1", + "layout": "float", + "childIDs": [ + "42-1", + "42-2", + "42-3" + ], + "selectedReviewFiles": [ + "Store.swift" + ], + "draftRetained": true + }, + { + "number": 43, + "open": false, + "focused": "43-1", + "layout": "tiles", + "childIDs": [ + "43-1", + "43-2" + ], + "selectedReviewFiles": [ + "Parser.swift" + ], + "draftRetained": false + } + ] + } + ] + }, + "captureSetup": "PR42 v1: Parser marked reviewed, Store selected, draft saved, Float. Phone uses Tabs; tablet/desktop Windows. Picker after closing PR42, empty after closing PR43, reopen PR42 with retained Store/children/draft. Light, 1x; actual transient toast cleared before capture; all nine inspected.", + "authorCorrection": "Expanded the narrow 44px target rule to the new outer window-close button, which is outside the existing workspace-actions group. Final-source runtime/hit checks include this correction.", + "limits": [ + "In-memory synthetic two-PR fixture; no GitHub closure, deletion, repository browsing or native implementation.", + "No cross-device open/closed policy; Q09 remains deferred.", + "Scoped WebKit checks are not a full Safari/device matrix.", + "No live-user-browser or VoiceOver acceptance; selected WCAG scans are partial automated evidence.", + "Default lint excludes this HTML; native tests/snapshots/SwiftFormat and unrelated type-catalog scenarios were not rerun.", + "User evaluation remains pending; experiment executing and issue In Review." + ] +} diff --git a/Plans/2026-11-14-mobius/Prototype/iteration-01.html b/Plans/2026-11-14-mobius/Prototype/iteration-01.html new file mode 100644 index 000000000..b379ad816 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/iteration-01.html @@ -0,0 +1,571 @@ + + + + + + +Mobius — a place for every review + + + +
+
Mobius/ Interaction studySample data
+
+
+
+ + + +

Review draft

+

+ +
+
+ + + diff --git a/Plans/2026-11-14-mobius/Prototype/iteration-02.html b/Plans/2026-11-14-mobius/Prototype/iteration-02.html new file mode 100644 index 000000000..d2f39457a --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/iteration-02.html @@ -0,0 +1,664 @@ + + + + + + +Mobius — a workspace for every review + + + +
Mobius/ Workspace study 02Sample data
+
+ + +

In floating layout, drag a view title to move it. Arrow keys move the view; Shift and arrow keys resize it. The corner handle also supports arrow-key resizing.

+
+ + + diff --git a/Plans/2026-11-14-mobius/Prototype/iteration-03.html b/Plans/2026-11-14-mobius/Prototype/iteration-03.html new file mode 100644 index 000000000..3e79cb984 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/iteration-03.html @@ -0,0 +1,651 @@ + + + + + + +Mobius — a workspace for every review + + + +
mobius
Sample dataControls

Prototype controls

PR #42
PR #43

Offline sample session. Previews are simulated; no code is running.

+
+ +

In floating layout, drag a view icon to move it. Arrow keys move the view; Shift and arrow keys resize it. The corner handle also supports arrow-key resizing.

+
+ + + diff --git a/Plans/2026-11-14-mobius/Prototype/iteration-04.html b/Plans/2026-11-14-mobius/Prototype/iteration-04.html new file mode 100644 index 000000000..a264a92b5 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/iteration-04.html @@ -0,0 +1,751 @@ + + + + + + +Mobius — a workspace for every review + + + +
mobius
Sample dataControls

Prototype controls

PR #42
PR #43

Offline sample session. Previews are simulated; no code is running.

+
+ +

In floating layout, drag a view icon to move it. Arrow keys move the view; Shift and arrow keys resize it. The corner handle also supports arrow-key resizing.

+
+ + + diff --git a/Plans/2026-11-14-mobius/Prototype/pre-astro.html b/Plans/2026-11-14-mobius/Prototype/pre-astro.html new file mode 100644 index 000000000..56d535111 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/pre-astro.html @@ -0,0 +1,848 @@ + + + + + + +Mobius — a workspace for every review + + + +
mobius
Sample dataControls

Prototype controls

PR #42
PR #43

Offline sample session. Previews are simulated; no code is running.

+
+ +

In floating layout, drag the view title bar or icon to move it. Click a filename without dragging to choose a file. With the move icon focused, arrow keys move the view; Shift and arrow keys resize it. The corner handle also supports arrow-key resizing.

+
+ + + diff --git a/Plans/2026-11-14-mobius/Prototype/src/app.js b/Plans/2026-11-14-mobius/Prototype/src/app.js new file mode 100644 index 000000000..fe493e944 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/src/app.js @@ -0,0 +1,598 @@ + + +'use strict'; +// Deliberately small, prepared fixtures. This is not a Git engine or a production state schema. +const icons = { + pr: '', + file: '', + search: '', + sidebar: '', + check: '', + comment: '', + refresh: '', + plus: '', + link: '', + folder: '', + chevron: '' +}; +const icon = name => ``; +const escapeHTML = value => String(value).replace(/[&<>"']/g, char => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[char])); +const rows = text => text.replace(/^\n|\n$/g, '').split('\n').map(line => ({kind: line[0] === '+' ? 'add' : line[0] === '-' ? 'delete' : 'context', text: line.slice(1)})); +const parserFull = version => rows(` + import Foundation + + struct Parser { + struct Query { + let terms: [String] ++ let scope: SearchScope + } + +- func parse(_ input: String) -> Query { ++ func parse(_ input: String, in scope: SearchScope) -> Query { + let normalized = input.trimmingCharacters(in: .whitespaces) + let terms = normalized.split(separator: " ").map(String.init) + +- return Query(terms: terms) ++ return Query( ++ terms: ${version === 2 ? 'terms.filter { !$0.isEmpty }' : 'terms'}, ++ scope: scope ++ ) + } + + func suggestions(for query: Query) -> [String] { + guard let first = query.terms.first else { + return [] + } + + return [first, first.lowercased()] + } + } + ++extension Parser.Query { ++ var description: String { ++ terms.joined(separator: " ") ++ } ++ ++ var isEmpty: Bool { ++ terms.isEmpty ++ } ++ ++ var scopeLabel: String { ++ switch scope { ++ case .repository: ++ return "Entire repository" ++ case .workspace: ++ return "This workspace" ++ } ++ } ++} + + // Search stays with the pull request that opened it. + // Navigating to a reference does not mark a file reviewed. +`); +const parserNew = rows(` + return Query( +- terms: terms, ++ terms: terms.filter { !$0.isEmpty }, + scope: scope + ) +`); +const storeFull = version => rows(` + import Foundation + + struct Store { +- var search: Search? ++ var searches: [WorkspaceID: Search] = [:] + +- mutating func save(_ search: Search) { +- self.search = search ++ mutating func save(_ search: Search, for workspace: WorkspaceID) { ++ searches[workspace] = search + } + ++ func search(for workspace: WorkspaceID) -> Search? { ++ searches[workspace] ++ } +${version === 2 ? '+\n+ mutating func removeSearch(for workspace: WorkspaceID) {\n+ searches.removeValue(forKey: workspace)\n+ }' : ' '} + } +`); +const storeNew = rows(` + func search(for workspace: WorkspaceID) -> Search? { + searches[workspace] + } ++ ++ mutating func removeSearch(for workspace: WorkspaceID) { ++ searches.removeValue(forKey: workspace) ++ } +`); +const stableFull = rows(` + import Foundation + ++enum SearchScope { ++ case repository ++ case workspace ++} ++ + struct Stable { + let name: String + } +`); +const referenceSource = `// Supporting source, unchanged by this pull request. +// Sample code for exploring context within a workspace. + +struct WorkspaceID: Hashable { + let number: Int +} + +struct Search { + let query: Parser.Query + let results: [SearchResult] +} + +struct SearchResult { + let path: String + let line: Int + let excerpt: String +} + +// Every search belongs to its originating PR workspace. +// Opening this file leaves review progress untouched.`; +const fixtures = { + 42: {title: 'Keep searches in their review workspace', branch: 'workspace-search', author: 'Maya Chen', initials: 'MC'}, + 43: {title: 'Restore a search when you return', branch: 'restore-search', author: 'Alex Rivera', initials: 'AR'} +}; +// Prepared fixture contents/comparisons, not runtime Markdown, catalog, or Git parsers. +const fileCatalog = {"Parser.swift":{"kind":"code","since":1,"revisions":{"1":1,"2":2},"available":true,"lfs":false},"Store.swift":{"kind":"code","since":1,"revisions":{"1":1,"2":2},"available":true,"lfs":false},"Stable.swift":{"kind":"code","since":1,"revisions":{"1":1,"2":1},"available":true,"lfs":false},"README.md":{"kind":"documents","since":1,"revisions":{"1":1,"2":2},"available":true,"lfs":false,"raw":{"0":"# Review a pull request\n\nUse repository search to understand a change.\n\n[Review guide](https://example.test/review)\n","1":"# Review a pull request\n\nKeep related research in this workspace.\n\n[Review guide](https://example.test/guides/review)\n","2":"# Review a pull request\n\nKeep related research in this workspace.\n\n[Review guide](https://example.test/guides/review#resume)\n"},"document":{"0":{"heading":"Review a pull request","text":"Use repository search to understand a change.","target":"https://example.test/review"},"1":{"heading":"Review a pull request","text":"Keep related research in this workspace.","target":"https://example.test/guides/review"},"2":{"heading":"Review a pull request","text":"Keep related research in this workspace.","target":"https://example.test/guides/review#resume"}},"diffs":{"0-1":[{"kind":"context","text":"# Review a pull request"},{"kind":"context","text":""},{"kind":"delete","text":"Use repository search to understand a change."},{"kind":"add","text":"Keep related research in this workspace."},{"kind":"context","text":""},{"kind":"delete","text":"[Review guide](https://example.test/review)"},{"kind":"add","text":"[Review guide](https://example.test/guides/review)"}],"0-2":[{"kind":"context","text":"# Review a pull request"},{"kind":"context","text":""},{"kind":"delete","text":"Use repository search to understand a change."},{"kind":"add","text":"Keep related research in this workspace."},{"kind":"context","text":""},{"kind":"delete","text":"[Review guide](https://example.test/review)"},{"kind":"add","text":"[Review guide](https://example.test/guides/review#resume)"}],"1-2":[{"kind":"context","text":"# Review a pull request"},{"kind":"context","text":""},{"kind":"context","text":"Keep related research in this workspace."},{"kind":"context","text":""},{"kind":"delete","text":"[Review guide](https://example.test/guides/review)"},{"kind":"add","text":"[Review guide](https://example.test/guides/review#resume)"}]}},"Localizable.xcstrings":{"kind":"localization","since":1,"revisions":{"1":1,"2":2},"available":true,"lfs":false,"raw":{"0":"{\n \"sourceLanguage\": \"en\",\n \"strings\": {\n \"search.title\": {\n \"localizations\": {\n \"en\": {\n \"stringUnit\": {\n \"state\": \"translated\",\n \"value\": \"Search\"\n }\n },\n \"fr\": {\n \"stringUnit\": {\n \"state\": \"translated\",\n \"value\": \"Rechercher\"\n }\n }\n }\n },\n \"search.empty\": {\n \"localizations\": {\n \"en\": {\n \"stringUnit\": {\n \"state\": \"translated\",\n \"value\": \"No results\"\n }\n }\n }\n }\n },\n \"version\": \"1.0\"\n}\n","1":"{\n \"sourceLanguage\": \"en\",\n \"strings\": {\n \"search.title\": {\n \"localizations\": {\n \"en\": {\n \"stringUnit\": {\n \"state\": \"translated\",\n \"value\": \"Search this workspace\"\n }\n },\n \"fr\": {\n \"stringUnit\": {\n \"state\": \"translated\",\n \"value\": \"Rechercher ici\"\n }\n }\n }\n },\n \"search.empty\": {\n \"localizations\": {\n \"en\": {\n \"stringUnit\": {\n \"state\": \"translated\",\n \"value\": \"No matches\"\n }\n }\n }\n }\n },\n \"version\": \"1.0\"\n}\n","2":"{\n \"sourceLanguage\": \"en\",\n \"strings\": {\n \"search.title\": {\n \"localizations\": {\n \"en\": {\n \"stringUnit\": {\n \"state\": \"translated\",\n \"value\": \"Search this workspace\"\n }\n },\n \"fr\": {\n \"stringUnit\": {\n \"state\": \"translated\",\n \"value\": \"Rechercher cet espace\"\n }\n },\n \"de\": {\n \"stringUnit\": {\n \"state\": \"translated\",\n \"value\": \"Arbeitsbereich durchsuchen\"\n }\n }\n }\n },\n \"search.empty\": {\n \"localizations\": {\n \"en\": {\n \"stringUnit\": {\n \"state\": \"translated\",\n \"value\": \"No matches\"\n }\n }\n }\n }\n },\n \"version\": \"1.0\"\n}\n"},"entries":{"0":{"search.title":{"en":"Search","fr":"Rechercher"},"search.empty":{"en":"No results"}},"1":{"search.title":{"en":"Search this workspace","fr":"Rechercher ici"},"search.empty":{"en":"No matches"}},"2":{"search.title":{"en":"Search this workspace","fr":"Rechercher cet espace","de":"Arbeitsbereich durchsuchen"},"search.empty":{"en":"No matches"}}},"diffs":{"0-1":[{"kind":"context","text":"{"},{"kind":"context","text":" \"sourceLanguage\": \"en\","},{"kind":"context","text":" \"strings\": {"},{"kind":"context","text":" \"search.title\": {"},{"kind":"context","text":" \"localizations\": {"},{"kind":"context","text":" \"en\": {"},{"kind":"context","text":" \"stringUnit\": {"},{"kind":"context","text":" \"state\": \"translated\","},{"kind":"delete","text":" \"value\": \"Search\""},{"kind":"add","text":" \"value\": \"Search this workspace\""},{"kind":"context","text":" }"},{"kind":"context","text":" },"},{"kind":"context","text":" \"fr\": {"},{"kind":"context","text":" \"stringUnit\": {"},{"kind":"context","text":" \"state\": \"translated\","},{"kind":"delete","text":" \"value\": \"Rechercher\""},{"kind":"add","text":" \"value\": \"Rechercher ici\""},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" },"},{"kind":"context","text":" \"search.empty\": {"},{"kind":"context","text":" \"localizations\": {"},{"kind":"context","text":" \"en\": {"},{"kind":"context","text":" \"stringUnit\": {"},{"kind":"context","text":" \"state\": \"translated\","},{"kind":"delete","text":" \"value\": \"No results\""},{"kind":"add","text":" \"value\": \"No matches\""},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" },"},{"kind":"context","text":" \"version\": \"1.0\""},{"kind":"context","text":"}"}],"0-2":[{"kind":"context","text":"{"},{"kind":"context","text":" \"sourceLanguage\": \"en\","},{"kind":"context","text":" \"strings\": {"},{"kind":"context","text":" \"search.title\": {"},{"kind":"context","text":" \"localizations\": {"},{"kind":"context","text":" \"en\": {"},{"kind":"context","text":" \"stringUnit\": {"},{"kind":"context","text":" \"state\": \"translated\","},{"kind":"delete","text":" \"value\": \"Search\""},{"kind":"add","text":" \"value\": \"Search this workspace\""},{"kind":"context","text":" }"},{"kind":"context","text":" },"},{"kind":"context","text":" \"fr\": {"},{"kind":"context","text":" \"stringUnit\": {"},{"kind":"context","text":" \"state\": \"translated\","},{"kind":"delete","text":" \"value\": \"Rechercher\""},{"kind":"add","text":" \"value\": \"Rechercher cet espace\""},{"kind":"add","text":" }"},{"kind":"add","text":" },"},{"kind":"add","text":" \"de\": {"},{"kind":"add","text":" \"stringUnit\": {"},{"kind":"add","text":" \"state\": \"translated\","},{"kind":"add","text":" \"value\": \"Arbeitsbereich durchsuchen\""},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" },"},{"kind":"context","text":" \"search.empty\": {"},{"kind":"context","text":" \"localizations\": {"},{"kind":"context","text":" \"en\": {"},{"kind":"context","text":" \"stringUnit\": {"},{"kind":"context","text":" \"state\": \"translated\","},{"kind":"delete","text":" \"value\": \"No results\""},{"kind":"add","text":" \"value\": \"No matches\""},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" },"},{"kind":"context","text":" \"version\": \"1.0\""},{"kind":"context","text":"}"}],"1-2":[{"kind":"context","text":"{"},{"kind":"context","text":" \"sourceLanguage\": \"en\","},{"kind":"context","text":" \"strings\": {"},{"kind":"context","text":" \"search.title\": {"},{"kind":"context","text":" \"localizations\": {"},{"kind":"context","text":" \"en\": {"},{"kind":"context","text":" \"stringUnit\": {"},{"kind":"context","text":" \"state\": \"translated\","},{"kind":"context","text":" \"value\": \"Search this workspace\""},{"kind":"context","text":" }"},{"kind":"context","text":" },"},{"kind":"context","text":" \"fr\": {"},{"kind":"context","text":" \"stringUnit\": {"},{"kind":"context","text":" \"state\": \"translated\","},{"kind":"delete","text":" \"value\": \"Rechercher ici\""},{"kind":"add","text":" \"value\": \"Rechercher cet espace\""},{"kind":"add","text":" }"},{"kind":"add","text":" },"},{"kind":"add","text":" \"de\": {"},{"kind":"add","text":" \"stringUnit\": {"},{"kind":"add","text":" \"state\": \"translated\","},{"kind":"add","text":" \"value\": \"Arbeitsbereich durchsuchen\""},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" },"},{"kind":"context","text":" \"search.empty\": {"},{"kind":"context","text":" \"localizations\": {"},{"kind":"context","text":" \"en\": {"},{"kind":"context","text":" \"stringUnit\": {"},{"kind":"context","text":" \"state\": \"translated\","},{"kind":"context","text":" \"value\": \"No matches\""},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" }"},{"kind":"context","text":" },"},{"kind":"context","text":" \"version\": \"1.0\""},{"kind":"context","text":"}"}]}},"SearchResults.svg":{"kind":"assets","since":1,"revisions":{"1":1,"2":2},"available":true,"lfs":true,"raw":{"0":"\n\nSearchKit\n\n\nEntire repository\n\nParser.swift\nRepository result\n\nStore.swift\n\n\n","1":"\n\nSearchKit\n\n\nCurrent workspace\n\nParser.swift\nWorkspace result\n\nStore.swift\n\n\n","2":"\n\nSearchKit\n\n\nCurrent workspace · 2 results\n\nParser.swift\nEmpty terms are filtered\n\nStore.swift\n\n\n"},"image":true,"meta":{"0":{"bytes":793,"oid":"91af0717949aa5af564ab4fa8d23fb9fd0ab1c1767fef3fcde260e9f786049cb","width":360,"height":240},"1":{"bytes":792,"oid":"a3e8891f5314184ea97858e8f35dca46be778894d8f2730a27a849fd49fa99dc","width":360,"height":240},"2":{"bytes":813,"oid":"142179bbec67e36d8e637812f3eedf46b58c2b8835f38125c2a2b825d8ee911c","width":360,"height":240}},"diffs":{"0-1":[{"kind":"context","text":""},{"kind":"context","text":""},{"kind":"context","text":"SearchKit"},{"kind":"context","text":""},{"kind":"context","text":""},{"kind":"delete","text":"Entire repository"},{"kind":"add","text":"Current workspace"},{"kind":"context","text":""},{"kind":"context","text":"Parser.swift"},{"kind":"delete","text":"Repository result"},{"kind":"add","text":"Workspace result"},{"kind":"context","text":""},{"kind":"context","text":"Store.swift"},{"kind":"context","text":""},{"kind":"context","text":""}],"0-2":[{"kind":"context","text":""},{"kind":"context","text":""},{"kind":"context","text":"SearchKit"},{"kind":"context","text":""},{"kind":"context","text":""},{"kind":"delete","text":"Entire repository"},{"kind":"add","text":"Current workspace · 2 results"},{"kind":"context","text":""},{"kind":"context","text":"Parser.swift"},{"kind":"delete","text":"Repository result"},{"kind":"add","text":"Empty terms are filtered"},{"kind":"context","text":""},{"kind":"context","text":"Store.swift"},{"kind":"context","text":""},{"kind":"context","text":""}],"1-2":[{"kind":"context","text":""},{"kind":"context","text":""},{"kind":"context","text":"SearchKit"},{"kind":"context","text":""},{"kind":"context","text":""},{"kind":"delete","text":"Current workspace"},{"kind":"add","text":"Current workspace · 2 results"},{"kind":"context","text":""},{"kind":"context","text":"Parser.swift"},{"kind":"delete","text":"Workspace result"},{"kind":"add","text":"Empty terms are filtered"},{"kind":"context","text":""},{"kind":"context","text":"Store.swift"},{"kind":"context","text":""},{"kind":"context","text":""}]}},"Design.psd":{"kind":"assets","since":1,"revisions":{"1":1,"2":1},"available":false,"lfs":true,"raw":{"0":"version https://git-lfs.github.com/spec/v1\noid sha256:1e1929833f1861e531d4611ff5b5d2b07b44d8b5dc25dfbf70cda472f3ef6a29\nsize 120000\n","1":"version https://git-lfs.github.com/spec/v1\noid sha256:9c41b21600d0529f53749575fbbdef3909eee1d5c2a060261d1db973a0f26ddc\nsize 142000\n","2":"version https://git-lfs.github.com/spec/v1\noid sha256:9c41b21600d0529f53749575fbbdef3909eee1d5c2a060261d1db973a0f26ddc\nsize 142000\n"},"meta":{"0":{"bytes":120000,"oid":"1e1929833f1861e531d4611ff5b5d2b07b44d8b5dc25dfbf70cda472f3ef6a29"},"1":{"bytes":142000,"oid":"9c41b21600d0529f53749575fbbdef3909eee1d5c2a060261d1db973a0f26ddc"},"2":{"bytes":142000,"oid":"9c41b21600d0529f53749575fbbdef3909eee1d5c2a060261d1db973a0f26ddc"}},"diffs":{"0-1":[{"kind":"context","text":"version https://git-lfs.github.com/spec/v1"},{"kind":"delete","text":"oid sha256:1e1929833f1861e531d4611ff5b5d2b07b44d8b5dc25dfbf70cda472f3ef6a29"},{"kind":"delete","text":"size 120000"},{"kind":"add","text":"oid sha256:9c41b21600d0529f53749575fbbdef3909eee1d5c2a060261d1db973a0f26ddc"},{"kind":"add","text":"size 142000"}],"0-2":[{"kind":"context","text":"version https://git-lfs.github.com/spec/v1"},{"kind":"delete","text":"oid sha256:1e1929833f1861e531d4611ff5b5d2b07b44d8b5dc25dfbf70cda472f3ef6a29"},{"kind":"delete","text":"size 120000"},{"kind":"add","text":"oid sha256:9c41b21600d0529f53749575fbbdef3909eee1d5c2a060261d1db973a0f26ddc"},{"kind":"add","text":"size 142000"}],"1-2":[{"kind":"context","text":"version https://git-lfs.github.com/spec/v1"},{"kind":"context","text":"oid sha256:9c41b21600d0529f53749575fbbdef3909eee1d5c2a060261d1db973a0f26ddc"},{"kind":"context","text":"size 142000"}]}},"EmptyResults.svg":{"kind":"assets","since":2,"revisions":{"1":null,"2":2},"available":true,"lfs":false,"raw":{"0":"","1":"","2":"\n\nSearchKit\n\n\nCurrent workspace · 2 results\nNo matching files\n\n\n"},"image":true,"meta":{"2":{"bytes":549,"oid":"55926284710d551886efcb95fc25eb61cab91fcddd4fc7f739030144e7d5700e","width":360,"height":240}},"diffs":{"0-1":[],"0-2":[{"kind":"add","text":""},{"kind":"add","text":""},{"kind":"add","text":"SearchKit"},{"kind":"add","text":""},{"kind":"add","text":""},{"kind":"add","text":"Current workspace · 2 results"},{"kind":"add","text":"No matching files"},{"kind":"add","text":""},{"kind":"add","text":""}],"1-2":[{"kind":"add","text":""},{"kind":"add","text":""},{"kind":"add","text":"SearchKit"},{"kind":"add","text":""},{"kind":"add","text":""},{"kind":"add","text":"Current workspace · 2 results"},{"kind":"add","text":"No matching files"},{"kind":"add","text":""},{"kind":"add","text":""}]}}}; +const files = Object.keys(fileCatalog); +const fileGroups = [{id:"code",label:"Code",icon:"pr"},{id:"documents",label:"Documents",icon:"file"},{id:"localization",label:"Localization",icon:"language"},{id:"assets",label:"Snapshots/assets",icon:"image"}]; +Object.assign(icons, { + windows: '', + tiles: '', + focus: '', + preview: '', + resize: '', + language: '', + image: '', + more: '', + close: '' +}); +const kindLabels = {review:'Review', source:'Source', search:'Research', preview:'Preview'}; +const kindIcons = {review:'pr', source:'file', search:'search', preview:'preview'}; +function makeView(workspace, kind, file) { + const ordinal = workspace.nextView++; + const state = kind === 'review' ? {file:file || 'Parser.swift', mode:'remaining', fileFilter:'remaining', format:'preview', collapsed:{code:false,documents:true,localization:true,assets:true}} + : kind === 'source' ? {file:file || 'Reference.swift'} + : kind === 'search' ? {query:'', searched:false} : {scene:'results'}; + return {id:`${workspace.number}-${ordinal}`, ordinal, kind, state, scroll:{top:0,left:0}, z:ordinal, + frame:{x:.025 + ((ordinal-1)%3)*.12, y:.025 + ((ordinal-1)%3)*.11, width:.64, height:.72}}; +} +function newWorkspace(number) { + const workspace = {number, open:true, version:1, reviewed:Object.fromEntries(files.map(file => [file,null])), skipped:Object.fromEntries(files.map(file=>[file,null])), draft:'', views:[], nextView:1, focused:null, layout:document.getElementById('stage').getBoundingClientRect().width<=680?'focus':'tiles', nextZ:5}; + const kinds = number === 42 ? ['review','source','preview'] : ['review','search']; + workspace.views = kinds.map(kind => makeView(workspace,kind)); + workspace.focused = workspace.views[0].id; + return workspace; +} +let workspaces = {42:newWorkspace(42),43:newWorkspace(43)}; +let activeWorkspace = 42; +let presentation = 'tabs'; +let rendering = false; +let dialogContext = null; +let toastTimer; +let outerScroll = 0; +const byNumber = number => workspaces[Number(number)]; +const openWorkspaces = () => Object.values(workspaces).filter(workspace=>workspace.open); +const focusedView = workspace => workspace?.views.find(view => view.id === workspace.focused); +const viewTitle = view => view.kind === 'review' || view.kind === 'source' ? view.state.file : view.kind === 'search' ? 'Repository search' : 'SearchKit preview'; +const viewName = view => `${kindLabels[view.kind]} ${view.ordinal}`; +const attributes = (workspace, view) => `data-workspace="${workspace.number}"${view ? ` data-view="${view.id}"` : ''}`; +const presentFiles = workspace => files.filter(file=>fileCatalog[file].since<=workspace.version); +const contentRevision = (file,version) => version===0?0:fileCatalog[file].revisions[version]; +function fileState(workspace,file) { + const baseline=workspace.reviewed[file]; + if(baseline===null)return 'unreviewed'; + return contentRevision(file,baseline)===contentRevision(file,workspace.version)?'reviewed':'changed'; +} +const isSkipped = (workspace,file) => workspace.skipped[file]!==null && contentRevision(file,workspace.skipped[file])===contentRevision(file,workspace.version); +const disposition = (workspace,file) => isSkipped(workspace,file)?'skipped':fileState(workspace,file)==='reviewed'?'reviewed':'remaining'; +function counts(workspace,members=presentFiles(workspace)) { + const result={remaining:0,reviewed:0,skipped:0};members.forEach(file=>result[disposition(workspace,file)]++);return result; +} +const remainingCount = workspace => counts(workspace).remaining; +const countSummary = value => `${value.remaining} remaining · ${value.reviewed} reviewed · ${value.skipped} skipped`; +function skipFiles(workspace,members) { + members.filter(file=>presentFiles(workspace).includes(file)&&disposition(workspace,file)==='remaining').forEach(file=>workspace.skipped[file]=workspace.version); +} +function undoSkips(workspace,members) { + members.filter(file=>isSkipped(workspace,file)).forEach(file=>workspace.skipped[file]=null); +} +function adaptFixture(workspace,prepared) { + return workspace.number===43?prepared.map(row=>({...row,text:row.text.replaceAll('suggestions','restoredTerms').replaceAll('searches','savedSearches')})):prepared; +} +function allDiffRows(workspace,file) { + if(fileCatalog[file].kind!=='code')return fileCatalog[file].diffs[`0-${workspace.version}`]; + return adaptFixture(workspace,file==='Parser.swift'?parserFull(workspace.version):file==='Store.swift'?storeFull(workspace.version):stableFull); +} +function sourceText(workspace,file) { + if(file==='Reference.swift')return referenceSource; + if(fileCatalog[file].kind!=='code')return fileCatalog[file].raw[workspace.version]; + return allDiffRows(workspace,file).filter(row=>row.kind!=='delete').map(row=>row.text).join('\n'); +} +function comparisonFrom(workspace,view) { + return view.state.mode==='remaining'&&fileState(workspace,view.state.file)==='changed'?workspace.reviewed[view.state.file]:0; +} +function comparisonRows(workspace,view) { + const file=view.state.file,from=comparisonFrom(workspace,view); + if(from===0)return allDiffRows(workspace,file); + if(fileCatalog[file].kind==='code')return adaptFixture(workspace,file==='Parser.swift'?parserNew:storeNew); + return fileCatalog[file].diffs[`${from}-${workspace.version}`]; +} +function diffTable(prepared, offset=1) { + let oldLine=offset, newLine=offset; + return `${prepared.map(row => ``).join('')}
Old lineNew lineChangeCode
${row.kind === 'add' ? '' : oldLine++}${row.kind === 'delete' ? '' : newLine++}${row.kind === 'add' ? '+' : row.kind === 'delete' ? '−' : ''}${escapeHTML(row.text) || ' '}
`; +} +function comparisonLabel(workspace,view) { + const state=fileState(workspace,view.state.file); + return view.state.mode==='remaining' && state==='changed' ? `New edits since v${workspace.reviewed[view.state.file]}` : view.state.mode==='remaining' && state==='reviewed' ? 'No remaining changes' : 'Full PR diff'; +} +function versionLabel(version) {return version===0?'PR base':`v${version}`;} +function renderDocument(workspace,view,from) { + const entry=fileCatalog[view.state.file],before=entry.document[from],after=entry.document[workspace.version]; + const linkChanged=before.target!==after.target; + return `${linkChanged?'

Link target changed. Exact targets are shown below; Source preserves Markdown syntax.

':''}
${[[from,before],[workspace.version,after]].map(([version,doc])=>`

${version===from?'Before':'After'} · ${versionLabel(version)}

${escapeHTML(doc.heading)}

${escapeHTML(doc.text)}

Link target ${escapeHTML(doc.target)}
`).join('')}
`; +} +function renderLocalization(workspace,view,from) { + const entry=fileCatalog[view.state.file],before=entry.entries[from],after=entry.entries[workspace.version],changes=[]; + [...new Set([...Object.keys(before),...Object.keys(after)])].forEach(key=>{[...new Set([...Object.keys(before[key]||{}),...Object.keys(after[key]||{})])].forEach(locale=>{const old=before[key]?.[locale],next=after[key]?.[locale];if(old!==next)changes.push({key,locale,old,next});});}); + return `

${changes.length} changed locale values · ${new Set(changes.map(change=>change.key)).size} keys · ${versionLabel(from)} → v${workspace.version}

${changes.map(change=>`
${escapeHTML(change.key)}${change.locale}
Before${change.old===undefined?'Not present':escapeHTML(change.old)}
After${change.next===undefined?'Removed':escapeHTML(change.next)}
`).join('')}
`; +} +function imageMetadata(entry,version) { + const meta=entry.meta[version];if(!meta)return ''; + return ``; +} +function renderAsset(workspace,view,from) { + const entry=fileCatalog[view.state.file]; + return `${!entry.available?'
Preview unavailable

Binary content is not included in this fixture. Only prepared LFS pointer metadata is available; the file cannot be marked reviewed.

':''}
${[from,workspace.version].map((version,index)=>{const exists=!(entry.since===2&&version<2);return `

${index===0?'Before':'After'} · ${versionLabel(version)}

${!exists?'
File not present
':entry.available?`${index===0?'Before':'After'} synthetic ${escapeHTML(view.state.file)} at ${versionLabel(version)}`:'
Image bytes unavailable
'}${exists?imageMetadata(entry,version):''}
`;}).join('')}
`; +} +function renderReviewContent(workspace,view) { + const file=view.state.file,entry=fileCatalog[file],from=comparisonFrom(workspace,view),state=fileState(workspace,file),skipped=isSkipped(workspace,file),control=attributes(workspace,view); + if(view.state.mode==='remaining'&&state==='reviewed'&&!skipped)return `
${icon('check')}

${file} is caught up

Last marked reviewed at v${workspace.reviewed[file]}.

`; + const banner=skipped?`

Skipped for this PR at v${workspace.skipped[file]}. Review history is unchanged.

`:''; + if(entry.kind==='code')return `${banner}${diffTable(comparisonRows(workspace,view),from?(file==='Parser.swift'?13:10):1)}
End of ${from?'new edits':'file'} · sample comparison
`; + const group=fileGroups.find(group=>group.id===entry.kind); + const tools=`
${icon(group.icon)} ${group.label}${entry.lfs?'LFS':''}
`; + const body=view.state.format==='source'?`${!entry.available?'

LFS pointer comparison only. Binary content is unavailable.

':''}${diffTable(comparisonRows(workspace,view))}`:entry.kind==='documents'?renderDocument(workspace,view,from):entry.kind==='localization'?renderLocalization(workspace,view,from):renderAsset(workspace,view,from); + return `${banner}${tools}
${body}
`; +} +function renderReview(workspace,view) { + const file=view.state.file,state=fileState(workspace,file),control=attributes(workspace,view),skipped=isSkipped(workspace,file),available=fileCatalog[file].available; + const action=skipped?``:state==='reviewed'?`${icon('check')} Reviewed`:available?``:'Content unavailable'; + return `
${action}
${renderReviewContent(workspace,view)}
`; +} +function fileStatusLabel(workspace,file) { + const value=disposition(workspace,file);return value==='skipped'?`Skipped v${workspace.skipped[file]}`:value==='reviewed'?`Reviewed v${workspace.reviewed[file]}`:fileState(workspace,file)==='changed'?`New edits since reviewed v${workspace.reviewed[file]}`:'Not reviewed'; +} +function renderFileGroups(workspace,view) { + const total=counts(workspace),control=attributes(workspace,view); + return `

${countSummary(total)}

${fileGroups.map(group=>{const members=presentFiles(workspace).filter(file=>fileCatalog[file].kind===group.id),value=counts(workspace,members),collapsed=view.state.collapsed[group.id],visible=members.filter(file=>view.state.fileFilter==='all'||disposition(workspace,file)==='remaining');return `
${value.remaining?``:''}${value.skipped?``:''}
${visible.length?visible.map(file=>``).join(''):`

No remaining files.${value.skipped?' Skipped files are available under All.':''}

`}
`;}).join('')}
${total.remaining===0?`

No remaining work · ${total.reviewed} reviewed · ${total.skipped} skipped

`:''}`; +} +function renderSource(workspace,view) { + const control=attributes(workspace,view),pointerOnly=fileCatalog[view.state.file]?.available===false; + return `
${view.state.file!=='Reference.swift'?``:''}
${pointerOnly?'

LFS pointer only · binary content unavailable.

':''}${diffTable(sourceText(workspace,view.state.file).split('\n').map(text=>({kind:'context',text})))}
${pointerOnly?'Prepared LFS pointer':'Sample source'} · v${workspace.version}
`; +} +function searchResults(workspace,view) { + if(!view.state.searched)return `

Try

`; + const query=view.state.query.trim().toLowerCase();if(!query)return '

Enter a term to search the sample source.

'; + const matches=['Reference.swift',...presentFiles(workspace)].map(file=>({file,text:sourceText(workspace,file)})).filter(document=>`${document.file} ${document.text}`.toLowerCase().includes(query)); + return `

${matches.length} ${matches.length===1?'file':'files'} found · ${1+presentFiles(workspace).length} sample source/pointer files searched

${matches.map(document=>``).join('')}`; +} +function renderSearch(workspace,view) { + return `
${searchResults(workspace,view)}
`; +} +function renderPreview(workspace,view) { + const scene=view.state.scene; + return `
Simulated
SearchKit
${scene==='results'?`
${icon('file')}Reference.swiftstruct WorkspaceID: Hashable
${icon('file')}Store.swiftSearches belong to a workspace
`:`
${scene==='empty'?'No matches yet':'Searching the repository…'}${scene==='empty'?'Try a different term or file name.':'A prepared loading-state preview.'}
`}
`; +} +function renderView(workspace,view) { + const active=workspace.focused===view.id, control=attributes(workspace,view), hasFiles=['review','source'].includes(view.kind); + const frame=workspace.layout==='float'?`style="left:${view.frame.x*100}%;top:${view.frame.y*100}%;width:${view.frame.width*100}%;height:${view.frame.height*100}%;z-index:${view.z}"`:''; + return `
${view.kind==='source'&&view.state.file!=='Reference.swift'?``:''}
${view.kind==='review'?renderReview(workspace,view):view.kind==='source'?renderSource(workspace,view):view.kind==='search'?renderSearch(workspace,view):renderPreview(workspace,view)}
`; +} +function workspaceActions(workspace) { + const control=attributes(workspace); + return `
`; +} +const shortWorkspace = workspace => workspace.number===42?'Search':'Restore'; +const workspaceName = workspace => `${shortWorkspace(workspace)} #${workspace.number}`; +function closeWorkspaceControl(workspace) { + return ``; +} +function workspacePresentationControls() { + return `
${[['tabs','sidebar','Tabs'],['windows','windows','Windows']].map(([value,glyph,label])=>``).join('')}
`; +} +function workspaceNavigation() { + const opened=openWorkspaces(),active=byNumber(activeWorkspace); + const picker=``; + if(!opened.length)return picker; + return picker+(presentation==='tabs' ? `${active?workspaceActions(active):''}` : ``); +} +function renderWorkspace(workspace) { + const control=attributes(workspace), count=workspace.views.length, active=focusedView(workspace); + const countClass=count===1?'one':count===2?'two':count===3?'three':'many'; + return `
${workspaceActions(workspace)}${closeWorkspaceControl(workspace)}
${active?`
`:''}
${count?workspace.views.map(view=>renderView(workspace,view)).join(''):`

No open views

`}
`; +} +function captureScroll() { + document.querySelectorAll('[data-scroll]').forEach(node => { + const view=Object.values(workspaces).flatMap(workspace => workspace.views).find(item => item.id === node.dataset.scroll); + if (view && node.getClientRects().length) view.scroll={top:node.scrollTop,left:node.scrollLeft}; + }); + const outer=document.querySelector('.outer-space'); + if (outer && presentation === 'windows') outerScroll=outer.scrollLeft; +} +function rememberFocus() { + const active=document.activeElement; + if (!document.getElementById('app').contains(active)) return null; + return active.id ? {id:active.id} : active.dataset.action || active.dataset.control ? {data:{...active.dataset}} : null; +} +function restoreFocus(saved) { + if (!saved || document.getElementById('modal').open) return; + const target=saved.id ? document.getElementById(saved.id) : [...document.querySelectorAll('button,select,input')].find(node => node.getClientRects().length && Object.entries(saved.data).every(([key,value]) => node.dataset[key] === value)); + (target || document.querySelector(`.child[data-view="${byNumber(activeWorkspace)?.focused}"]`) || [...document.querySelectorAll(`button[data-workspace="${activeWorkspace}"][data-action="new-view"]`)].find(node=>node.getClientRects().length) || document.querySelector('.workspace-picker'))?.focus({preventScroll:true}); +} +function render() { + finishDrag(); + const saved=rememberFocus();rendering=true; + const app=document.getElementById('app');app.dataset.presentation=presentation; + app.innerHTML=`
${workspaceNavigation()}
${openWorkspaces().length?openWorkspaces().map(renderWorkspace).join(''):`

No open workspaces

Your sample PR workspaces are retained.

`}
`; + document.querySelectorAll('[data-scroll]').forEach(node=>{const view=Object.values(workspaces).flatMap(workspace=>workspace.views).find(item=>item.id===node.dataset.scroll);node.scrollTop=view.scroll.top;node.scrollLeft=view.scroll.left;}); + document.querySelectorAll('.prototype-panel [data-action="push"]').forEach(button=>{const applied=byNumber(button.dataset.workspace).version===2;button.disabled=applied;button.textContent=applied?'Push applied':'Simulate push';button.setAttribute('aria-label',`${button.textContent} for PR ${button.dataset.workspace}`);}); + if(presentation==='windows')document.querySelector('.outer-space').scrollLeft=outerScroll; + observeFloatingCanvases();restoreFocus(saved);document.querySelector(`.child[data-view="${byNumber(activeWorkspace)?.focused}"]`)?.scrollIntoView({block:'nearest',inline:'nearest'});rendering=false; +} +function focusView(workspace,view) { + if(!workspace?.open||!workspace.views.includes(view))return; + const resumed=activeWorkspace !== workspace.number || workspace.focused !== view.id; + activeWorkspace=workspace.number;workspace.focused=view.id;view.z=workspace.nextZ++; + if (resumed && view.kind === 'review') view.scroll={top:0,left:0}; +} +function activateWorkspace(workspace) { + if(!workspace?.open)return; + const view=focusedView(workspace); + if (view) focusView(workspace,view); else activeWorkspace=workspace.number; +} +function closeWorkspace(workspace) { + if(!workspace?.open)return; + const opened=openWorkspaces(),index=opened.indexOf(workspace),neighbor=opened[index+1]||opened[index-1]; + workspace.open=false; + if(activeWorkspace===workspace.number){activeWorkspace=null;if(neighbor)activateWorkspace(neighbor);} +} +function reopenWorkspace(workspace) { + if(!workspace)return; + workspace.open=true;activateWorkspace(workspace); +} +function paintFocus() { + const workspacePicker=document.querySelector('[data-control="workspace"]');if(workspacePicker)workspacePicker.value=String(activeWorkspace); + document.querySelectorAll('.workspace-host').forEach(host=>{const owner=byNumber(host.dataset.workspace), active=focusedView(owner), picker=host.querySelector('.view-picker');if(active&&picker){picker.innerHTML=`${icon(kindIcons[active.kind])}${escapeHTML(viewTitle(active))}${icon('chevron')}`;picker.setAttribute('aria-label',`Views in PR ${owner.number}. Current ${viewName(active)}: ${viewTitle(active)}`);const close=picker.nextElementSibling;close.dataset.view=active.id;close.setAttribute('aria-label',`Close ${viewName(active)}`);}}); + document.querySelectorAll('.workspace-host,.workspace-tab,.workspace-tab-shell').forEach(node => { + const selected=Number(node.dataset.workspace) === activeWorkspace; + node.classList.toggle(node.classList.contains('workspace-tab') ? 'active' : 'selected',selected); + if (node.classList.contains('workspace-tab')) { if(selected)node.setAttribute('aria-current','true');else node.removeAttribute('aria-current'); } + }); + document.querySelectorAll('.child,.child-tab').forEach(node => { + const workspace=byNumber(node.dataset.workspace), selected=workspace.focused === node.dataset.view; + node.classList.toggle(node.classList.contains('child') ? 'focused' : 'active',selected); + if(node.classList.contains('child')) { node.dataset.focused=String(selected); const view=workspace.views.find(item=>item.id===node.dataset.view); if(workspace.layout==='float')node.style.zIndex=view.z; } + else {if(selected)node.setAttribute('aria-current','true');else node.removeAttribute('aria-current');} + }); +} +function scrollWorkspaceIntoView(workspace) { + if(workspace?.open&&presentation === 'windows') document.querySelector(`.workspace-host[data-workspace="${workspace.number}"]`)?.scrollIntoView({block:'nearest',inline:'nearest'}); +} +function addView(workspace,kind,file) { + if(!workspace?.open)return null; + const view=makeView(workspace,kind,file);workspace.views.push(view);focusView(workspace,view);return view; +} +function toast(message) { + clearTimeout(toastTimer);document.getElementById('toast').textContent=message; + toastTimer=setTimeout(()=>{document.getElementById('toast').textContent='';},3500); +} +function showModal(kind,workspace,opener) { + if(kind!=='workspaces'&&!workspace?.open)return; + const previous=dialogContext; + dialogContext={kind,number:workspace?.number??null,view:opener.dataset.view,opener:previous?.opener||{...opener.dataset}}; + const modal=document.getElementById('modal'), view=workspace?.views.find(item=>item.id===dialogContext.view), control=workspace?attributes(workspace,view):''; + let title,body; + if(kind==='workspaces') { + title='Workspaces'; + body=`

PR workspaces

${workspacePresentationControls()}`; + } else if(kind==='new-view') { + title=`Add a view · PR #${workspace.number}`; + body=`
${[['review','Read another file or comparison.'],['source','Browse sample code.'],['search','Search with a separate query.'],['preview','Compare simulated app states.']].map(([type,description])=>``).join('')}
`; + } else if(kind==='draft') { + title=`Review draft · PR #${workspace.number}`; + body=`

Private session note. Nothing is sent to GitHub.

`; + } else if(kind==='workspace-options') { + title=`Workspace · PR #${workspace.number}`; + body=`
${fixtures[workspace.number].title}

PR workspaces

${workspacePresentationControls()}

Views in ${workspaceName(workspace)}

${[['tiles','tiles','Tile'],['float','windows','Float'],['focus','focus','One view']].map(([value,glyph,label])=>``).join('')}
`; + } else if(kind==='views') { + title=`Views · PR #${workspace.number}`; + body=``; + } else if(kind==='files') { + title=`${view.kind==='review'?'Review':'Source'} files`; + body=view.kind==='review'?renderFileGroups(workspace,view):``; + } else if(kind==='comparison-menu') { + title='Comparison';const file=view.state.file,baseline=workspace.reviewed[file],skipped=isSkipped(workspace,file); + body=`

${file} · ${baseline===null?'not marked reviewed':`last marked v${baseline}`} · current v${workspace.version}

${skipped?`

Skipped current changes at v${workspace.skipped[file]}.

`:''}`; + + } + modal.innerHTML=`
${body}`; + if(!modal.open)modal.showModal();else {const target=[...modal.querySelectorAll('button')].find(node=>node.getClientRects().length&&Object.entries(opener.dataset).every(([key,value])=>node.dataset[key]===value));(target||modal.querySelector('[data-action="close-modal"]')).focus();} +} +function contextFor(node) { + const workspace=byNumber(node.dataset.workspace || node.closest('.workspace-host')?.dataset.workspace || activeWorkspace); + const view=workspace?.views.find(item=>item.id===(node.dataset.view || node.closest('.child')?.dataset.view)); + return {workspace,view}; +} +document.addEventListener('click',event=>{ + const button=event.target.closest('button[data-action]');if(!button || button.disabled)return; + captureScroll();const {workspace,view}=contextFor(button); + if(!workspace?.open&&!['workspaces','reopen-workspace','close-workspace','close-modal','presentation','push','reset'].includes(button.dataset.action))return; + if(view && button.dataset.action !== 'close-view')focusView(workspace,view); + switch(button.dataset.action) { + case 'workspaces': showModal('workspaces',null,button);break; + case 'reopen-workspace': reopenWorkspace(workspace);dismissModal('child');scrollWorkspaceIntoView(workspace);break; + case 'close-workspace': closeWorkspace(workspace);render();scrollWorkspaceIntoView(byNumber(activeWorkspace));break; + case 'workspace': activateWorkspace(workspace);if(dialogContext)dismissModal('child');else render();scrollWorkspaceIntoView(workspace);document.querySelector(`.child[data-view="${workspace.focused}"]`)?.focus({preventScroll:true});break; + case 'presentation': presentation=button.dataset.presentation;dismissModal('opener');scrollWorkspaceIntoView(byNumber(activeWorkspace));break; + case 'focus-view': if(dialogContext)dismissModal('child');else render();break; + case 'layout': workspace.layout=button.dataset.layout;activateWorkspace(workspace);dismissModal('opener');break; + case 'focus-layout': workspace.layout=workspace.layout==='focus'?'tiles':'focus';render();break; + case 'new-view': activateWorkspace(workspace);paintFocus();showModal('new-view',workspace,button);break; + case 'workspace-options': case 'views': case 'files': case 'comparison-menu': showModal(button.dataset.action,workspace,button);break; + case 'create-view': {const owner=byNumber(dialogContext.number);addView(owner,button.dataset.kind);dismissModal('child');break;} + case 'close-view': workspace.views=workspace.views.filter(item=>item.id!==view.id);if(workspace.focused===view.id){workspace.focused=null;const next=workspace.views.at(-1);if(next){if(activeWorkspace===workspace.number)focusView(workspace,next);else workspace.focused=next.id;}}render();if(dialogContext?.kind==='views')showModal('views',workspace,button);break; + case 'file': case 'source-file': view.state.file=button.dataset.file;view.scroll={top:0,left:0};dismissModal('child');break; + case 'comparison': view.state.mode=button.dataset.mode;view.state.fileFilter=button.dataset.mode==='full'?'all':'remaining';view.scroll={top:0,left:0};if(dialogContext)dismissModal('child');else render();break; + case 'review': if(!fileCatalog[view.state.file].available)break;workspace.reviewed[view.state.file]=workspace.version;workspace.skipped[view.state.file]=null;if(dialogContext)dismissModal('child');else render();toast(`${view.state.file} reviewed at v${workspace.version} · shared in PR #${workspace.number}`);break; + case 'push': if(!workspace)break;closePrototypeControls();if(workspace.open)activateWorkspace(workspace);workspace.version=2;render();toast(`PR #${workspace.number} · new edits and one new asset`);break; + case 'format': view.state.format=button.dataset.format;view.scroll={top:0,left:0};render();break; + case 'file-filter': view.state.fileFilter=button.dataset.filter;showModal('files',workspace,button);break; + case 'toggle-group': view.state.collapsed[button.dataset.group]=!view.state.collapsed[button.dataset.group];showModal('files',workspace,button);break; + case 'skip': skipFiles(workspace,[view.state.file]);dismissModal('child');break; + case 'undo-skip': undoSkips(workspace,[view.state.file]);if(dialogContext)dismissModal('child');else render();break; + case 'skip-group': case 'undo-group': {const members=presentFiles(workspace).filter(file=>fileCatalog[file].kind===button.dataset.group);if(button.dataset.action==='skip-group')skipFiles(workspace,members);else undoSkips(workspace,members);render();showModal('files',workspace,button);break;} + case 'open-source': addView(workspace,'source',button.dataset.file);render();break; + case 'review-source': addView(workspace,'review',view.state.file);render();break; + case 'example-search': view.state.query='WorkspaceID';view.state.searched=true;render();break; + case 'draft': activateWorkspace(workspace);paintFocus();showModal('draft',workspace,button);break; + case 'close-modal': dismissModal('opener');break; + case 'reset': closePrototypeControls();workspaces={42:newWorkspace(42),43:newWorkspace(43)};activeWorkspace=42;presentation='tabs';outerScroll=0;render();toast('Sample workspaces reset');break; + } +}); +document.addEventListener('input',event=>{ + if(event.target.id==='draft' && dialogContext){const owner=byNumber(dialogContext.number);if(owner?.open)owner.draft=event.target.value;return;} + if(event.target.dataset.control==='query'){const {workspace,view}=contextFor(event.target);if(workspace?.open&&view)view.state.query=event.target.value;} +}); +document.addEventListener('change',event=>{ + if(event.target.id==='viewport'){captureScroll();document.getElementById('stage').dataset.size=event.target.value;return;} + const control=event.target.dataset.control; + if(control==='workspace'){captureScroll();activateWorkspace(byNumber(event.target.value));render();scrollWorkspaceIntoView(byNumber(activeWorkspace));return;} + if(!['source-file','preview-scene'].includes(control))return; + captureScroll();const {workspace,view}=contextFor(event.target);if(!workspace?.open||!view)return;focusView(workspace,view); + if(control==='source-file'){view.state.file=event.target.value;view.scroll={top:0,left:0};} + if(control==='preview-scene')view.state.scene=event.target.value; + render(); +}); +document.addEventListener('submit',event=>{ + if(!event.target.matches('.search-form'))return;event.preventDefault(); + const {workspace,view}=contextFor(event.target);if(!workspace?.open||!view)return;view.state.searched=true; + document.querySelector(`[data-results="${view.id}"]`).innerHTML=searchResults(workspace,view); +}); +// Native close events are queued. Finish owned dismissal synchronously so a +// later close event cannot replace a newly focused form or steal its input. +function dismissModal(destination) { + const previous=dialogContext;dialogContext=null; + document.getElementById('modal').close();render(); + const opener=previous && [...document.querySelectorAll('button[data-action]')].find(node=>node.getClientRects().length && Object.entries(previous.opener).every(([key,value])=>node.dataset[key]===value)); + const child=document.querySelector(`.child[data-view="${byNumber(activeWorkspace)?.focused}"]`); + const newView=[...document.querySelectorAll(`button[data-workspace="${activeWorkspace}"][data-action="new-view"]`)].find(node=>node.getClientRects().length); + ((destination==='child' ? child || newView : opener || child || newView) || document.querySelector('.workspace-picker'))?.focus({preventScroll:true}); +} +document.getElementById('modal').addEventListener('cancel',event=>{event.preventDefault();dismissModal('opener');}); +document.getElementById('modal').addEventListener('close',()=>{if(dialogContext&&!document.getElementById('modal').open)dismissModal('opener');}); + +function focusFromChild(node) { + const child=node.closest('.child');if(node.closest('[data-action="close-view"]') || !child || rendering || document.getElementById('modal').open)return; + const {workspace,view}=contextFor(child);if(!workspace?.open||!view)return; + if(workspace.focused===view.id && activeWorkspace===workspace.number)return; + captureScroll();focusView(workspace,view);paintFocus(); + if(view.kind==='review'){const scroll=child.querySelector('[data-scroll]');if(scroll){scroll.scrollTop=0;scroll.scrollLeft=0;}} +} +document.addEventListener('focusin',event=>focusFromChild(event.target)); +document.addEventListener('pointerdown',event=>focusFromChild(event.target)); +// Saved normalized placement is authored only by explicit move/resize. Fitting a +// smaller host changes displayed bounds without overwriting the wider arrangement. +function frameBounds(workspace) { + if(!workspace?.open)return null; + const canvas=document.querySelector(`.workspace-host[data-workspace="${workspace.number}"] .child-canvas`); + if(workspace.layout!=='float'||!canvas?.getClientRects().length||!canvas.clientWidth||!canvas.clientHeight)return null; + const rect=canvas.getBoundingClientRect(); + return {x:rect.x+canvas.clientLeft,y:rect.y+canvas.clientTop,width:canvas.clientWidth,height:canvas.clientHeight}; +} +function fittedFrame(frame,rect) { + const width=Math.max(Math.min(300/rect.width,1),Math.min(1,frame.width)); + const height=Math.max(Math.min(210/rect.height,1),Math.min(1,frame.height)); + return {x:Math.max(0,Math.min(1-width,frame.x)),y:Math.max(0,Math.min(1-height,frame.y)),width,height}; +} +function paintFrame(view,frame) { + const child=document.querySelector(`.child[data-view="${view.id}"]`); + Object.assign(child.style,{left:frame.x*100+'%',top:frame.y*100+'%',width:frame.width*100+'%',height:frame.height*100+'%'}); +} +function fitFloatingWorkspace(workspace) { + const rect=frameBounds(workspace);if(rect)workspace.views.forEach(view=>paintFrame(view,fittedFrame(view.frame,rect))); +} +const frameObserver=new ResizeObserver(entries=>entries.forEach(entry=>{if(entry.target.isConnected)fitFloatingWorkspace(byNumber(entry.target.dataset.workspace));})); +function observeFloatingCanvases() { + frameObserver.disconnect(); + openWorkspaces().filter(workspace=>workspace.layout==='float').forEach(workspace=>{fitFloatingWorkspace(workspace);const canvas=document.querySelector(`.child-canvas[data-workspace="${workspace.number}"]`);frameObserver.observe(canvas);}); +} +function applyFrame(workspace,view,frame) { + const rect=frameBounds(workspace);if(!rect)return; + const next=fittedFrame(frame,rect),current=fittedFrame(view.frame,rect); + if(Object.keys(next).every(key=>next[key]===current[key]))return; + view.frame=next;paintFrame(view,next); +} +// CSS pixels: allow click/tap jitter before a title-bar gesture becomes a move. +const moveThreshold=5; +let drag=null,dragClickPointer=null; +document.addEventListener('click',event=>{ + if(event.detail===0||event.pointerId!==dragClickPointer)return; + dragClickPointer=null;event.preventDefault();event.stopImmediatePropagation(); +},true); +document.addEventListener('pointerdown',event=>{ + if(!event.isPrimary||event.button!==0||drag)return; + dragClickPointer=null; + const resize=event.target.closest('[data-resize]'),titlebar=event.target.closest('.child-titlebar'); + if(!resize&&(!titlebar||event.target.closest('.child-controls')))return; + const handle=resize||event.target.closest('.child-title,[data-drag]')||titlebar; + const {workspace,view}=contextFor(handle),rect=frameBounds(workspace);if(!rect)return; + // Capturing the original button keeps its ordinary stationary click native. + // Header gaps capture the header; independent action buttons never enter here. + handle.setPointerCapture(event.pointerId); + if(resize){event.preventDefault();handle.focus({preventScroll:true});} + drag={workspace,view,handle,titlebar,rect,resize:!!resize,pointerId:event.pointerId, + started:false,x:event.clientX,y:event.clientY,frame:fittedFrame(view.frame,rect)}; +}); +document.addEventListener('pointermove',event=>{ + if(!drag||event.pointerId!==drag.pointerId)return; + const dx=event.clientX-drag.x,dy=event.clientY-drag.y; + if(!drag.started){ + if(drag.resize?dx===0&&dy===0:Math.hypot(dx,dy)finishDrag()); +document.addEventListener('keydown',event=>{ + const handle=event.target.closest('[data-drag],[data-resize]');if(!handle || !['ArrowLeft','ArrowRight','ArrowUp','ArrowDown'].includes(event.key))return; + const {workspace,view}=contextFor(handle),rect=frameBounds(workspace);if(!rect)return; + event.preventDefault();const dx=event.key==='ArrowLeft'?-12/rect.width:event.key==='ArrowRight'?12/rect.width:0,dy=event.key==='ArrowUp'?-12/rect.height:event.key==='ArrowDown'?12/rect.height:0; + const resize=event.shiftKey||handle.hasAttribute('data-resize'),frame=fittedFrame(view.frame,rect);applyFrame(workspace,view,{...frame,...(resize?{width:frame.width+dx,height:frame.height+dy}:{x:frame.x+dx,y:frame.y+dy})}); +}); +function closePrototypeControls() { + const details=document.getElementById('prototype-controls');if(details.open){details.open=false;details.querySelector('summary').focus({preventScroll:true});} +} +document.addEventListener('keydown',event=>{if(event.key==='Escape'&&document.getElementById('prototype-controls').open&&!document.getElementById('modal').open){event.preventDefault();closePrototypeControls();}}); +document.addEventListener('click',event=>{const details=document.getElementById('prototype-controls');if(details.open&&!details.contains(event.target))details.open=false;}); +render(); diff --git a/Plans/2026-11-14-mobius/Prototype/src/pages/index.astro b/Plans/2026-11-14-mobius/Prototype/src/pages/index.astro new file mode 100644 index 000000000..29f980111 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/src/pages/index.astro @@ -0,0 +1,21 @@ +--- +import '../styles.css'; +--- + + + + + + +Mobius — a workspace for every review + + + +
mobius
Sample dataControls

Prototype controls

PR #42
PR #43

Offline sample session. Previews are simulated; no code is running.

+
+ +

In floating layout, drag the view title bar or icon to move it. Click a filename without dragging to choose a file. With the move icon focused, arrow keys move the view; Shift and arrow keys resize it. The corner handle also supports arrow-key resizing.

+
+ + + diff --git a/Plans/2026-11-14-mobius/Prototype/src/styles.css b/Plans/2026-11-14-mobius/Prototype/src/styles.css new file mode 100644 index 000000000..3809c635e --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/src/styles.css @@ -0,0 +1,231 @@ + + +:root { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; color: #272b35; background: #eaeae7; --ink: #272b35; --muted: #626774; --line: #dddfe5; --accent: #5942b6; --tint: #efebfa; } +* { box-sizing: border-box; } +body { margin: 0; } +button, input, select, textarea { font: inherit; color: inherit; } +button { cursor: pointer; background: none; border: 0; touch-action: manipulation; } +button:disabled { opacity: .55; cursor: default; } +button:focus-visible, select:focus-visible, input:focus-visible, textarea:focus-visible, summary:focus-visible, [tabindex]:focus-visible { outline: 3px solid #8c76dc; outline-offset: 2px; } +button svg, button span { pointer-events: none; } +svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; vertical-align: middle; flex-shrink: 0; } +h1, h2, h3, p { margin: 0; } +.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; } +.lab { position: relative; z-index: 20; max-width: 1600px; margin: auto; padding: 0 22px; height: 48px; display: flex; align-items: center; justify-content: space-between; gap: 12px; color: var(--muted); font-size: 12px; } +.brand { display: flex; align-items: center; gap: 7px; color: var(--ink); font-size: 17px; font-weight: 650; letter-spacing: -.5px; } +.brand-mark { color: var(--accent); font-size: 30px; line-height: 1; font-weight: 450; } +.prototype-controls { position: relative; z-index: 30; } +.prototype-controls summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; gap: 10px; list-style: none; } +.prototype-controls summary::-webkit-details-marker { display: none; } +.prototype-controls summary::after { content: '⌄'; font-size: 15px; } +.sample { font-size: 11px; color: #626774; white-space: nowrap; } +.prototype-panel { position: absolute; right: 0; top: 44px; width: min(330px,calc(100vw - 24px)); border: 1px solid #d2d0dc; border-radius: 10px; background: #fff; box-shadow: 0 14px 40px #25243c2b; padding: 16px; } +.prototype-panel h2 { color: var(--ink); font-size: 14px; margin-bottom: 14px; } +.prototype-panel p { line-height: 1.6; margin-top: 12px; } +.prototype-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin: 9px 0; } +.prototype-row select { min-height: 36px; background: #fff; border: 1px solid #ccc7d7; border-radius: 5px; padding: 6px; } +.stage { position: relative; z-index: 0; max-width: 1556px; width: calc(100% - 44px); margin: auto; container-type: inline-size; } +.stage[data-size="phone"] { max-width: 390px; } +.stage[data-size="tablet"] { max-width: 834px; } +.stage[data-size="desktop"] { max-width: 1440px; } +.app { height: calc(100dvh - 66px); min-height: 460px; max-height: 1300px; display: flex; flex-direction: column; overflow: hidden; background: #f5f5f8; border: 1px solid #d2d4dc; border-radius: 10px; box-shadow: 0 8px 30px #25273c12; } +.app-bar { display: flex; align-items: center; gap: 8px; min-height: 50px; padding: 0 8px; background: #f8f8fb; border-bottom: 1px solid #d2d4dc; } +.workspace-tabs { display: flex; align-items: stretch; gap: 4px; flex: 1; min-width: 0; align-self: stretch; overflow-x: auto; } +.workspace-tab-shell { display:flex; align-items:center; flex:0 0 auto; border-bottom:2px solid transparent; } +.workspace-tab-shell.selected { border-bottom-color:var(--accent); background:#efedf6; } +.workspace-tab-shell .workspace-tab { border-bottom:0; background:transparent; } +.workspace-picker { flex-shrink:0; } +.workspace-picker span { font-size:12px; } +.workspace-empty { flex:1; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:14px; padding:24px; text-align:center; } +.workspace-empty p { color:var(--muted); font-size:13px; line-height:1.5; } +.workspace-tab { display: flex; align-items: center; gap: 7px; padding: 0 13px; min-height: 48px; min-width: 0; color: #626774; font-size: 13px; border-bottom: 2px solid transparent; white-space: nowrap; } +.workspace-tab.active { color: var(--accent); border-bottom-color: var(--accent); background: #efedf6; } +.workspace-tab .pr-number { color: #626774; font-size: 11px; } +.workspace-window-navigation { display:flex; align-items:center; gap:12px; flex:1; min-width:0; padding:0 5px; } +.workspace-window-navigation span { color:var(--muted); font-size:12px; white-space:nowrap; } +.workspace-window-navigation select { min-width:0; max-width:220px; min-height:38px; flex:1; padding:6px 9px; border:1px solid #d5d7df; border-radius:6px; background:#fff; font-size:13px; } +.workspace-actions, .child-controls { display: flex; align-items: center; gap: 2px; flex-shrink: 0; } +.icon-button { width: 36px; height: 36px; display: inline-grid; place-items: center; border-radius: 6px; color: #626774; flex-shrink: 0; position: relative; } +.icon-button:hover, .child-title:hover, .view-picker:hover { background: #eeebf5; } +.has-draft::after { content: ''; position: absolute; top: 6px; right: 5px; width: 6px; height: 6px; border-radius: 50%; background: var(--accent); } +.button { min-height: 36px; border: 1px solid #d5d7df; border-radius: 6px; background: #fff; padding: 7px 10px; display: inline-flex; align-items: center; justify-content: center; gap: 6px; font-size: 12px; font-weight: 550; white-space: nowrap; } +.button:hover { background: #f3f0fa; } +.button.primary { background: var(--accent); border-color: var(--accent); color: #fff; } +.button.primary:hover { background: #483597; } +.button svg { width: 15px; height: 15px; } +.segment { display: flex; background: #eaeaf0; padding: 3px; border: 1px solid #dcdde4; border-radius: 7px; gap: 3px; } +.segment button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; min-height: 38px; flex: 1; padding: 6px 10px; border-radius: 4px; font-size: 12px; color: #626774; white-space: nowrap; } +.segment button[aria-pressed="true"] { background: white; color: #333743; box-shadow: 0 1px 3px #27243818; } +.outer-space { flex: 1; min-height: 0; overflow: hidden; } +.outer-space[data-presentation="tabs"] { display: flex; } +.outer-space[data-presentation="tabs"] .workspace-host:not(.selected) { display: none; } +.outer-space[data-presentation="windows"] { display: flex; gap: 12px; padding: 12px; overflow-x: auto; scroll-snap-type: x mandatory; align-items: stretch; } +.workspace-host { min-width: 0; flex: 1; display: flex; flex-direction: column; background: #f0f0f5; container-type: inline-size; } +.outer-space[data-presentation="windows"] .workspace-host { flex: 0 0 calc(50% - 6px); min-width: 430px; border: 1px solid #c9cbd5; border-radius: 9px; overflow: hidden; box-shadow: 0 7px 17px #25253e0b; scroll-snap-align: center; } +.outer-space[data-presentation="windows"] .workspace-host:only-child { flex-basis:100%; } +.outer-space[data-presentation="windows"] .workspace-host.selected { border-color: #9889c5; } +.window-bar { display: none; align-items: center; justify-content: space-between; gap: 4px; padding: 3px 7px; background: #f8f8fc; border-bottom: 1px solid var(--line); } +.outer-space[data-presentation="windows"] .window-bar { display: flex; } +.app[data-presentation="windows"] > .app-bar > .workspace-actions { display: none; } +.window-identity { display: flex; align-items: center; gap: 7px; min-height: 38px; text-align: left; font-size: 13px; } +.window-identity span { color: var(--muted); font-size: 11px; } +.compact-view-bar { display: none; align-items: center; gap: 4px; min-height: 46px; padding: 2px 8px; border-bottom: 1px solid var(--line); background: #f5f2fb; } +.view-picker { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; min-height: 40px; padding: 6px; text-align: left; border-radius: 5px; font-size: 13px; } +.view-picker strong { font-weight: 550; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.chevron-down { width: 12px; height: 12px; transform: rotate(90deg); } +.child-canvas { position: relative; flex: 1; min-height: 0; padding: 12px; overflow: auto; } +.child-canvas[data-layout="tiles"] { display: grid; grid-template-columns: minmax(0,1.45fr) minmax(0,1fr); grid-template-rows: repeat(2,minmax(0,1fr)); gap: 12px; } +.child-canvas[data-layout="tiles"].one { grid-template-columns: 1fr; grid-template-rows: 1fr; } +.child-canvas[data-layout="tiles"].two { grid-template-rows: 1fr; } +.child-canvas[data-layout="tiles"].three .child:first-child { grid-row: span 2; } +.child-canvas[data-layout="tiles"].many { grid-template-columns: repeat(2,minmax(0,1fr)); grid-template-rows: none; grid-auto-rows: minmax(310px,1fr); } +.child-canvas[data-layout="focus"] { display:flex; padding:0; } +.child-canvas[data-layout="focus"] .child { width:100%; border:0; border-radius:0; } +.child-canvas[data-layout="focus"] .child:not(.focused) { display: none; } +.child-canvas[data-layout="float"] { background-image: radial-gradient(#c7c6d1 .7px,transparent .7px); background-size: 16px 16px; margin: 12px; padding: 0; border: 1px solid #dedde7; border-radius: 8px; overflow: hidden; } +.child-canvas[data-layout="float"] .child { position: absolute; box-shadow: 0 9px 25px #2a224b20; } +.child { container-type:inline-size; min-width: 0; min-height: 0; display: flex; flex-direction: column; border: 1px solid #d2d4de; background: white; border-radius: 7px; overflow: hidden; } +.child.focused { border-color: #a18dcf; box-shadow: 0 0 0 1px #a18dcf1a; } +.child-titlebar { min-height: 43px; display: flex; align-items: center; gap: 3px; padding: 2px 4px; background: #fafafd; border-bottom: 1px solid #e4e4ec; } +.child.focused .child-titlebar { background: #f1edf9; } +.child-title { display: flex; align-items: center; gap: 5px; min-width: 0; flex: 1; min-height: 36px; text-align: left; padding: 5px; border-radius: 4px; color: #4e5360; font-size: 13px; } +.child-title strong { font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } +.child-title .chevron-down { margin-left: 3px; } +.child-canvas[data-layout="float"] .child-titlebar { touch-action: none; user-select: none; } +.child-canvas[data-layout="float"] :is(.child-titlebar,.child-title,[data-drag]) { cursor: grab; } +.child-canvas[data-layout="float"] .child-titlebar[data-moving] :is(.child-title,[data-drag]), .child-canvas[data-layout="float"] .child-titlebar[data-moving] { cursor: grabbing; } +.child-body { display: flex; flex-direction: column; flex: 1; min-height: 0; overflow: hidden; } +.child-toolbar { display: flex; align-items: center; justify-content: space-between; padding: 5px 9px; gap: 8px; border-bottom: 1px solid var(--line); min-height: 48px; background: #fff; } +.comparison-button { display: flex; align-items: center; gap: 7px; min-height: 36px; min-width: 0; padding: 5px 3px; text-align: left; color: #65577f; font-size: 12px; line-height: 1.35; } +.reviewed { color: #28704e; font-size: 12px; display: flex; align-items: center; gap: 5px; white-space: nowrap; } +.compact-only { display: none; } +.pane-scroll { overflow: auto; min-height: 0; flex: 1; overscroll-behavior: contain; } +.diff-table { width: 100%; border-collapse: collapse; font-family: ui-monospace,SFMono-Regular,Menlo,Consolas,monospace; font-size: 12px; line-height: 25px; } +.diff-table td { padding: 0; vertical-align: top; } +.diff-table .num { min-width: 30px; width: 30px; padding: 0 5px; text-align: right; color: #626774; font-size: 10px; user-select: none; } +.diff-table .sign { min-width: 20px; width: 20px; text-align: center; user-select: none; } +.diff-table .code { white-space: pre; padding-right: 18px; color: #4e5563; } +.diff-table .add { background: #edf7f0; } +.diff-table .delete { background: #fff0ee; } +.diff-table .add .code, .diff-table .add .sign { color: #286042; } +.diff-table .delete .code, .diff-table .delete .sign { color: #8b443f; } +.diff-table .add .num { background: #e2f0e6; color: #4c705b; } +.diff-table .delete .num { background: #f9e5e2; color: #875e5a; } +.code-end { padding: 18px 13px 30px; color: #626774; font-size: 11px; } +.empty-state { max-width: 360px; margin: auto; padding: 35px 20px; text-align: center; } +.empty-state h2 { font-size: 16px; font-weight: 600; letter-spacing: -.2px; margin-bottom: 9px; } +.empty-state p { color: #626774; font-size: 12px; line-height: 1.7; margin-bottom: 15px; } +.check-circle { display: grid; place-items: center; width: 39px; height: 39px; margin: 0 auto 14px; border-radius: 50%; background: #e8f3ed; color: #28704e; } +.source-select { min-width: 0; flex: 1; max-width: 75%; padding: 7px; border: 1px solid #d2d4dc; border-radius: 5px; font-size: 13px; background: #fff; } +.search-content { padding: 12px; overflow: auto; flex: 1; } +.search-content p { color: #626774; font-size: 12px; line-height: 1.7; margin-top: 7px; } +.search-form { display: flex; gap: 7px; margin: 0 0 12px; } +.search-form input { min-width: 0; flex: 1; min-height: 40px; border: 1px solid #ccc7dc; border-radius: 6px; padding: 9px; font-size: 13px; } +.search-result { display: block; width: 100%; text-align: left; padding: 12px; border: 1px solid var(--line); border-radius: 6px; margin-top: 10px; background: #fff; } +.search-result:hover { background: #faf8ff; } +.search-result strong { display: block; font-size: 13px; font-weight: 550; } +.search-result code { display: block; margin-top: 7px; font-size: 12px; color: #626774; white-space: pre-wrap; overflow-wrap: anywhere; } +.search-result small { display: block; color: var(--accent); font-size: 11px; margin-top: 8px; } +.example-search { color: var(--accent); min-height: 36px; padding: 6px 0; font-size: 12px; text-decoration: underline; } +.preview-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 5px 10px; border-bottom: 1px solid var(--line); } +.simulated-badge { color: #6b536e; font-size: 11px; background: #f7edf7; border: 1px solid #e7d8e7; padding: 4px 6px; border-radius: 4px; white-space: nowrap; } +.preview-toolbar select { max-width: 150px; min-height: 36px; padding: 6px; border-radius: 5px; border: 1px solid #d5d1de; background: #fff; font-size: 12px; } +.preview-stage { background: #f0eef7; flex: 1; min-height: 0; padding: 16px; overflow: auto; } +.preview-device { border: 1px solid #ccc8db; border-radius: 12px; max-width: 320px; margin: auto; background: #fff; box-shadow: 0 6px 14px #2d244914; padding: 16px; min-height: 190px; } +.preview-app-name { display: flex; justify-content: space-between; font-size: 15px; font-weight: 650; margin-bottom: 12px; } +.preview-search { background: #f3f3f7; border-radius: 6px; padding: 9px; color: #626774; font-size: 12px; margin-bottom: 10px; } +.preview-item { padding: 10px 0; border-bottom: 1px solid #ededf2; display: flex; gap: 9px; align-items: center; font-size: 13px; } +.preview-item svg { color: #7b688f; } +.preview-item small { display: block; margin-top: 4px; font-size: 11px; color: #626774; } +.preview-empty { text-align: center; padding: 25px 10px; color: #626774; font-size: 12px; line-height: 1.8; } +.preview-empty strong { display: block; color: #4a4358; } +.resize-handle { display: none; position: absolute; bottom: 2px; right: 2px; width: 28px; height: 28px; background: #f3effa; color: #796b94; border-radius: 5px; cursor: nwse-resize; touch-action: none; z-index: 5; } +.child-canvas[data-layout="float"] .resize-handle { display: grid; place-items: center; } +.resize-handle svg { width: 14px; height: 14px; } +dialog { width: min(460px,calc(100% - 28px)); max-height: calc(100dvh - 36px); padding: 20px; border: 1px solid #d7d4e0; border-radius: 12px; box-shadow: 0 20px 80px #29203933; color: var(--ink); } +dialog::backdrop { background: #2a283955; } +.dialog-heading { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 12px; } +dialog h2 { font-size: 18px; font-weight: 600; letter-spacing: -.35px; } +dialog h3 { font-size: 13px; margin: 18px 0 8px; font-weight: 600; } +dialog p { font-size: 13px; color: #626774; line-height: 1.65; } +.view-options { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 8px; } +.view-option { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; text-align: left; border: 1px solid #dcd9e5; border-radius: 8px; padding: 14px; min-height: 102px; } +.view-option:hover { background: #f6f2fe; border-color: #b6a6d9; } +.view-option svg { color: var(--accent); } +.view-option strong { font-size: 13px; font-weight: 600; } +.view-option small { color: #626774; font-size: 12px; line-height: 1.5; } +dialog label { display: block; font-size: 13px; margin-top: 18px; margin-bottom: 8px; } +dialog textarea { width: 100%; min-height: 130px; padding: 10px; border: 1px solid #cbc7d7; border-radius: 6px; font-size: 13px; line-height: 1.7; } +.dialog-footer { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-top: 16px; color: #626774; font-size: 12px; } +.menu-list { display: flex; flex-direction: column; gap: 4px; margin-top: 10px; } +.menu-row { display: flex; align-items: center; gap: 5px; } +.menu-item { display: flex; align-items: center; gap: 10px; width: 100%; min-height: 44px; border: 1px solid transparent; border-radius: 6px; padding: 9px; font-size: 13px; text-align: left; } +.menu-item:hover, .menu-item[aria-current="true"] { background: var(--tint); border-color: #d2c5eb; } +.menu-item span { min-width: 0; flex: 1; } +.menu-item small { display: block; color: #626774; font-size: 11px; margin-top: 3px; } +.metadata { display: grid; grid-template-columns: auto minmax(0,1fr); gap: 8px 12px; margin: 14px 0; font-size: 12px; line-height: 1.5; } +.metadata dt { color: #626774; }.metadata dd { margin: 0; overflow-wrap: anywhere; } +.workspace-title { font-size: 15px; font-weight: 550; line-height: 1.5; } +.toast { position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); max-width: calc(100% - 28px); padding: 11px 16px; background: #2b2935; color: #fff; border-radius: 8px; box-shadow: 0 4px 18px #21183130; font-size: 12px; z-index: 100; pointer-events: none; } +.toast:empty { display: none; } +.workspace-host[data-layout="focus"] .compact-view-bar { display: flex; } +.child-canvas[data-layout="focus"] .child-titlebar { display: none; } +.child-canvas[data-layout="focus"] .compact-only { display: flex; } +@container (max-width: 680px) { + .child-canvas[data-layout="tiles"], .child-canvas[data-layout="tiles"].one, .child-canvas[data-layout="tiles"].two, .child-canvas[data-layout="tiles"].many { grid-template-columns:minmax(0,1fr); grid-template-rows:none; grid-auto-rows:minmax(320px,1fr); } + .child-canvas[data-layout="tiles"].three .child:first-child { grid-row:auto; } + .child-canvas[data-layout="float"] .resize-handle { width:44px; height:44px; } + .icon-button, .button, .view-picker, .comparison-button, .source-select, .preview-toolbar select { min-height: 44px; } + .icon-button { width: 44px; } + .child-toolbar { padding: 3px 8px; gap: 6px; } + .child-toolbar .button { padding: 7px 9px; } + .comparison-button { font-size: 12px; flex: 1; } + .preview-toolbar { padding: 3px 10px; } + .search-form input { min-height: 44px; } +} +@container (max-width: 520px) { + .app-bar { gap: 2px; padding: 0 4px; } + .workspace-tab { padding: 0 7px; gap: 5px; font-size: 12px; flex: 1; } + .workspace-tab svg, .workspace-picker span { display: none; } + .workspace-picker { width:44px; min-height:44px; padding:0; } + .workspace-tab-shell > .icon-button, .window-bar > .icon-button { width:44px; height:44px; } + .workspace-actions .icon-button { width: 44px; min-height: 44px; } + .outer-space[data-presentation="windows"] { padding: 7px; gap: 8px; } + .outer-space[data-presentation="windows"] .workspace-host { min-width: 100%; flex-basis: 100%; } +} +@media (max-width: 650px) { + .lab { padding: 0 12px; height: 44px; } + .prototype-controls summary { gap: 7px; } + .stage { width: 100%; } + .app { border-radius: 0; border-left: 0; border-right: 0; height: calc(100dvh - 44px); min-height: 400px; } + .prototype-panel .button, .prototype-panel select, dialog .button, dialog .icon-button, dialog .segment button { min-height: 44px; } + dialog .icon-button { width: 44px; } +} + +/* Typed comparison content remains inside the existing scroll pane. */ +.renderer-tools { display:flex; align-items:center; justify-content:space-between; gap:10px; padding:8px 12px; border-bottom:1px solid var(--line); background:#faf9fd; } +.renderer-tools > span { display:flex; align-items:center; gap:7px; font-size:12px; color:#626774; } +.renderer-tools .segment { flex-shrink:0; }.renderer-tools .segment button { min-height:32px; font-size:11px; padding:4px 8px; } +.lfs-badge, .availability-badge { display:inline-block; flex:0 0 auto !important; font-size:10px; padding:3px 5px; border-radius:4px; background:#efedf5; color:#625378; white-space:nowrap; } +.availability-badge { background:#fff2df; color:#855817; } +.rich-comparison { padding:14px; }.rich-comparison > .diff-table { margin:-14px; width:calc(100% + 28px); } +.content-note, .skip-note { padding:10px 12px; margin:0 0 12px; background:#f5f2fb; border:1px solid #e5ddf2; border-radius:6px; font-size:12px; line-height:1.6; color:#65577f; } +.skip-note { margin:0; border-radius:0; border-width:0 0 1px; background:#fff6e8; border-color:#ecddc5; color:#755825; } +.comparison-pair { display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:12px; } +.content-card { min-width:0; border:1px solid #dddde5; border-radius:8px; overflow:hidden; background:#fff; } +.content-card h3 { padding:11px 13px; background:#f7f7fa; border-bottom:1px solid #e4e4ec; font-size:12px; font-weight:600; color:#626774; } +.markdown-preview { padding:18px 15px; font-size:13px; line-height:1.7; }.markdown-preview h2 { font-size:20px; letter-spacing:-.4px; line-height:1.3; margin-bottom:16px; }.markdown-preview p { margin-top:13px; }.markdown-link { color:var(--accent); text-decoration:underline; } +.source-detail { padding:12px 15px; border-top:1px solid #e6e4ec; font-size:11px; color:#626774; }.source-detail code { display:block; margin-top:7px; overflow-wrap:anywhere; color:#5942b6; } +.locale-changes { display:flex; flex-direction:column; gap:12px; }.locale-change { border:1px solid #dddde6; border-radius:7px; overflow:hidden; font-size:13px; } +.locale-change header { display:flex; justify-content:space-between; gap:8px; padding:11px 13px; background:#f6f5fa; }.locale-change header code { overflow-wrap:anywhere; }.locale-change header span { font-size:11px; color:#65577f; } +.locale-change > div { display:grid; grid-template-columns:54px minmax(0,1fr); gap:8px; padding:11px 13px; border-top:1px solid #e9e7ee; }.change-label { color:#626774; font-size:11px; }.old-value { color:#8b443f; }.new-value { color:#286042; } +.asset-image { display:block; width:100%; height:auto; padding:12px; background:#f0eef6; }.asset-metadata { display:grid; grid-template-columns:auto minmax(0,1fr); gap:8px; margin:0; padding:13px; border-top:1px solid #e5e4ec; font-size:11px; line-height:1.5; }.asset-metadata dt { color:#626774; }.asset-metadata dd { margin:0; overflow-wrap:anywhere; }.asset-metadata code { font-size:10px; } +.absent-content { display:grid; place-items:center; min-height:140px; padding:20px; color:#626774; font-size:12px; background:#f5f4f8; } +.unavailable-note { padding:14px; margin-bottom:14px; border:1px solid #ead6b3; border-radius:7px; color:#78551e; background:#fff7eb; font-size:13px; line-height:1.6; }.unavailable-note p { margin-top:7px; }.unavailable-label { font-size:11px; color:#78551e; max-width:96px; line-height:1.4; } +.progress-summary { font-size:12px; color:#626774; margin:0 0 10px; }.file-filter { margin:12px 0; }.file-groups { display:flex; flex-direction:column; gap:8px; } +.file-group { border:1px solid #dfdce8; border-radius:7px; overflow:hidden; }.group-heading { display:flex; align-items:center; gap:2px; padding:3px; background:#f8f7fb; } +.group-disclosure { min-height:50px; min-width:0; flex:1; display:flex; align-items:center; gap:7px; text-align:left; padding:7px; }.group-disclosure > span { min-width:0; flex:1; }.group-disclosure strong { display:block; font-size:13px; font-weight:600; }.group-disclosure small { display:block; font-size:10px; line-height:1.6; margin-top:4px; color:#626774; }.group-disclosure > svg:last-child { width:12px; height:12px; }.group-disclosure[aria-expanded="true"] > svg:last-child { transform:rotate(90deg); } +.group-actions { display:flex; flex-direction:column; padding-right:4px; }.group-actions button { min-height:36px; min-width:48px; font-size:11px; color:var(--accent); border-radius:4px; }.group-actions button:hover { background:var(--tint); }.group-actions small { display:block; font-size:10px; } +.file-item { border-radius:0; border-width:1px 0 0; border-color:#e9e5ee; }.file-item > span:first-child { overflow-wrap:anywhere; }.file-item .lfs-badge, .file-item .availability-badge { font-size:9px; }.group-empty { padding:10px 12px; font-size:12px; line-height:1.6; color:#626774; } +@container (max-width:680px) { .comparison-pair { grid-template-columns:1fr; }.renderer-tools { padding:5px 9px; }.renderer-tools .segment button { min-height:44px; }.rich-comparison { padding:12px; } } +@media (max-width:650px) { .group-actions button { min-height:44px; min-width:44px; }.group-disclosure { min-height:60px; }.group-disclosure small { font-size:11px; }.renderer-tools > span { font-size:11px; } } diff --git a/Plans/2026-11-14-mobius/Prototype/tsconfig.json b/Plans/2026-11-14-mobius/Prototype/tsconfig.json new file mode 100644 index 000000000..1b9b804d4 --- /dev/null +++ b/Plans/2026-11-14-mobius/Prototype/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "astro/tsconfigs/strict", + "compilerOptions": { "types": ["node"] }, + "include": [".astro/types.d.ts", "src/**/*", "astro.config.mjs"], + "exclude": ["dist"] +} diff --git a/Plans/2026-11-14-mobius/README.md b/Plans/2026-11-14-mobius/README.md index 422d166d7..70c1b60f7 100644 --- a/Plans/2026-11-14-mobius/README.md +++ b/Plans/2026-11-14-mobius/README.md @@ -2,14 +2,13 @@ ## Planning checkpoint -- Updated: 2026-11-14; initial repository baseline `b629d56ac44a3f2a5ea59c3d6ae9cd5401f37674`; merged main through `96f5bf0f1685de259d7ff080842b8092f9a950d2` in `68477fe625784a1a1e68c0115d7e42cc63166692`. -- Operation: Add explicit closing and reopening of PR workspaces to the prototype and record the lifecycle in the production outlines. -- Requested scope and source: On 2026-11-14, the user reports that PR 42 and PR 43 cannot be dismissed and requests closing/reopening workspaces. This extends the existing retained-workspace and restoration decisions; it does not request native implementation. -- Stage: Close/reopen behavior is integrated into the shared contract and native outlines; 01a method `0768b8c0d` is reviewed and ready for the authorized prototype work. -- Completed: The title-bar follow-up is also published at `f21e01fec` with receipt `ac4ac4478`; its focused browser checks, independent review, and scoped Chromium/WebKit check pass. Q-22–Q-25 and affected production outlines are integrated and reviewed. The fourth prototype iteration and its focused layout correction are built. The correction checks actual selected/rendered geometry, narrow movement/resize, and preserved workspace state; fresh independent review has no actionable findings. The coordinator verified the final HTML/capture hashes and inspected representative phone/tablet/desktop captures. Earlier artifacts/evidence remain intact. [01a's execution record](https://github.com/kyleve/Stuff/blob/codex/mobius-prototype/Plans/2026-11-14-mobius/01a-workspace-prototype.md#layout-correction-implementation-and-evidence) owns detailed evidence and publication. [PR #497](https://github.com/kyleve/Stuff/pull/497)/[STU-329](https://linear.app/kve/issue/STU-329/plan-mobius-code-review-app) track the plan; [PR #500](https://github.com/kyleve/Stuff/pull/500)/[STU-330](https://linear.app/kve/issue/STU-330/prototype-mobius-review-workspaces) track the experiment. -- Pending: Cascade this parent revision into the clean method checkpoint, then implement, verify, and publish the demo. The implementation branch owns current 01a execution evidence and its checkpoint. User evaluation, PR review, and merge remain. Q-09 retains cross-device open/closed presentation policy. -- Execution authorization and ownership: The user's request authorizes this bounded prototype change. `/root/mobius_prototype` owns `Prototype/**` and 01a on `codex/mobius-prototype`; the coordinator owns shared requirements/native outlines on `codex/mobius-plan` and the completion notice. Cascade at a clean method checkpoint before UI edits. The implementation branch then owns the current execution checkpoint and publication receipt. Native implementation remains outside scope. -- Next action: Publish the coordinated plan/method and release prototype implementation. Its next evaluation covers active/inactive/last-workspace closure and retained-state reopening. The 01a copy here is the pre-execution baseline; its implementation branch owns current methods, evidence, and resume points. Native plans remain outlines. +- Updated: 2026-11-15; initial repository baseline `b629d56ac44a3f2a5ea59c3d6ae9cd5401f37674`. The stack is now based on main `2193072f6a1c988f797c77c14c3b6cf0923d8ca0`, including merged [PR #503](https://github.com/kyleve/Stuff/pull/503). +- Operation and source: The user reported #503 merged after approving the shared prototype command. The coordinator synced the Mobius stack and adopted that command in the prototype's run/check/build instructions. +- Stage: Astro migration and reusable tooling are delivered. The preview remains available for user evaluation; [01a](01a-workspace-prototype.md#astro-implementation-and-evidence) retains the implementation and verification history. +- Completed: The stack sync preserves the prototype source/configuration, archived artifacts and capture bytes. The merged command verifies the existing server and current local/LAN URLs; check/build pass. [PR #497](https://github.com/kyleve/Stuff/pull/497)/[STU-329](https://linear.app/kve/issue/STU-329/plan-mobius-code-review-app) track the plan; [PR #500](https://github.com/kyleve/Stuff/pull/500)/[STU-330](https://linear.app/kve/issue/STU-330/prototype-mobius-review-workspaces) track the experiment. +- Pending: User evaluation and integration of further product decisions. The prior completion notices and separate workflow PR are delivered; 01a remains executing and native plans 01–07 remain outlines. +- Ownership: Coordinator `/root` owns the running preview and completion reporting in `/Users/kve/.codex/worktrees/mobius-prototype/Stuff` on `codex/mobius-prototype`; the background prototype implementation task has returned. [Run/status/stop commands](Prototype/README.md#run-the-demo) identify the owned project. +- Next action: Continue product discussion and integrate evaluation before refining the next planning horizon. Keep the intentional review server running through handoff. ## Outcome and scope @@ -420,7 +419,7 @@ User answers came from this chat on 2026-11-14. Q-13–Q-25 refine the original ### Q-18 - Answer/source: Lightweight interactive mockup for quick iteration. -- Integration: 01a produces a self-contained browser artifact; native UIKit targets, persistent stores, authentication, and CloudKit remain later work. +- Integration: 01a produces a lightweight browser prototype, now authored through the repository’s pinned Astro toolchain at the user’s request. Fixtures remain local and session-only; native UIKit targets, persistent stores, authentication, and CloudKit remain later work. - History: Asked, answered, integrated, and closed after checking prototype scope and acceptance. Browser technology is an implementation choice for the mockup, not the production app architecture. ### Q-19