Skip to content

v0.15.2 — fix(agent ask): fence-only capture — the scraping fallback IS the fabrication path (DIVE-1901 iteration 2)

Choose a tag to compare

@lodar lodar released this 25 Jul 07:47
94eac22

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. ask now 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-unfenced restores 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 as abstainKind=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_DIR persists 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 -S is therefore inert. That was measured on claude and codex panes and overstated as a universal: -S -200 on 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) drives cmd_ask itself, both dispatch branches, under set -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.