Summary
#730 merged without a re-review after the last BLOCK, then was reverted on main (d876e8d). The data-loss hole is not on main. The catch-22 from #728 is. Do not re-land plan #729 as written.
Timeline
| SHA |
What |
f490094 |
Grant = offset===1 && !byteTruncated. Clipped 1000/1400 authorizes edit. Adversarial review: BLOCK (write_file of the 1000 lines the model saw can drop lines 1001–1400). |
9c766d0 |
Restored (truncated) + use limit>=N hint. Grant still too loose. Re-review: BLOCK (hint is advisory; tests still assert str_replace after a clipped read). |
05ffd57 |
Restored returned >= totalLines. Hint kept. This is the fix for the BLOCK. Never re-reviewed. |
433c5e2 |
Merge PR #730 (accidental, no re-review). |
d876e8d |
Revert of that merge. Current main. |
Current main (d876e8d)
isFullFileReadGrant is the pre-730 gate: offset===1 && !byteTruncated && returned >= totalLines. Clipped windows deny edit. There is no use limit>=N hint.
So:
What to land
Keep the EOF grant. Re-land only the display/hint from 9c766d0/05ffd57:
- Clipped window →
(truncated) — use limit>=N to read all lines and recordRead({ truncated: true }).
- Grant only when
offset===1 && !byteTruncated && returned >= totalLines.
- A follow-up
read_file with limit>=totalLines is the escape hatch (already works).
What not to land
Plan #729 / f490094: “line window is display-only; grant when the daemon returned full bytes.” That is the BLOCK. The model prompt contains formatLineWindow only. write_file of those 1000 lines deletes the unread tail.
Related
- Source catch-22: #728
- Unsafe plan: #729
- Merged then reverted: #730
lib/agent/tools.ts — isFullFileReadGrant, read_file status line
lib/agent/fileFreshness.ts — truncated deny
docs/sandbox.md — Read-before-edit table
Summary
#730 merged without a re-review after the last BLOCK, then was reverted on main (
d876e8d). The data-loss hole is not on main. The catch-22 from #728 is. Do not re-land plan #729 as written.Timeline
f490094offset===1 && !byteTruncated. Clipped 1000/1400 authorizes edit. Adversarial review: BLOCK (write_file of the 1000 lines the model saw can drop lines 1001–1400).9c766d0(truncated)+use limit>=Nhint. Grant still too loose. Re-review: BLOCK (hint is advisory; tests still assertstr_replaceafter a clipped read).05ffd57returned >= totalLines. Hint kept. This is the fix for the BLOCK. Never re-reviewed.433c5e2d876e8dmain.Current
main(d876e8d)isFullFileReadGrantis the pre-730 gate:offset===1 && !byteTruncated && returned >= totalLines. Clipped windows deny edit. There is nouse limit>=Nhint.So:
limit=1000on a longer file denies edit; the tool does not tell the model to passlimit>=totalLines. Explicitlimit: 1400already grants (it was never server-capped). #728 / #729 comments that say “fixed by fix(tools): decouple read-before-edit grant from line-window limit (#729) #730” are stale.What to land
Keep the EOF grant. Re-land only the display/hint from
9c766d0/05ffd57:(truncated) — use limit>=N to read all linesandrecordRead({ truncated: true }).offset===1 && !byteTruncated && returned >= totalLines.read_filewithlimit>=totalLinesis the escape hatch (already works).What not to land
Plan #729 /
f490094: “line window is display-only; grant when the daemon returned full bytes.” That is the BLOCK. The model prompt containsformatLineWindowonly.write_fileof those 1000 lines deletes the unread tail.Related
lib/agent/tools.ts—isFullFileReadGrant,read_filestatus linelib/agent/fileFreshness.ts—truncateddenydocs/sandbox.md— Read-before-edit table