Skip to content

fix(F3): align compress cut-point to user-message boundary - #78

Merged
yogthos merged 1 commit into
mainfrom
fix/f3-compress-tool-pair-boundary
May 21, 2026
Merged

fix(F3): align compress cut-point to user-message boundary#78
yogthos merged 1 commit into
mainfrom
fix/f3-compress-tool-pair-boundary

Conversation

@yogthos

@yogthos yogthos commented May 21, 2026

Copy link
Copy Markdown
Collaborator

Track F-HIGH #3. Compress's reverse token-budget scan could land cut_idx on a non-User message, breaking provider role sequencing after the System summary is inserted. New align_cut_to_user_boundary helper walks cut_idx forward to the next User. 5 new tests, 656 pass.

Track F-HIGH #3 from ROADMAP.md.

## Problem

`handle_compress` (`ui/slash.rs:115-123`) did a reverse token-budget
scan to pick the cut index, then drained `messages[..cut_idx]`
into the summary. If that scan landed on an Assistant message,
the kept tail started with [Assistant, …]. After compress, the
session became [SystemSummary, Assistant, …] — broken role
sequence. Anthropic and OpenAI reject with HTTP 400.

The reverse-scan was content-only: it accumulated tokens until
the threshold without considering role-boundary constraints.

## Fix

New `align_cut_to_user_boundary(messages, cut_idx) -> usize`
helper. Walks `cut_idx` forward until the message at that index
is a `User` message (or the index reaches end-of-array). Called
right after the existing reverse-scan, before any state
mutation. Matches opencode's `splitTurn` discipline in
`session/compaction.ts:161-184`.

## Tests

5 new tests in `ui::slash::tests`:

- `align_cut_advances_past_assistant_to_next_user`: cut_idx
  landed on Assistant → advance to next User.
- `align_cut_idempotent_when_already_on_user`: User-boundary
  cut unchanged.
- `align_cut_past_end_clamps`: out-of-range index stays in range.
- `align_cut_returns_end_when_no_user_in_tail`: no User after
  cut → return messages.len() (caller surfaces "nothing to
  compress").
- `align_cut_skips_system_to_user`: System messages (prior
  summaries) are also skipped — only User starts a kept tail.

656 pass (was 651). All build profiles clean.
@yogthos
yogthos merged commit f52512a into main May 21, 2026
1 check passed
@yogthos
yogthos deleted the fix/f3-compress-tool-pair-boundary branch May 21, 2026 04:12
yogthos added a commit that referenced this pull request May 21, 2026
All actionable Track F items now landed:

- F-CRITICAL (PRs #76, #77): ACP perm asks routed to Deny, find/glob/list_dir hide dotfiles by default
- F-HIGH (PRs #78#84): compress aligns cut-point, read streams large files, ACP parallel tool ids, bash pgid cleanup, symlink canonicalize, session schema version, quote-aware bash splitter
- F-MEDIUM (PRs #85, #86, #87, #89, #90, #91): interleaved bash output, compress net-savings, Retry-After parsing, plugin docs, relative-path normalize, BOM strip, bounded interject channel
- F-SKIP (F9, F11, F15): verified false positives or N/A; rationale documented inline

Status legend updated; ordering recommendation replaced with the
shipped-status section.

Co-authored-by: Yogthos <yogthos@gmail.com>
allen-munsch pushed a commit to allen-munsch/dirge that referenced this pull request Jun 3, 2026
…e#78)

Track F-HIGH #3 from ROADMAP.md.

## Problem

`handle_compress` (`ui/slash.rs:115-123`) did a reverse token-budget
scan to pick the cut index, then drained `messages[..cut_idx]`
into the summary. If that scan landed on an Assistant message,
the kept tail started with [Assistant, …]. After compress, the
session became [SystemSummary, Assistant, …] — broken role
sequence. Anthropic and OpenAI reject with HTTP 400.

The reverse-scan was content-only: it accumulated tokens until
the threshold without considering role-boundary constraints.

## Fix

New `align_cut_to_user_boundary(messages, cut_idx) -> usize`
helper. Walks `cut_idx` forward until the message at that index
is a `User` message (or the index reaches end-of-array). Called
right after the existing reverse-scan, before any state
mutation. Matches opencode's `splitTurn` discipline in
`session/compaction.ts:161-184`.

## Tests

5 new tests in `ui::slash::tests`:

- `align_cut_advances_past_assistant_to_next_user`: cut_idx
  landed on Assistant → advance to next User.
- `align_cut_idempotent_when_already_on_user`: User-boundary
  cut unchanged.
- `align_cut_past_end_clamps`: out-of-range index stays in range.
- `align_cut_returns_end_when_no_user_in_tail`: no User after
  cut → return messages.len() (caller surfaces "nothing to
  compress").
- `align_cut_skips_system_to_user`: System messages (prior
  summaries) are also skipped — only User starts a kept tail.

656 pass (was 651). All build profiles clean.

Co-authored-by: Yogthos <yogthos@gmail.com>
allen-munsch pushed a commit to allen-munsch/dirge that referenced this pull request Jun 3, 2026
…irge-code#92)

All actionable Track F items now landed:

- F-CRITICAL (PRs dirge-code#76, dirge-code#77): ACP perm asks routed to Deny, find/glob/list_dir hide dotfiles by default
- F-HIGH (PRs dirge-code#78dirge-code#84): compress aligns cut-point, read streams large files, ACP parallel tool ids, bash pgid cleanup, symlink canonicalize, session schema version, quote-aware bash splitter
- F-MEDIUM (PRs dirge-code#85, dirge-code#86, dirge-code#87, dirge-code#89, dirge-code#90, dirge-code#91): interleaved bash output, compress net-savings, Retry-After parsing, plugin docs, relative-path normalize, BOM strip, bounded interject channel
- F-SKIP (F9, F11, F15): verified false positives or N/A; rationale documented inline

Status legend updated; ordering recommendation replaced with the
shipped-status section.

Co-authored-by: Yogthos <yogthos@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant