Skip to content

Windows parity: Dialog and sheet framework: in-window dark sheets that size to content and never clip #768

Open

Description

@coneilen

Visual and functional parity work item, from the 2026-10-13 side-by-side review.

  • Comparison: macOS reference Run A (app at 09eda11a, Dark, 2x) against the Windows testing-gaps run (installed 0.1.78-windows.beta26, 2560x1440 at 100%).
  • Ground truth: macOS is the reference. Only platform chrome may differ: the title bar, window buttons, menu-bar location and native file pickers.
  • Evidence limits:
    • File names below refer to the two local evidence bundles. The next macOS ground-truth run will attach captures.
    • Difference IDs (D1, E2, …) refer to the review report.
    • The reviewer opened the paired images it cites. Some surfaces could not be reviewed; they are listed under "Captures needed" in the ledger entry.
  • Done when: every acceptance box is met and shown with paired screenshots in the PR. Before/after Windows captures go next to the macOS capture, and a reviewer from a different model vendor confirms them. A UIA readback or green unit test alone does not satisfy a visual criterion.

Evidence:

  • macOS: 750-rename-prompt, 750-delete-loop-confirmation, 750-delete-loops-confirmation-attempt3, 750-delete-project-folder-confirmation, 750-promote-to-goal-form, 750-new-loop-sheet-type-Goal;
  • Windows: tg750-rename, tg750-new-workspace, tg734-template-dialog, tg734-delete-dialog, tg735-promote-dialog, tg733-edit-details-form, tg750-create-edge, tg750-worktrees;
  • differences L1–L3, O1–O2, U1–U2, K3, M2, N1, S1; issue Windows Update node dialog: Check description field sits under OK/Cancel and cannot be typed into #760;
  • source: WindowsNativeDialogs.zig:86-127, NativeForms.zig:101-106, 1221.

Acceptance criteria:

  • Every prompt, sheet and confirmation is dark, rounded and centred over a dimmed app window, with no light title bar or grey label bands.
  • Dialog height is computed from content plus the non-client frame. No button or field is ever outside the client area or under the footer, at 100%, 150% and 200% DPI.
  • No scrollbar appears unless the content exceeds the sheet's maximum height. The scroll region ends above a fixed footer, as in 750-new-loop-sheet-type-Goal.
  • The footer has a "Cancel" text button on the left, a validation reason, and a blue primary capsule with a ⏎ hint, disabled while invalid. Destructive primaries are red.
  • Rename reads 'Rename "<title>"', uses the macOS body copy, and has a Rename button. Delete Loop uses the macOS copy and Cancel/Delete, not a system MessageBox.
  • Fields are rounded and filled, with a blue focus ring and selected initial text.

