v0.15.2 — fix(agent ask): fence-only capture — the scraping fallback IS the fabrication path (DIVE-1901 iteration 2)
0.15.1 fixed the short-ask case and then failed live on a long one: a 2811-char ask to an antigravity seat returned Gemini 3.6 Flash · high — the TUI footer — at rc=0, while the seat had answered correctly with a well-formed fence sitting in the pane.
- the fallback is not a safety net, it is the fabrication path, so it is now OFF by default. Every bad reply this ticket has caught came from pane scraping and none from the fence: 0.14.7 returned the token plus the footer on antigravity and pure box-drawing on opencode; 0.15.1 returned the footer. A scrape cannot tell "furniture that happened to hold still" from "an answer" — at the instant it looks they are the same thing, text on a screen that is not changing. A fence can: an unclosed fence is unambiguously not finished.
asknow returns the fenced reply or nothing, and nothing becomes a timeout that names what it saw (fence opened but never closed / delivered but never fenced / marker never seen, which is a delivery failure, not a capture one). --allow-unfencedrestores scraping for a seat that cannot follow the instruction, and is REFUSED on a council ask. "Everyone just sets the flag" is how this fix would decay, so the governance path rejects it in validation rather than by convention. A ballot may never fall back to a rail that can return furniture as a vote; such a seat records asabstainKind=capture-failed.- marker lines are matched by SHAPE, not by a glyph list. The first draft used a hardcoded list, and a pane whose bullet was not in it (
◆) fell straight through to the fallback — a per-harness signature smuggled into the one function whose entire purpose was not having one. Caught by its own test. FIVE_ASK_DEBUG_DIRpersists what the extractor actually saw — baseline, accumulated transcript, returned slice — on both the success and timeout paths. The original failure could not be reproduced from a pane dumped minutes later, because an alt-screen TUI redraws in place and the frame was already gone.- CORRECTION to the 0.15.1 notes, which are published and wrong on this point. They state that a full-screen TUI has no scrollback and that
capture-pane -Sis therefore inert. That was measured on claude and codex panes and overstated as a universal:-S -200on a live antigravity pane returns 100 non-blank lines, 50 unique, including real history. Scrollback availability is per-harness. The rail now asks for-S(free where it works) and accumulates frames (needed where it does not). - this release makes the failing case pass; it is NOT a diagnosis of it. The original failure was never reproduced offline — three real renders from the failing seat replay through 0.15.1 correctly, and a sweep of all 201 windows of that scrollback produced zero furniture returns. What carries this fix is a structural argument, not a repro: fabrications came from the fallback, the fallback is off, so that frame is unreturnable whatever it was. A green run here should not be read as the mechanism having been understood.
- tests:
ask_cmd_wiring_unit.sh(4) drivescmd_askitself, both dispatch branches, underset -u— the previous suites tested only the pure helpers, and that gap shipped an unbound-variable crash on the exact branch this iteration exists to fix; reintroducing the defect reproduces the original error at the original line.ask_capture_live_replay.sh(5) replays real pane renders from the failing seat, including the mid-write frame, and states in its header that it does not reproduce the live failure.ask_capture_unit.sh(9) unchanged, now behind--allow-unfenced.