A new window opens at half the width of its display#305

opened4d agobySSamanyu Das

Note

🤖 Claude Opus 5.5 responding on behalf of Sam

Problem

Release scope says that new windows start at 50% of display width, and existing windows keep their widths (release scope, Default shortcuts and layout). Miri Developer does not do this: a new resizable window keeps the width it opens with.

Observed on main at 6edff137, engine ee89647, macOS 27.0.1 (26A434), 2560 x 1440 external display as the main display, during the #83 audit:

  • verify-miri run 20261106-090237 opened three AXFixture windows, each with a 380-point content width.
  • The engine tiled each one as a 388-point column, at x = 1015, 1403, and 1791. 50% of the display is 1280 points.

The code agrees with the observation:

  • Miri's config.toml sets no width window rule. Its only [windows] rules are miri-gaps and miri-settings.
  • The engine resizes a new window only when a window rule sets width (WindowProperties::width_ratio in vendor/paneru/src/ecs.rs:1410).
  • Configuration notes that the engine's width rules also apply to existing windows found at startup, so this behavior "requires integration beyond a blanket width rule". No issue tracked that integration until now.

Acceptance ledger check AS-5 covers this behavior.

Proposed behavior

  • A resizable window that opens while Miri runs starts at 50% of its display's width.
  • A window that already exists when the engine starts or restarts keeps its width, including a window that session restore places.
  • Fixed-size windows still float and keep their size.

Requested by

decisions/release-scope.md, accepted on 14 October 2026. Found by the #83 audit.

Release

v1

Acceptance criteria

  • verify-miri: open an AXFixture window with a 380-point width while Miri runs. Its column is 50% of the display width, within 1 point plus the configured padding.
  • verify-miri: open a fixture window 900 points wide, then quit and relaunch Miri. The fixture keeps its width.
  • An engine test in vendor/paneru/src/tests shows that a newly created window gets the 50% width and that windows found at startup or placed by session restore do not.
  • make check passes.

Alternatives considered

  • A blanket [windows] width rule of 0.5 in Miri's configuration. The engine applies it to existing windows found at startup too, which breaks "existing windows retain their widths".

Note

🤖 Claude Opus 5.5 responding on behalf of Sam

Reproduced on current main. The root cause is a missing feature, not a regression. Acceptance criterion 2 needs a change before work starts, so this issue gets needs-info.

Reproduction

  • Build: the main engine pin a20f56e. The tested bundle was built from 471737fb. Between 471737fb and main at ffefedfa, only PROGRESS.md and docs/limitations.md changed.
  • Display 3 is the main display, 2560 x 1440 points, so 50% is 1280 points.
  • verify-miri run 20261106-192150 opened fixture-1 and fixture-2 (380-point content) while Miri ran.
  • Both fixtures tiled as 388-point columns, at x = 1015 and x = 1403. Neither column was 1280 points.
  • The run ended with matched=10, missing=0 at begin and at end, and the layout check passed.

Root cause

  • Miri has no default width for new windows. The engine's only way to set a window's first width is a [windows] rule with width.
  • apply_window_defaults (vendor/paneru/src/ecs/triggers.rs:1383) applies that rule to every window entity that the engine adds. It runs at startup too. The comment at triggers.rs:1430 says "Safe during init". The schedule at vendor/paneru/src/ecs.rs:287 has no Initializing condition.
  • So a blanket width = 0.5 rule would also resize windows that exist at startup. That is why Miri writes no width rule (decisions/configuration.md:54). The engine test test_step_grow_then_shrink_keeps_a_fitting_strip_at_viewport_edges (vendor/paneru/src/tests/tiling.rs:595) shows this. Its two windows exist at startup, and a 0.5 rule makes each one 512 points wide on a 1024-point display.
  • Per-window width rules arrived in paneru dbf6ead. No commit ever gave new windows their own width, so nothing regressed.

Where a fix can hook in

  • The engine already has the facts a fix needs, and apply_window_defaults is the hook. The fix applies 50% only when no rule sets width, and only after the floating check returns.
  • LaunchWindows (vendor/paneru/src/ecs.rs:546) records every window that existed when the engine started, even one that a slow scan finds late. An engine restart is a new process, so it records them again.
  • The Initializing resource (vendor/paneru/src/ecs.rs:960) exists until finish_setup removes it (vendor/paneru/src/ecs/systems.rs:407).
  • Session restore keeps matching windows for a startup grace period (restore_startup_grace, 2 s by default, vendor/paneru/src/ecs/restore.rs:453). A window that appears after startup but inside that grace period is not in LaunchWindows, and restore can still place it. matches_startup_restore_state (vendor/paneru/src/ecs/restore.rs:394) tells whether restore will place a window. The engine test at vendor/paneru/src/tests/session_restore.rs:857 covers such a late window.
  • So a new window gets 50% only when all three hold: its id is not in LaunchWindows, Initializing is absent, and restore does not match it. Without the third condition, a late restored window would first get 50% and then its saved width. I read this in the code and did not observe it live.
  • The engine computes the ratio from the active display (active_display.bounds(), vendor/paneru/src/ecs/triggers.rs:1424), not from the display that holds the window. The issue says "its display". The two differ only when a new window opens on a display that is not active.
  • Fixed-size windows float, and apply_window_defaults returns for them before any width code (triggers.rs:1405-1418), so a hook placed after that check cannot resize them.

Acceptance criteria gaps

  1. Criterion 2 ("open a fixture window 900 points wide, then quit and relaunch Miri") cannot run as written, and passing it would not prove the behavior.
    • verify-miri fixture has no width option. AXFixture always opens 380 points wide (Sources/AXFixture/main.swift:40).
    • With the new behavior, a fixture opened while Miri runs gets 1280 points, not 900.
    • After a quit and relaunch, session restore sets the saved width. So the check passes through restore even if the startup path resizes found windows.
  2. Proposed replacement for criterion 2, after AXFixture and verify-miri fixture get a --width option:
    • verify-miri: with Miri quit, open a 900-point fixture, then launch Miri. The fixture, which is not in the saved session, keeps a 900-point width. This checks the startup path.
    • verify-miri: with that fixture still open and now saved in the session, quit and relaunch Miri. The fixture keeps its 900-point width. This checks the restore path.
    • Engine test: a window that appears inside the restore grace period and matches the saved session gets its saved width and never gets 50%.

Criteria 1, 3, and 4 can be checked as written.

Note

🤖 T3 Tots responding on behalf of Sam

Scope decision (v1 readiness audit, 6 Nov 2026): v1 blocker. Labelled. The criterion-2 answer and which display 50% refers to are still open.