Commit f1183ef
feat(server): Wave 6 -- source/understand pagination hardening (items a-e)
Audit follow-up (2026-08-23), final wave of the 6-wave plan.
- item a: source()'s edit_symbol suggestion no longer says "no preview
needed" when the response was truncated -- the etag/expected_hash is
still valid (always hashes the FULL range), but only part of the body
was actually seen; the reason text now says so and points at
resume_from_line.
- item b: understand()'s embedded source_output now honors max_lines/
resume_from_line via the same paginate_range() source() uses, instead
of always returning the whole symbol body unpaginated.
- item c: max_lines/max_chars <= 0 are now rejected with INVALID_PARAMS
at the tool boundary (source() and, via the same check, understand())
instead of silently falling back to "unlimited".
- item d: new max_chars param (SourceParams + UnderstandParams) hard-caps
rendered text length on top of whatever max_lines already selected --
counts whole lines only, never splits one line's own characters across
pages (apply_char_budget/narrow_by_char_budget, shared by source(),
source_range(), and understand()).
- item e: resuming a paginated source() read with a stale if_none_match
(the range changed since that etag was issued) now returns a new
RANGE_CHANGED_SINCE_PAGINATION error (needs_verification) instead of
silently serving a page sliced against new bytes at old coordinates.
The pre-existing not_modified shortcut is now gated on
resume_from_line being unset, so it no longer swallows a legitimate
page-2+ request that happens to carry a still-valid etag.
10 new/changed tests (5 new: truncated-suggestion wording, max_lines/
max_chars <= 0 rejection, max_chars narrowing, stale-if_none_match
rejection, understand() pagination; plus SourceParams/UnderstandParams
literals updated at every existing call site for the 4 new fields).
1291 calm-core + 465 calm-server tests green, clippy/fmt clean.
Dogfooding note: hit a reproducible false-positive PARSE_ERROR from
edit_lines/edit_symbol specific to re-editing understand()'s tail a
second time this session, on trivially-valid Rust (confirmed via direct
cargo check + isolated sub-edits). Worked around via one native Edit
for that single hunk, with explicit user sign-off; everything else in
this wave went through CALM's own edit tools as usual. Worth a root-cause
pass on CALM's own edit-validation path separately.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>1 parent 5d9b16b commit f1183ef
5 files changed
Lines changed: 619 additions & 8 deletions
File tree
- crates/calm-server/src
- __toolsnaps__
- tools
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
76 | 84 | | |
77 | 85 | | |
78 | 86 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
21 | 45 | | |
22 | 46 | | |
23 | 47 | | |
| |||
0 commit comments