Skip to content

fix: reject stray lines between file sections instead of silently dropping them - #46

Merged
code-yeongyu merged 3 commits into
mainfrom
fix/padded-hunk-headers
Oct 3, 2026
Merged

code-yeongyu merged 3 commits into
mainfrom
fix/padded-hunk-headers

Conversation

@code-yeongyu

@code-yeongyu code-yeongyu commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

Fixes #45.

Summary

  • The bug: between file sections the parser skipped any line not starting with *** . An indented file header was therefore dropped along with its hunk lines, and the patch reported success. As the first section, the same header failed with a misleading "no hunks found".
  • The fix: file headers are recognized after trimming, as in Codex (streaming_parser.rs process_line). Any other non-blank line between sections rejects the whole patch with '<line>' is not a valid hunk header, before anything is applied. Indented markers inside an update hunk stay context lines, as in Codex.

Verification

  • bun run check (typecheck + biome)
  • bun run test: 67/67
  • New test/patch-headers.test.ts: 6 user-facing cases. The 5 that exercise the fix fail on main and pass here. The sixth (an indented marker inside a hunk stays context) passes on both and guards against over-trimming.
  • Codex's portable conformance scenarios (codex-rs/apply-patch/tests/fixtures/scenarios, 26 cases) replayed against this branch: 017_whitespace_padded_hunk_header now passes. The remaining two failures (023/024, line endings) are a separate fix.

apply_patch impact

  • No schema or grammar change
  • Path safety unchanged
  • CHANGELOG entry under [Unreleased]

Review in cubic

…pping them

Between file sections the parser skipped every line that did not start with
'*** ', so a file header indented by a space was dropped together with its
hunk lines and the patch still reported success. File headers are now
recognized after trimming, as in Codex, and any other non-blank line between
sections rejects the patch with "is not a valid hunk header".

Fixes #45
@code-yeongyu

Copy link
Copy Markdown
Owner Author

Lead in-session review at 0598319: PASS. File headers are recognized after trimming (Codex behavior), and a non-header, non-blank line between file sections now reaches the header parser and is rejected before anything is applied, instead of being skipped together with the section it introduced (the silent dropped edit). Add-file body lines start with '+', so the trimmed *** break can't fire on content. Tests are user-view (whole patch rejected, nothing changes).

The parser now accepts indented file headers, so the exported path extractor
must report them too; a consumer that gates writes per file (a permission
prompt, the pending-path display) would otherwise not see a file the patch
is about to change.

Refs #45
@code-yeongyu

Copy link
Copy Markdown
Owner Author

Lead re-review of b3efd4c (extractPatchedPaths): right direction, one P1 left.

The parser recognizes headers with String.prototype.trim(), which strips ALL JS whitespace (\u00A0, \uFEFF, \v, \f, \u2000-\u200A, \u3000, ...), but the extractor regex only allows [ \t] around the header. So \u00A0*** Update File: x is parsed and written but NOT extracted: that file skips the per-file approval, the same bypass in a narrower form; and a trailing \u00A0 makes the approved path differ from the written one.

Fix: make the extractor use exactly the parser's notion of whitespace, e.g. derive both from one helper (split lines, .trim() each, then match ^\*\*\* (?:(?:Add|Delete|Update) File|Move to): (.+)$ on the trimmed line), or use [^\S\r\n]* on both sides plus a final .trim() on the captured path. Add a test with a \u00A0-indented and a trailing-\u00A0 header asserting extractPatchedPaths lists exactly the paths the parser will write.

…tchedPaths

The parser trimmed headers with String.prototype.trim, but the extractor's
regex only allowed spaces and tabs, so a header indented with a no-break
space was written but not listed, and a trailing one made the listed path
differ from the written one. Both now read headers through parseFileHeader
and parseMoveTo (Move to is trimmed at the end, as in Codex), so the listed
paths are exactly the paths the patch writes.

Refs #45
@code-yeongyu

Copy link
Copy Markdown
Owner Author

Lead re-review of 36388ed: PASS. Parser and extractPatchedPaths now share parseFileHeader (String.prototype.trim) and parseMoveTo (trimEnd), so the whitespace definition is one by construction; the extractor's extra trimStart on Move to only over-approximates (fail-safe for per-file approval). The trailing-space Move to mismatch is fixed too, and the \u00A0 test asserts extracted == written. Merge on green.

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.

apply_patch silently drops a file section whose header is indented, and reports success

1 participant