Skip to content

harness: Busy ■ Stop stays on-canvas at ~390px via full button-footprint reserve (plan #782, issue #779) - #784

Merged
btipling merged 3 commits into
mainfrom
plan/stop-on-canvas
Aug 22, 2026
Merged

harness: Busy ■ Stop stays on-canvas at ~390px via full button-footprint reserve (plan #782, issue #779)#784
btipling merged 3 commits into
mainfrom
plan/stop-on-canvas

Conversation

@btipling

Copy link
Copy Markdown
Owner

Closes #779 (via plan #782). Human cap-approval recorded 2026-08-22.

What

While a turn is Busy the composer's trailing icon pack is ▶ enqueue + ■ Stop. On a ~390px phone-width canvas the ■ was crushed flush into the right edge (tag rect slid past win.w) — un-hittable, so the operator can't tap-cancel the in-flight turn on the width they actually use.

Root cause (rect-proven, not assumed): the trailing-icon reserve counted only TOUCH_H (40) per button, but each ButtonWidget's real tag-rect footprint includes dvui's default padding (6) + margin (4) per side → TOUCH_H + 2·10 = 60. Reserve under-counted by 20px/button, so the two Busy buttons overran the row and dvui's horizontal compactor crushed the rightmost ■ off-canvas.

Fix: reserve the FULL button footprint — ICON_PAD(6) / ICON_MARGIN(4) / ICON_EDGE_W(10), iconCellW() = TOUCH_H + 2·ICON_EDGE_W = 60, fieldW = avail_w − (n·iconCellW + 8) — and pin every trailing ▶/■ button's padding/margin to those same constants so arithmetic and widget options can never drift.

Cap raise (human-approved)

The trailing-icon reserve raises TOUCH_H×n + 8 (88 busy / 48 idle) → iconCellW×n + 8 (128 busy / 68 idle), +20px/icon, narrowing the message field at all widths (idle 552→532, busy 512→472 @ 600px). Approved by operator 2026-08-22. TOUCH_H/SUBMIT_CAP/MAX_ITEMS are NOT raised.

Tests

  • composer_layout 11 pass — new ~390px locks: busy empty-queue, idle narrow, busy unbreakable-line — asserting ■/▶ full tag rects stay on-canvas with real slack (never flush) and field stays left of icons.

Gates (all green locally)

zig fmt --check · zig build test-rich (exit 0) · zig build test-rich-invariants · zig build harness -Doptimize=Debug.

Ops

Cloud ops N/A — no Production mutate. Docs: docs/harness-limits.md updated in the same PR.

…int reserve (plan #782, issue #779)

Root cause (rect-proven): the trailing-icon reserve counted only TOUCH_H
(40) per button, but each ButtonWidget's real tag-rect footprint includes
dvui default padding (6) + margin (4) per side = TOUCH_H + 2*10 = 60.
The reserve under-counted by 20px/button so the two Busy buttons overran
the row and dvui's compactor crushed the trailing ■ flush into the right
edge at ~390px (Stop un-hittable).

Fix: define ICON_PAD(6)/ICON_MARGIN(4)/ICON_EDGE_W(10); iconCellW() =
TOUCH_H + 2*ICON_EDGE_W = 60; iconPackW/iconReserveW/fieldW rebuilt on
iconCellW(); pin every trailing ▶/■ button's padding/margin to those same
constants so the arithmetic and the widget options can never drift.

Tests: parameterize the layout helper to arbitrary width and add ~390px
locks — busy empty-queue, idle narrow, busy unbreakable-line — asserting
■/▶ full tag rects stay on-canvas with real slack (never flush) and the
field stays left of the icons. 600px rows: composer_layout now 11 pass.

Docs: harness-limits.md Layout/Wrap-grow/Icon-button rows + iconCellW
inlined (cap raise approved by operator 2026-08-22).

Cloud ops: N/A (no Production mutate).
@btipling btipling added ui harness Harness / agent UI labels Aug 22, 2026
@vercel

vercel Bot commented Aug 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
invincible Ignored Ignored Aug 22, 2026 8:09pm

Request Review

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #784

Verdict: PASS WITH NOTES
Repo: btipling/invincible
Scope: mainplan/stop-on-canvas · 3 files · Busy ■ Stop on-canvas at ~390px (full button-footprint reserve)
Lenses run: L1, L3, L6, L8, L9 (skip: L2 no trust-boundary/API/secret files; L4 no GHA/artifact path change — zig → harness.wasm already green on the PR; L5 no poll/history/body-size; L7 no host pin; L6 DI/cost N/A — existing dvui_testing layout backend, not PGlite)
AGENTS.md read: yes (docs/feature-divide.md — Stop stays Wasm; no dual-chat)

Findings

Sev Lens Finding Break scenario Refutation attempt Confidence
Minor L6 Plan #782 tests 2 and 3 (Busy ~390 with queue Pause/Clear header; paused + · full) are not implemented. composer_layout.test.zig only paints paintComposerChrome at 390 (empty-queue, idle, unbreakable-line). docs/harness-limits.md Layout / Icon-button rows claim ▶/■ stay on-canvas “including with the queue-band Pause/Clear header visible.” A later queue-band header min-width growth is what tests 2/3 were written to catch. This PR’s 390 locks would stay green while the docs sentence is false. Defender: queue band is a separate vertical band at the same avail.w (ui.zig); max_size_content.w = max_float_safe; host sizes the canvas, dvui min-size cannot widen it. Production leak path is bounded. Still an untested DoD row plus a living-doc overclaim. high
Minor L8 Living docs and new comments cite “plan #779. Source bug is #779; the plan is #782. docs/harness-limits.md (Layout / Composer / wrap-grow / Icon-button) plus composer_chrome.zig / composer_layout.test.zig. Plan living-docs rule was timeless / no process artifacts. Next reader looks up issue #779 expecting the plan body (caps, test table) and finds the bug ticket instead. Defender: operators say “#779” for the crush. The plan-issue number is still wrong in a file whose job is to be the timeless cap source. high
Nit L8 composer_layout.test.zig module comment still documents field_w = avail_w − (TOUCH_H×n + 8) — the pre-fix formula. composer_chrome.zig still says icons “land post-reserve at TOUCH_H.” Arithmetic is iconCellW() (60). An agent “aligns” fieldW back to the test header and re-ships the #779 crush. Tests below the header call iconReserveW()/iconCellW(), so CI would catch a silent revert of the functions — unless someone “fixes” the tests to match the stale comment. high
Nit L6 assertBusyOnCanvasW accepts stop.w >= 0.8 * iconCellW (48 logical vs 60). The original crush was ~28 logical, so this still fails the reported bug, but it allows a 20% shrink before CI notices. A future pad/margin drift that cuts the cell to 50px stays green. 0.8 is a subpixel/font fudge; gap >= 2*EPS is the real “not flush” lock. Soft, not a current miss. medium

Residual risk

Did not execute zig build test-rich here (no Zig 0.16 on PATH). GHA zig → harness.wasm is green. ButtonWidget defaults on pin 4f810ef match ICON_PAD=6 / ICON_MARGIN=4; borderGet() is empty unless set, so tag-rect width = TOUCH_H + 2·10 is the right cell. Vertical pad+margin (button ~60 tall in a 44px idle chrome, gravity_y = 1.0) is pre-existing default chrome, not introduced. Operator tap-cancel on a real ~390 device was not driven. ui.zig:710 and native/harness/build.zig still describe TOUCH_H×n + 8 (out of diff).

Merge guidance

  • PASS WITH NOTES: safe to merge from this attack. Fix the #782 vs #779 citations and the stale TOUCH_H×n+8 / “lands at TOUCH_H” comments in the same file set when cheap; tests 2/3 are optional given band isolation. Do not treat the Goal 1 ~390 busy lock as missing — it is there and would fail the original crush.

What was not attacked

Live phone /harness tap on ■, zig build test-rich / test-rich-invariants in this session, queue_band layout at 390, dvui versions other than the harness pin, host chrome padding that could make the canvas slightly narrower than 390.

… formulas and tighten the ~390px cell lock

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #784 (round 2)

Verdict: PASS WITH NOTES
Repo: btipling/invincible
Scope: mainplan/stop-on-canvas · 3 files · 2 commits (1e122ef + a16cd2f feedback follow-up)
Lenses run: L1, L3, L6, L8, L9 (skip: L2 no trust-boundary/API/secret files; L4 no GHA/artifact path change — zig → harness.wasm green on HEAD; L5 no poll/history/body-size; L7 no host pin; L6 DI/cost N/A — existing dvui_testing layout backend, not PGlite)
AGENTS.md read: yes (docs/feature-divide.md — Stop stays Wasm; no dual-chat)

Round 1 was PASS WITH NOTES (Minor L6: plan tests 2/3 unpainted; Minor L8: docs/comments cited plan #779; Nit L8: stale TOUCH_H×n+8 / “lands at TOUCH_H”; Nit L6: stop.w >= 0.8·cell). a16cd2f addresses the cheap notes. This pass re-attacks HEAD.

Round-1 items

Round-1 Status on a16cd2f
Minor L8 plan #779 vs plan #782 Closed in the three PR files (docs, composer_chrome.zig, composer_layout.test.zig now say #782). Source bug #779 is still named only as the crush, which is correct.
Nit L8 stale field_w = avail_w − (TOUCH_H×n + 8) and “land post-reserve at TOUCH_H Closed in the PR files. Arithmetic comments now use iconCellW().
Nit L6 stop.w >= 0.8·cell Tightened to 0.9·cell (108 physical vs 120). Still catches the ~28-logical crush (~47% cell) without a rounding false-fail.
Minor L6 plan tests 2/3 (Busy ~390 with queue Pause/Clear header; paused + · full) Unchanged. composer_layout.test.zig still only paints paintComposerChrome.

Findings (HEAD)

Sev Lens Finding Break scenario Refutation attempt Confidence
Nit L8 docs/harness-limits.md Layout / Icon-button rows still claim ▶/■ stay on-canvas “including with the queue-band Pause/Clear header visible.” No test mounts queue_band. Living docs also still embed “plan #782” process artifacts (the follow-up corrected the number, did not drop the theater). A later header min-width growth is what tests 2/3 were written to catch; the sentence stays green. Next reader treats plan numbers as the cap source. Defender (same as round 1): queue band is a separate vertical band at avail.w; max_size_content.w = max_float_safe; host sizes the canvas. Production leak path is bounded. Caps themselves (iconCellW = 60, pin ICON_PAD/ICON_MARGIN) are correct. high

No new L1: follow-up is comments + citation + 0.8 → 0.9. iconCellW / fieldW / the three button padding/margin pins are unchanged. Vendored ButtonWidget defaults remain padding=6 / margin=4 / empty borderGet(), so the 60 px cell still matches tag-rect width.

Residual risk

Did not run zig build test-rich here. GHA zig → harness.wasm is green on a16cd2f. Out of diff (not this PR’s files): ui.zig:710 and native/harness/build.zig still describe TOUCH_H×n + 8 — a later agent could “align” those comments backward; the layout tests would still catch a silent fieldW revert. Operator tap-cancel on a real ~390 device was not driven. Vertical pad+margin (button ~60 tall in 44 px idle chrome) remains pre-existing default chrome.

Merge guidance

  • PASS WITH NOTES: safe to merge from this attack. Round-1 Goal 1 ~390 busy lock is intact and tighter. Tests 2/3 remain optional given band isolation; dropping “plan #782” from living docs is cosmetic.
  • Do not treat the missing queue-header paint as a Goal 1 miss — empty-queue + unbreakable-line at 390 still fail the original crush.

What was not attacked

Live phone /harness tap on ■, test-rich / test-rich-invariants in this session, queue_band layout at 390, dvui versions other than the harness pin.

…m + plan-#782 theater from living docs (L8 Nit, round 2)
@btipling

Copy link
Copy Markdown
Owner Author

Round-2 L8 Nit resolved in 59f80ce (docs-only, no code touch):

Docs-only so no Zig/TS gates apply.

@btipling btipling left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial review — PR #784 (round 3)

Verdict: PASS WITH NOTES
Repo: btipling/invincible
Scope: mainplan/stop-on-canvas · 3 files · 3 commits (HEAD 59f80ce — docs-only follow-up)
Lenses run: L1, L3, L6, L8, L9 (skip: L2 no trust-boundary/API/secret files; L4 no GHA/artifact path change — zig → harness.wasm green on HEAD; L5 no poll/history/body-size; L7 no host pin; L6 DI/cost N/A — existing dvui_testing layout backend, not PGlite)
AGENTS.md read: yes (docs/feature-divide.md — Stop stays Wasm; no dual-chat)

Round 1/2 were PASS WITH NOTES. 59f80ce is docs-only. Production iconCellW / fieldW / the three button padding/margin pins are unchanged from a16cd2f.

Round-2 items

Round-2 Status on 59f80ce
Nit L8 docs claimed on-canvas “with the queue-band Pause/Clear header visible”; living docs embedded “plan #782 Closed. Layout / Composer / wrap-grow / Icon-button rows dropped the untested header clause and the plan-number theater. Caps remain inline (iconCellW = TOUCH_H + 2·(pad 6 + margin 4)).
Plan tests 2/3 (queue header / paused+· full) unpainted Unchanged, accepted residual. Composer is a separate vertical band at avail.w; host sizes the canvas. Docs no longer claim that lock.

Findings (HEAD)

None that survive refutation. Docs-only delta does not reintroduce the #779 crush, the TOUCH_H-only reserve, or a dual-chat path.

Residual risk

Did not run zig build test-rich here. GHA zig → harness.wasm is green on 59f80ce. Out of this PR’s files: ui.zig:710 and native/harness/build.zig still describe TOUCH_H×n + 8 — a later agent could “align” those comments; the composer_layout ~390 locks would still fail a silent fieldW revert. stop.w >= 0.9·cell still allows a 10% shrink (the gap >= 2*EPS lock is the “not flush” assertion). Operator tap-cancel on a real ~390 device was not driven. Zig comments in composer_chrome.zig still cite plan #782 — fine for implementation notes, not living docs.

Merge guidance

  • PASS WITH NOTES: safe to merge from this attack. Goal 1 ~390 busy lock is intact (assertBusyOnCanvasW + unbreakable-line). Round-2 living-doc overclaim is gone.
  • Do not treat missing queue-band paint as a Goal 1 miss.

What was not attacked

Live phone /harness tap on ■, test-rich / test-rich-invariants in this session, queue_band layout at 390, dvui versions other than the harness pin.

@btipling
btipling merged commit a41b500 into main Aug 22, 2026
3 checks passed
@btipling
btipling deleted the plan/stop-on-canvas branch August 22, 2026 20:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

harness Harness / agent UI ui

Projects

None yet

Development

Successfully merging this pull request may close these issues.

harness: Busy ■ Stop is pushed off the right edge of the canvas

1 participant