Activity

  1. added
    enhancementNew feature or request
    parityWindows/macOS UI parity ledger row (investigation/ui-parity-matrix.md)
    P1 layoutParity priority 1: layout, clipping, overlap, broken rendering vs macOS
    visual parityVisual fidelity against the macOS reference captures
    on Oct 14, 2026
  2. coneilen commented on Oct 14, 2026

    @coneilen
    CollaboratorAuthor

    Escalation record (wave 1, lane A), 2026-10-14 02:45 PDT.

    Old model claude-sonnet-5.5, xhigh (lane A2, itself the 1st escalation from gpt-6.1-sol)
    Trigger 2 substantive rubber-duck rejections (reviewer gpt-6.1-sol, high), per the abandon rule in investigation/windows-parity-orchestration-plan.md
    New model claude-opus-5.5, max, long_context (lane A3)

    State handed over: branch coneilen-microsoft-content-sized-dialogs-768 at c56a6b34 (8 commits, starting with the cherry-pick of WIP 059d8457); no PR opened.

    Done and evidenced by A2:

    • Root cause of the white label strips and white footer band: statics under WS_CLIPCHILDREN returned a hollow brush to WM_CTLCOLORSTATIC, so nothing painted those pixels. They now use an opaque panel brush, through shared helpers in WindowsNativeDialogs.zig.
    • Root cause of the label overlap: stale pixels left after moving controls with repaint suppressed. layoutForm now ends with a RedrawWindow of the content viewport.
    • Prompts now paint dark.
    • RED/GREEN logs for both fixes.
    • Full -ShellPart unit exit 0, 55/55 sections.
    • Paired before/after captures.
    • Found the harness issue uia-live-gate ActivateWindow Alt tap can leave a modal dialog in system-menu mode #797 (the Alt tap in ActivateWindow).

    Reviewer findings that A3 must close:

    1. A real bug inherited from the WIP: the Project Settings .worktree_policy form sizes its window and scrollbar with scaled(316), but the scroll clamps use contentHeight(), which is 92 for that form. Under overflow, the threshold inputs can't be scrolled into view.
    2. A PR-body overclaim: "every form kind" for the geometry coverage. The test covers four node variants, update, edge and default-Goal promotion.

    A3 rebases onto current main and re-runs all cited evidence on its own head.

  3. 46 remaining items

  4. coneilen commented on Oct 14, 2026

    @coneilen
    CollaboratorAuthor

    Wave 1 stopped (operator decision, 2026-10-14). No PR was opened. A3 reached af5e951a: it cherry-picked A2's commits, fixed the Project Settings scroll clamp, and made Project Settings reveal on focus. All this work is abandoned. Root causes worth reusing in wave 2:

    • White label strips and white footer band: statics under WS_CLIPCHILDREN answered WM_CTLCOLORSTATIC with a hollow brush, so nothing painted those pixels.
    • Label overlap: stale pixels left after moving controls with repaint suppressed. A RedrawWindow of the viewport at the end of layout fixes it.
    • Overflow: the .worktree_policy form sized its scrollbar with scaled(316) but clamped scrolling with contentHeight(), which is 92.
    • PR claims: the geometry guard covers only node, update, edge and default-Goal forms; don't claim "every form kind".

    Restarting from main under investigation/windows-parity-lane-kickoff.md.

  5. coneilen commented on Oct 14, 2026

    @coneilen
    CollaboratorAuthor

    Implementation plan (wave 2)

    Planning worker pa, lane A. Investigated baseline: origin/main = 8ea81062. This is a plan, not an implementation or runtime sign-off. No product files changed, no desktop used, and no build or test execution is claimed.

    Decision: first PR fixes bounded geometry, not the entire visual redesign

    First slice: make GraphCodeWindowsDialog text prompts and GraphCodeNativeForm forms size from their content, preserve a fixed footer, and make overflow reachable without paint artifacts. Rename/New Workspace/Save as Template have the same clipped-button defect; short promotion forms unnecessarily occupy a full-height window; long forms need one consistent viewport/scroll extent. These are the shared P1 foundation for later forms, not an invitation to implement New Node, Settings, or Worktrees feature parity here.

    Keep current commands, values, labels, field ordering, modal outcomes, ownership checks and persistence semantics. Do not remove Edit Details: macOS has no such sheet, but Windows has actions there without equivalent Windows routes. Do not bulk-cherry-pick the abandoned branch: its three-file diff is 1,885 insertions/185 deletions and includes more than this slice.

    Acceptance accounting: this PR delivers the content/frame sizing and fixed-footer/overflow subconditions of boxes 2 and 3 for the two named window classes, and removes unpainted label/footer bands in those classes. It does not close any issue-wide checkbox in full: box 2 says no field/button ever clips, but Product Settings and the separate update dialogs are additional implementations; box 3's universal sheet scope also needs those surfaces audited. Boxes 1, 4, 5 and 6 remain open. Keep all six issue boxes unticked rather than converting a scoped framework fix into an “every prompt” claim. The coordinator can approve a narrower checklist on this comment, but the PR must use Refs #768, not Fixes #768.

    Findings reused from the stopped wave, checked against source

    Read Wave 1 stopped before investigating. Also read the earlier escalation/review findings and inspected retained commit af5e951a read-only.

    • Main's NativeForms.formCtlColorStatic (graphcode-windows/src/NativeForms.zig:1295-1300) returns NULL_BRUSH with transparent background. The stopped branch's shared colorSheetStatic instead returns a solid panel brush, sets panel background color, and uses OPAQUE. Important distinction: main does not yet have that branch's WS_CLIPCHILDREN content viewport. The “nothing paints behind statics under WS_CLIPCHILDREN” defect is confirmed in the abandoned architecture, not evidence that main already has that architecture. Port the opaque paint contract together with any new clipped viewport.
    • Main's layoutContentControl moves controls with repaint disabled (NativeForms.zig:2391) and layoutForm ends after updateScrollBar (2315-2362). The retained branch adds a viewport RedrawWindow(... RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN) after layout. Preserve this repair when introducing the viewport; do not rely on old control pixels being erased automatically.
    • On main, .worktree_policy has zero generic fields (NativeForms.zig:1416), although WM_CREATE places policy controls through y=308 (1579-1594). Generic contentHeight consequently returns 92 design units (2404-2413), and both range and clamps use that wrong value. In the intermediate abandoned implementation the range used 316 while clamps still used 92; the final retained commit fixes both with one policy extent and adds policy focus reveal. Do not reproduce that intermediate mismatch. A 316-unit policy extent is justified by its last body line ending at 308 plus trailing space; validation belongs in the footer, not that extent.
    • Main's existing geometry tests (NativeForms.zig:4740-4807,4841-4852) are mostly arithmetic/clipping assertions, not coverage of every live form. The stopped-wave “four node variants, update, edge, default-Goal promotion” guard was also not every kind. Enumerate coverage explicitly below.

    Acceptance-by-acceptance source audit

    Paths below are repository-relative. macOS source is the behavioral reference; Run A confirms the visible result at source 09eda11a. Current source citations are at baseline 8ea81062.

    Box Exact macOS behavior/reference Current Windows behavior/root cause Disposition
    1. Dark, rounded, centered, dimmed owner; no light title/label bands graphcode/Sources/Features/App/AppView.swift:153 forces dark. New Node uses .sheet/Theme.sheet (Project/NodeDraftForm.swift:39-76); Promote uses SketchPromotionForm.swift:21-32. Run A 750-new-loop-sheet-type-Goal, 750-promote-to-goal-form, 750-rename-prompt, 750-delete-loop-confirmation visibly show rounded centered panels over a dimmed window. Theme.swift:190 is sheet #2a2a2e. NativeForms.show:1186-1243 creates a captioned separate HWND centered on monitor work area, not an owner-dimmed in-window sheet. WindowsNativeDialogs.createDialogWindow:118-134 uses CW_USEDEFAULT, WS_CAPTION, WS_VSCROLL, and no dark paint handlers (windowProc:191-274). formCtlColorStatic:1295-1300 has the hollow-brush hazard noted above. WindowsProductSettings.open:245-272 is another captioned window. Fix paint coverage in the two named classes as a coupled geometry prerequisite. Leave rounded in-window presentation, scrim, light title bar removal, and all other dialog families open.
    2. Content + non-client frame; no field/button clipped at 100/150/200% Promote is intrinsically sized with width >=460, content padding and no fixed height (SketchPromotionForm.swift:21-32). Rename is an alert with one field (AppView.swift:211-231), not an arbitrary 600x202 frame. New Node is an intentional exception to “shrink every sheet”: min height 560, ideal 760, resizable (NodeDraftForm.swift:60-69). Text prompts use outer height 150 + count*52 or 620, then place buttons at outerHeight-55 (WindowsNativeDialogs.textWithDescription:86-91, WM_CREATE:196-202, createButton:329-336); non-client pixels are never added, and footer coordinates are not derived from client bounds. Description height is fixed 36 (277-293). Native forms always request 760, or policy 520, as outer height (NativeForms.show:1210-1240), regardless of contentHeight. layoutFooter:2488-2508 uses fixed button widths; “Remove Selected” can truncate and auxiliary buttons share space allocated to validation. Product Settings separately fixes its client at 620x830 (WindowsProductSettings.zig:245-250,373-374), with no monitor-fit/DPI policy. Primary slice: measured prompt content; short forms shrink; tall forms cap; account for the real non-client frame and work-area limit; footer text fits. Do not shrink New Node below its macOS minimum when the work area can accommodate it. Product Settings/update dialogs remain future work, so no universal box-2 claim.
    3. Overflow only; scroll region ends above fixed footer New Node's ScrollView wraps type fields, runs-as and recap, not footer (NodeDraftForm.swift:48-58); indicators automatic (57). Footer sits below that scroll view (NodeDraftTemplateBar.swift:143-172). Goal capture shows the scrollbar ending above the footer. Short Promote has no ScrollView (SketchPromotionForm.swift:21-32). Both top-level classes use WS_VSCROLL, including short prompts. Text scrolling uses hard-coded count/510/535 thresholds (WindowsNativeDialogs.zig:220-231,315-326) and does not establish a scrollbar range from content. NativeForms clips each child manually (layoutContentControl:2380-2402) but puts the scrollbar on the whole window; formViewportHeight:186-188 fabricates a minimum 120 even if the actual client is shorter. Policy bypasses layoutForm on creation/resize (1579-1607,1638-1642) and fieldTop cannot reveal its threshold edits because field_count=0 (2305-2313,2458-2470). Primary slice: real bounded viewport, scrollbar owned by that viewport, same extent/page/clamp everywhere, policy included. Other modal implementations and visual parity remain unclaimed.
    4. Footer Cancel/reason/blue capsule/return hint, invalid disabled; destructive red New Node footer has left plain Cancel, optional Save as template, reason and primary (NodeDraftTemplateBar.swift:143-172); primary has return glyph, blue fill, and disabled state (NodeDraftForm.swift:219-247,260-282). Promote matches (SketchPromotionForm.swift:126-170). Not universal: Project Settings has only Done (Worktrees/ProjectSettingsView.swift:118-127); New Workspace has right-aligned Cancel/Create & Open (Workspaces/NewWorkspaceFormView.swift:43-54); Rename/Delete are system alert buttons, not this sheet footer. Delete has semantic .destructive (AppView.swift:176-178), but Run A's Delete primary visibly renders blue, not red. NativeForms.createButton:2478-2485 uses native push buttons; layoutFooter:2488-2508 places Cancel beside the right primary; WM_COMMAND:1713-1725 reports validation on submission rather than updating an invalid disabled primary. Text prompt primary is always OK (WindowsNativeDialogs.zig:201). Only reserve enough geometry for existing footer actions/reason here. Defer semantic/footer redesign. Coordinator should reconcile the literal “red destructive” wording with the captured blue system Delete button before that later slice; do not silently assert every macOS dialog has the New Node footer.
    5. Rename title/body/action; Delete copy and custom confirmation AppView.swift:211-231: Rename “title”, Only the name changes — the loop keeps its session, its edges, and its work., Rename/Cancel. AppView.swift:168-184: Delete “title”?, Its terminal session is ended and every edge touching it is removed. This can't be undone., Delete/Cancel. Rename starts from existing title (ProjectFeature.swift:567-573) and Return submits (AppView.swift:221-225). App.editSelectedNode (graphcode-windows/src/App.zig:3555-3595) passes “Rename Loop”, different description, and gets generic OK. App.deleteSelectedNode:4309-4330 builds different consequence copy and calls GraphContextMenu.confirm; GraphContextMenu.zig:317-323 uses MessageBoxW Yes/No. This cannot be fixed only in NativeForms. Defer. Later scope needs coordinator-approved App.zig function edits and a new confirmation API in leased WindowsNativeDialogs; do not globally replace GraphContextMenu.confirm and change all confirmation semantics in this PR. Preserve current owned-target/revalidation behavior.
    6. Rounded filled fields, blue ring, selected initial text Project/NodeDraftFields.swift:58-81 defines fill, radius 8, 1.5 blue focus border plus outer tint; 91-113 applies it to text fields. Rename capture shows initial title selected; source prepopulates it as above. Not every draft field is automatically selected. NativeForms.createField:2145-2273 creates WS_EX_CLIENTEDGE native EDIT/COMBOBOX; no shared rounded focus-ring renderer. Text prompt edit creation is the same (WindowsNativeDialogs.zig:298-312), but first text is already selected (WM_CREATE:203-206), with existing activation/selection and Enter/Escape tests (498-647). Defer field renderer/ring styling. Preserve existing selection/focus/key contracts; do not claim selection is missing, and do not run foreground-taking legacy tests locally without a lease.

    Related ledger rows read: Node creation / Edge creation / Node update/rename / Sketch promotion; Product Settings / Project Settings / Worktree sweep (investigation/ui-parity-matrix.md:222-230); Loop rename/delete (259-260); dialogs/updates (251-263). Ledger status updates are coordinator-owned. Project Settings currently says Validated; this newly source-identified overflow defect must be called out in the coordinator's subsequent ledger change, not silently used as proof of universal parity.

    Implementation steps and exact test obligations

    Add tests to the existing roots, with filter prefix sheet framework:. Test setup may factor the current creation phase out of the modal presentation loop without changing behavior, so tests call the same production creator while keeping the top-level parent hidden. Do not create a second window/layout implementation only for tests. Tests on main must compile and fail assertions; a missing new helper is not RED.

    1. Establish actual-client regression cases first.

      • WindowsNativeDialogs.zig, createDialogWindow/creation portion of textWithDescription: add sheet framework: text prompt footer fits the actual client. Prepare 1- and 4-field prompts, with and without description, using production creation and current requested-height calculation. Assert both buttons' mapped rectangles fit GetClientRect, do not intersect any field/description, and fit at 96/144/192 logical DPI. Expected main RED: one-field description prompt's Cancel/OK bottom extends beyond the actual client because its y derives from outer height; the beta26 tg750-rename, tg750-new-workspace, tg734-template-dialog images show this defect.
      • NativeForms.zig, production hidden creation seam for show: add sheet framework: short promotion uses content height not the maximum window. Assert Goal promotion's actual client height is its content + footer (bounded only by work area), rather than a fixed full-height frame. Expected main RED: show selects 760 independent of this content.
      • NativeForms.zig, contentHeight/policy controls: add sheet framework: project policy extent includes its final body line. Configure actual policy controls; assert the extent covers the final body static at y=276..308 plus trailing inset. Expected main RED: 92 < 308.
      • WindowsNativeDialogs.zig and NativeForms.zig: add sheet framework: static labels paint an opaque panel background, dispatching the actual WM_CTLCOLORSTATIC to a memory DC and inspecting the returned LOGBRUSH/background mode/color. Expected main RED: generic prompts use default light handling; NativeForms returns BS_HOLLOW/transparent instead of solid/opaque. Capture the behavioral assertion, not just a source regex.
    2. Add one small, shared geometry model in Forms.zig.

      • Reuse the stopped branch's idea of SheetRect/SheetGeometry (client content/footer rectangles and bounded offset), not its entire diff. Consolidate the existing NativeForms.LayoutRect arithmetic instead of keeping two subtly different clamp implementations.
      • Inputs: actual client size, footer size, measured content extent. Invariants: content.bottom == footer.top, nonnegative sizes, max scroll = max(0, extent - viewport), and offset always in that range. No fabricated minimum viewport larger than the client.
      • Add sheet framework: client geometry partitions content and footer at all DPI steps in Forms.zig, asserting exact 96/144/192-DPI boundaries for short, overflowing, and smaller-than-footer clients, and first/last/clamped offsets. This new pure model test is not itself original-product RED; steps 1 and 3 must prove production adoption.
    3. Wire shared client/frame measurement and content viewport in WindowsNativeDialogs.zig.

      • textWithDescription, createDialogWindow, windowProc, createDescription, createField, repositionFields: measure description text using its real available width and DPI font (DrawTextW with DT_CALCRECT), include labels/inputs/insets/footer, convert the desired client rectangle with AdjustWindowRectExForDpi, then clamp the outer rectangle to the selected monitor work area. Recompute available client space after that clamp. Center over owner when possible, clamped to work area; handle absent owner explicitly.
      • Keep an intentional maximum client height; only overflow beyond that/work-area cap scrolls. Put scrolling content in a WS_EX_CONTROLPARENT child viewport and buttons outside it. Remove top-level WS_VSCROLL. The viewport's scrollbar range/page/position must come from the shared geometry. Reserve scrollbar width before measuring wrapped content, or perform a bounded relayout once overflow is known.
      • Expose only the helpers NativeForms needs: client-to-window fit, viewport creation/layout, text measurement, solid sheet static/edit/button coloring. The retained sheetWindowRect, createSheetContent, layoutSheetContent, textHeight and color helpers are useful prior art; do not copy unrelated abandoned tests/presentation changes.
      • Forward viewport WM_COMMAND, WM_DRAWITEM, color, wheel and scrollbar messages to the owning host. Preserve DM_GETDEFID, Cancel-as-default-when-focused, first-edit selection, IsDialogMessage navigation, owned result buffers and surfaced error paths. Treat failed class/viewport/frame creation as errors with normal modal cleanup, not success-shaped fallbacks.
      • Add sheet framework: prompt overflow scrolls above a fixed footer: 16 fields, long wrapped description, short work area; assert last edit becomes fully reachable at maximum scroll, scrollbar bounds end at content.bottom, footer never moves, short prompts have no visible scrollbar. Expected main RED: hard-coded 510/535 scroll rules and whole-window scrollbar do not satisfy the actual-client contract.
    4. Adopt the same geometry in NativeForms.zig, including the policy special case.

      • DialogState, show, WM_CREATE, WM_SIZE, layoutForm, formContentWidth, formViewportHeight, contentHeight, updateScrollBar, scrollFields, setScrollOffset, ensureControlVisible: initialize/configure visible content before selecting height. Preserve New Node's deliberate minimum if space allows; other short kinds shrink to content, tall kinds cap to measured work area. Create fields/tiles/intro/recap/attachments inside the viewport, and validation/actions on the host.
      • Add a dedicated layoutPolicy path: retain every body static/radio/edit HWND with its baseline position, apply scroll to all of them, and use the same policy content extent for initial sizing, scrollbar, wheel/thumb clamping and focus reveal. Threshold edits are not generic rows: reveal their actual control rectangles. Done remains dismiss-only; valid edits persist immediately and partial numeric edits do not overwrite persisted values.
      • layoutFooter: measure each existing action label, including Remove Selected/Show in Explorer/Templates, instead of assuming 96 pixels. Allocate validation only in the remaining region; no overlap with auxiliary actions. If a genuinely narrow work area cannot hold one row, derive the additional footer row height before choosing the viewport; do not place controls outside the client or silently shrink text beneath its measured width. Keep current action order/styling in this slice.
      • After moving controls, invalidate/erase/redraw the content viewport and children. Solid opaque label/background brushes must ship in this same change, since the new WS_CLIPCHILDREN hierarchy otherwise recreates white strips/footer bands.
      • Add sheet framework: all declared form variants keep reachable content above the footer in NativeForms.zig. Named cases: node turnBased/timeBased/goalBased/proactive; edge locked and unlocked endpoints with none/template/script transforms and spawn; update; promotion Goal/Turn/Timed preset/Timed custom; advanced settings; legacy jump; template picker; policy; sweep empty/one/256 rows. Include node attachments visible/hidden and 0/8 entries. For each case and DPI 96/144/192, check actual hidden HWND client/viewport/footer rectangles, named action text bounds, top/bottom scroll, and focus-reveal routing via notifications (no foreground activation). Existing Kind has nine values (NativeForms.zig:81); cover them rather than claiming the prior seven-case guard is comprehensive.
      • Specifically assert policy can reach both thresholds under overflow and resizing after a prior nonzero scroll clamps/repositions without stale coordinates. Expected main RED: policy extent/reveal is wrong, short forms use full-height sizing, and the scrollbar belongs to the host. Cases that already pass are regression coverage, not separate claimed REDs.
    5. DPI/repaint regression and documentation.

      • Handle/reuse DPI font application and WM_DPICHANGED in the two host procedures; recompute measured text, outer fit, footer, range and offsets together. Do not multiply already-scaled values again. Reuse Dpi.zig, AppFont.getForDpi, and opaque-handle conversion conventions.
      • Add sheet framework: relayout repaints vacated content without changing footer geometry. Exercise node type changes, scrolling down/up, and resize/DPI recalculation; inspect invalidation coverage and render native controls/background into an owned DIB with WM_PRINT/WM_PRINTCLIENT. Assert static blank margins/footer pixels are the panel color. Do not show an off-screen window: that is still desktop use. If a hidden print path cannot establish stale composed pixels, record that limitation and use the final leased screenshots to prove the rendered result; don't call a synthetic blank bitmap “rendering evidence.”
      • The abandoned branch proves the stale-pixel hazard with WS_CLIPCHILDREN, not that this new regression necessarily fails on today's unconverted main. Retain an observed RED for actual defects above and label this case a migration/regression guard if main already passes.
      • Update the relevant Windows README native-form paragraph to describe content-capped scrolling and its actual coverage/limits. No ledger promotion.

    File scope for coordinator approval

    File First PR Lease
    graphcode-windows/src/Forms.zig Pure shared geometry + its tests A, allowed
    graphcode-windows/src/WindowsNativeDialogs.zig Text prompt sizing/viewport/opaque painting + shared native helpers and focused hidden tests A, allowed
    graphcode-windows/src/NativeForms.zig Shared sizing/viewport adoption, policy layout/reveal, footer fitting, DPI/repaint + tests A, allowed
    graphcode-windows/README.md One directly related description of the bounded-dialog behavior and evidence limits Outside supplied lease: approval requested with this plan
    graphcode-windows/src/WindowsProductSettings.zig No changes in this first slice; independent Settings redesign/830-unit layout belongs to later work A, deliberately excluded

    Existing test roots are registered in Tools/windows/Tests/WindowsShell.Tests.ps1:753,1198; Forms is also an existing test root. No new root registration, gate edits, workflow edits, tokens, App.zig, GraphContextMenu.zig, C++ provider or macOS/shared Swift changes are planned. If new native GDI calls expose a missing link flag in the NativeForms runner, ask for approval for only that invocation at line 753 (add -lgdi32); don't edit the harness speculatively. Its current invocation has -luser32 while the WindowsNativeDialogs invocation already has -lgdi32.

    Later scope, not pre-authorized by this plan: box 5 requires App.zig:editSelectedNode/deleteSelectedNode; universal geometry/visual claims require audit/adoption in UpdateOfferDialog.zig:show (83-108), UpdateInstallDialog.zig:run (window creation at 246), Product Settings, and other standalone modal classes. Owner dimming/rounding and a common visual footer/field renderer are separate reviewed slices. Main-window lanes C/D own neighboring App.zig code; the coordinator must lease those exact functions before any later edits.

    Validation/evidence plan

    Environment for implementer: worker-owned C:\gcs\pa, C:\gct\pa, C:\gcp\pa; real short validation root C:\gcpa (7 characters). If the implementer has a different assigned id, use its roots, not this planner's. Seed pinned caches/providers and run the canonical bootstrap with those roots, load its generated environment in every shell, redirect TEMP/TMP/support/profile process-only. Use pinned Zig 0.15.2; no PATH toolchain or existing session build outputs.

    Focused commands, from graphcode-windows, after loading that environment:

    & $env:GRAPHCODE_ZIG0152 test src\Forms.zig --test-filter "sheet framework:" --cache-dir C:\gcs\pa\forms-cache --global-cache-dir C:\gcs\pa\zig-global
    & $env:GRAPHCODE_ZIG0152 test src\WindowsNativeDialogs.zig -target x86_64-windows-msvc -lc -luser32 -lgdi32 -ladvapi32 "-I$env:GRAPHCODE_WINGHOSTTY_ROOT\include" --test-filter "sheet framework:" --cache-dir C:\gcs\pa\dialogs-cache --global-cache-dir C:\gcs\pa\zig-global
    & $env:GRAPHCODE_ZIG0152 test src\NativeForms.zig -target x86_64-windows-msvc -lc -luser32 -lgdi32 -ladvapi32 "-I$env:GRAPHCODE_WINGHOSTTY_ROOT\include" --test-filter "sheet framework:" --cache-dir C:\gcs\pa\native-cache --global-cache-dir C:\gcs\pa\zig-global

    Keep separate timestamped RED/GREEN logs and assert a positive executed test count for each command, including the new native tests; report the actual All N tests passed, not the number of table subcases. Full legacy WindowsNativeDialogs tests can activate/focus windows, so do not run the entire root locally outside a lease. Full regression is exact-head hosted CI (unit shards, integration and packaging plus every other workflow); cite nonzero run/job counts and exact head. Run -Task visual-baseline if changing palette/font contracts; Pester ValidationRunner only if approved harness edits actually occur. Code/evidence review precedes screenshots.

    Final screenshot slot (one lease, <=15 minutes, 100% Windows; hidden tests cover the arithmetic at 150/200, not rendered DPI/hardware parity):

    Surface/state and fixture Windows before/after macOS reference to pair
    Rename existing loop RefTurn, initial title selected; long description/window footer visible Fresh baseline main and final head, full owner plus dialog; measure Cancel/OK containment and absence of bands 750/750-rename-prompt@1x-srgb.png (opened in planning)
    Short Goal promotion, blank and invalid, then a nonempty value without submitting Baseline and final head, same RefSketchA, short content and footer visible 750/750-promote-to-goal-form@1x-srgb.png (opened)
    New Goal form top and bottom, long enough to overflow; switch Goal -> Turn -> Goal and scroll down/up Baseline/final at same owner size, fixed footer in every image; visible fields after scroll and cleared label background 750/750-new-loop-sheet-type-Goal@1x-srgb.png (opened); bottom not present in Run A, so obtain matched macOS bottom capture before claiming complete visual equivalence
    Compact/nonoverflowing composite form, no automatic scrollbar Baseline/final same available owner/work area, compare no-scroll behavior rather than matching missing composite fields 750/750-new-loop-sheet-type-Composite@1x-srgb.png (opened). Do not claim #769 content parity.
    New Workspace and Save as Template prompt Baseline/final footer fully visible; empty and prefilled initial field as applicable No matching Run A capture for New Workspace; no TemplateSave capture. Existing Windows beta26 tg750-new-workspace and tg734-template-dialog were opened and confirm clipping, but are not substitutes for new main-before or macOS pairs. Request missing macOS captures; leave those visual-parity claims unverified meanwhile.
    Neighboring Project Settings overflow, Worktrees populated footer, Edge/Edit Details geometry Prefer hidden geometry evidence plus a compact neighboring-surface contact sheet within the same lease; policy values 2 GiB / 8, sweep safe/look/in-use fixture and enough rows to overflow; cancel all mutations Worktrees: 750/750-worktrees-sheet@1x-srgb.png; Project Settings and edge sheet need new macOS captures (Run A README says absent/unrecorded; the edge “wire-it-up” image is not a sheet). Edit Details is absent on macOS, so Windows regression only. Do not claim paired visual verification for missing references.

    Use fixture-only graph/project/worktree data, with support-scoped onboarding-seen, no real agent turns, destructive submission or install. Capture main-before and final-head-after in the same lease using PrintWindow(hwnd,hdc,2) and pixel checks; use ownership-checked screen capture only for omitted owned popups. Do not use ActivateWindow's Alt tap (#797). Preserve all failed attempts. Exit File > Exit, stop only owned PIDs (including zmx daemons), verify none remain, release lease. Image reviewer opens every cited image; missing pairs leave visual boxes open.

    Risks and stopping conditions

    • Scope/size: the abandoned branch was too broad to take wholesale. First PR is geometry/painting only, not an in-window overlay, form-content redesign, button palette or settings rewrite. If implementation cannot preserve that boundary, ask the coordinator rather than expanding it.
    • Shared routing: reparenting controls changes notification delivery and dialog-manager traversal. Forward command/color/draw/scroll messages and preserve control IDs/default action; existing exact-head CI must exercise actual modal commands. Changing tab order, attachment pickers, template handoff, policy persistence or sweep confirmation is a regression, not intended scope.
    • Policy: field_count=0 means generic field iteration misses every policy control. One shared content height is insufficient unless all static/radio/edit HWNDs also move and focus reveal uses their real rectangles.
    • DPI/theme: text measurement, scrollbar width, non-client frame and font updates must use the same DPI and actual client width. Test each supported logical DPI; no mixed-monitor hardware claim. Opaque panel brushing must accompany WS_CLIPCHILDREN; no hollow brush in the new hierarchy.
    • Concurrent changes: open-PR inventory at planning time showed Bound UIA Worktrees gate traversal #587 touching Tools/windows/uia-live-gate.ps1 and Tools/windows/Tests/WindowsShell.Tests.ps1; Show loop-to-loop discussion on the board (#273) #274/Rename a loop when its session is renamed (#261) #263/An earned, one-time in-app ask to star the repository #207 affect unrelated macOS/shared surfaces. Other Wave 2 lanes may create PRs after this snapshot. No first-slice App.zig or DesignTokens edits; rebase and inspect every hunk to preserve merged Windows: make the right loop panel readable and match its macOS hierarchy #789 panel geometry.
    • Harness/environment: hidden tests must never call presentDialog, ShowWindow on a top-level host, SetForegroundWindow, or real SetFocus. An off-screen shown window is not “hidden.” Treat long-path/profile/provider/bootstrap faults as harness failures, retain logs, and don't weaken preflight or borrow another session's caches/builds. Follow canonical five-failed-iterations escalation.

    Planning evidence limits: source/capture inspection only; the expected REDs above are predictions grounded in the named production code and viewed beta26 captures, not invented test runs. No runtime, CI, bootstrap, glyph, physical-keyboard, accessibility, hardware, persistence, or completed visual-parity result is asserted. Approval requested for this precise first slice and the one README file.

  6. coneilen commented on Oct 14, 2026

    @coneilen
    CollaboratorAuthor

    Plan approved (coordinator)

    Approved plan: #768 (comment), with a smaller first slice: fix content/client-frame sizing, opaque paint coverage and fixed-footer overflow for GraphCodeWindowsDialog text prompts only. The proposed simultaneous migration of every NativeForms kind is too large for one first PR. No issue-wide checkbox is completed by this slice.

    Approved files: graphcode-windows/src/WindowsNativeDialogs.zig, and one directly related paragraph in graphcode-windows/README.md (explicit out-of-lease approval). No Forms.zig, NativeForms.zig, WindowsProductSettings.zig, App.zig, GraphContextMenu.zig, shared Swift, gate, workflow or test-runner edits in this PR. Keep any small geometry helpers local to the prompt class; shared extraction can follow when the second consumer is migrated.

    Source checks: AppView.swift:211-231 confirms the single-title Rename alert, selected existing value/Return path and macOS copy. NodeDraftForm.swift:48-69 confirms a scrolling body above a fixed footer and an intentional 560/760 minimum/ideal for New Node; it does not authorize shrinking every sheet. SketchPromotionForm.swift:21-32 is intrinsically content-sized. Those latter classes are deferred here. I opened the Run A rename, quick-chat, minimum-width and card reference images myself; Rename is a centered dark alert over a dimmed owner, but this geometry slice does not claim rounded in-window/scrim or wording parity.

    Required behavioral RED: exercise the existing production creation path without presenting a top-level window. At main, textWithDescription uses outer height 150 + count*52 and button_y = outerHeight-55, while WM_CREATE places 28-high buttons without accounting for the non-client frame; the actual-client containment assertion must fail. Use both a description prompt and a no-description prompt, and retain the failing output. New missing helpers/compile failures do not establish RED. Tests must compile against baseline behavior or a behavior-preserving creation seam.

    Implement the approved prompt subset of steps 1 and 3: measure wrapped description/labels with the actual DPI/font and width, derive desired client height, account for the non-client frame and work-area cap, keep the existing actions outside a real bounded scrolling content viewport, and use one extent/page/clamp for layout, scroll and focus reveal. Preserve owned values, Unicode, initial selection, default action, Cancel/Enter/Escape, notification routing and modal error cleanup. Opaque brushing and redraw must accompany reparenting. Do not borrow presentDialog/openProbeDialog tests that show or focus windows for local hidden tests. Cover 1/4/16 fields, long text, overflow/no-overflow, bottom-field reachability, footer stability and 96/144/192-DPI geometry. Only failed baseline cases count as RED; first-pass cases are regression coverage.

    Before screenshots, obtain cross-vendor code acceptance and green exact-head CI. One <=15 minute lease captures main-before/final-head-after Rename and neighboring New Workspace/Save as Template, with PrintWindow/pixel checks. Missing macOS pairs for the latter prompts remain explicitly Not verified. Existing labels and visual-frame differences remain open; use Refs #768 and leave all six issue boxes unticked.

    NativeForms policy extent, viewport/repaint, all-variant enumeration and footer fitting remain documented follow-up work, not silently dropped or pre-approved edits. Implementer id ia uses C:\gcs\ia, C:\gct\ia, C:\gcp\ia and real C:\gcia; never the planner's roots.

    Implementation model (user-directed policy, 2026-10-14): gpt-6.1-sol, high, long_context. Although narrowed to one window class, this introduces a shared text-prompt content viewport and non-client/DPI sizing mechanism used by Rename, New Workspace and Save as Template, with coupled scrolling, focus/default-action and modal ownership contracts. This is a new shared mechanism, so it meets the highly-complex exception. The already-started ia session uses this model. Reviewer remains claude-sonnet-5.5, high.

    Approved narrow harness extension (ia request): Tools/windows/uia-live-gate.ps1 GraphCodeUiaGateState ControlById and SetEditTextById/EditTextById lookups, plus only the lookup portion of TypeEditTextById if required by the real prompt input path; Tools/windows/Tests/ValidationRunner.Tests.ps1 corresponding executable positive/negative functional cases. Verified the pushed prompt EDIT now belongs to the direct GraphCodeWindowsDialogContent viewport and the root GetDlgItem probe returns zero while viewport lookup returns the actual edit. Preserve direct-child lookup first; allow a bounded fallback only for the real GraphCodeWindowsDialog root and exact named direct viewport, never a recursive search or arbitrary same-ID descendant. Preserve WM_SETTEXT/WM_GETTEXT, injected-input accounting, focus, Rename outcome/wire/cancel assertions and all nonprompt behavior. Require tests for direct precedence, valid named viewport, missing ID, wrong root/container and unrelated/deeper same-ID children; run ValidationRunner.Tests.ps1 locally with positive execution evidence. Hidden probe is native lookup evidence, not a CI/live-rendering pass. C/E hold disjoint oracle/test hunks in these files; do not overwrite them. No local full integration/desktop lease is granted, and fresh exact-head CI is still mandatory.

    Additional coupled prompt-hit scope (source reviewer): within the already approved uia-live-gate.ps1/ValidationRunner.Tests.ps1 extension, approve GraphCodeMultiProjectRenameNative.ChildAt and its Hit adapter to descend exactly once only from root class GraphCodeWindowsDialog through immediate child class GraphCodeWindowsDialogContent, mapping the original screen point into that viewport before resolving one direct child. Preserve all outer root/PID/foreground/visibility/enabled/control-ID/stability guards and unchanged behavior elsewhere; no recursion or viewport-background-to-edit fallback. Hidden native tests cover nested edit, background, wrong root/container and no deeper fallback; outer Hit/FocusMouse guard tests can use the existing injected seams, never showing a local root to make WindowFromPoint pass. Audit GraphCodeUiaGateState ResolveChild/ResolvesToControl/ClickScreenPoint prompt callers for the same assumption; reuse only this identical bounded prompt-only resolution if required by actual prompt paths. No activation, injection/fallback or unrelated-form redesign. Reviewer handoff must enumerate remaining direct-child assumptions; full gate acceptance and fresh exact-head CI remain pending. 34b history/failures retained; no screenshot lease.

  7. coneilen commented on Oct 14, 2026

    @coneilen
    CollaboratorAuthor

    Stable acceptance claim IDs (wave-2 verification exception)

    These IDs belong to this issue and reference its existing acceptance boxes without redefining them. Implementers must not change their meaning or proof class. This is the verification-time exception for already-approved wave-2 work; it does not impose a new verifier, scenario or desktop slot retroactively.

    Claim ID Allowed proof class Existing acceptance box Current whole-claim status
    768-C1 visual 1: dark, rounded, centred, dimmed presentation and title/label bands Open
    768-C2 mixed 2: content/non-client sizing and containment at the named DPI levels Open; #808 supplies scoped text-prompt evidence only
    768-C3 mixed 3: overflow-only scrolling above a fixed footer Open; #808 supplies scoped text-prompt evidence only
    768-C4 mixed 4: footer placement, reason, styling, hint and enablement Open
    768-C5 mixed 5: Rename/Delete copy and actions Open
    768-C6 mixed 6: filled/rounded fields, focus ring and initial selection Open

    No whole claim is verified or closed by #808. Its accepted evidence covers the existing GraphCodeWindowsDialog subset at 96 DPI plus explicitly limited native/geometry coverage; NativeForms, full styling/copy, physical input and the unpaired/missing visual states remain deferred. The original six checkboxes stay unchanged and unticked.

  8. coneilen commented on Oct 14, 2026

    @coneilen
    CollaboratorAuthor

    Merged #808 as 9e6d13c after exact-head27 completed checks (23 SUCCESS/4 path-gated SKIPPED), accepted source/CI/log and different-vendor image review, and independently verified desktop cleanup. Coordinator opened all26 Windows images and the macOS Rename reference. The scoped footer/paint result is visible, but no entire acceptance claim is met; all six boxes stay open. Stable claim register: #768 (comment). New Workspace/Template lack macOS pairs; live overflow, rendered150/200 percent DPI, physical input, real agent/daemon persistence and universal sheet parity remain unverified. Retained failures/provenance limits are in the PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1 layoutParity priority 1: layout, clipping, overlap, broken rendering vs macOSenhancementNew feature or requestparityWindows/macOS UI parity ledger row (investigation/ui-parity-matrix.md)visual parityVisual fidelity against the macOS reference captureswindowsWindows port

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions