Skip to content

chore(sync): Conflicted Sync of upstream/develop 2026-09-07 (42 commits), re-adopt #3268 head - #162

Merged
kylehgc merged 46 commits into
developfrom
sync/upstream-2026-09-07
Sep 8, 2026
Merged

kylehgc merged 46 commits into
developfrom
sync/upstream-2026-09-07

Conversation

@kylehgc

@kylehgc kylehgc commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Conflicted Sync of upstream/develop (head ab0cf40, dev-0.49.0-rc.410, 42 commits since the 2026-09-05 sync) into fork develop, per the CONTEXT.md Conflicted Sync policy: topic branch, upstream wins, only proven-additive fork code survives.

Full writeup: claudedocs/sync-conflict-2026-09-07.md.

Commits

Commit Author Kind
8a6658a chore(sync): merge upstream/develop (42 commits), upstream wins on 3 conflicts kylehgc Sync merge
8ca2e0e fix(diff): align by LCS and name the cause of an invisible difference Ilia Alshanetsky Cherry-pick of upstream rtk-ai#3268 d4239ec (re-adoption; two adjacency conflicts resolved as the union, no PR line changed)
091e4a5 fix(diff): number both files on a crossed rewrite pairing, and name the cap a refusal hit Ilia Alshanetsky Cherry-pick of upstream rtk-ai#3268 head 8073112 (clean)
686af2c docs(sync): record the 2026-09-07 conflicted sync, heal the merged diff rounds kylehgc Writeup, HEALED_SHAS, delta page

Conflicts and how each was resolved

File Colliding upstream work Resolution
src/cmds/git/diff_cmd.rs rtk-ai#3788 merged — the fork's own region-parser rework, rounds 1-8 Upstream verbatim. Every fork-side hunk was rounds 1-4 (now upstream's 1-8) interleaved with the rtk-ai#3268 adoption; the adoption is re-applied on top from the PR's current head, attribution preserved.
src/cmds/js/lint_cmd.rs rtk-ai#253 sqlfluff dispatch restructure (TheGlitching) Upstream's structure verbatim; the fork's rtk-ai#3567 adoption (617ef8e, WoldenMn: bare-path guard in detect_linter) and its amendment (3240075: failure passthrough in filter_generic_lint) survive — upstream rtk-ai#3567 is still open and git show upstream/develop:src/cmds/js/lint_cmd.rs | grep 'exists()|succeeded' is blank.
src/discover/rules.rs rtk-ai#3343 pipeline safety — new pipeline_safety field on every rule Upstream's PipelineSafety::ProducerOnly taken on the git rule; the fork's rewrite_prefixes: &["git"] survives (1d67272, RawNuke, adoption of rtk-ai#3414 — upstream rtk-ai#3408 is still open and upstream's rule still rewrites yadm commit to rtk git commit).

Fork code removed or superseded

  • diff_cmd.rs: the fork's copies of rounds 1-4 (8243d1a, 2219c6d, 25a17c0, fb5a3dc, 5939842) are byte-identical to upstream's f42eaf9…1b11b52 and heal by patch-id; 5a61595 and the five pre-region-parser hunk fixes (1f64783, 8e65037, 89cfe86, 5bcee1c, 6375941) are subsumed by upstream's ee614e4 and enter HEALED_SHAS. The ecef036 snapshot of fix(diff): stop reporting differing files as identical, and align by LCS rtk-ai/rtk#3268 (acbe88c) is superseded by the re-adopted head and enters HEALED_SHAS too.
  • registry.rs: fork test test_rewrite_ls_pipe_skipped removed. It came from e95207d (already healed) and asserted ls -t \| head -1 is never rewritten; upstream's per-rule safety now marks ls a safe producer on purpose. Measured: piped rtk ls -t prints git/ where ls -t prints git — a trailing / on directories, not the "size columns" the test's comment claimed. Upstream's call; the test encoded a superseded design.

Why rtk-ai#3268 is re-adopted whole (not the alignment half alone, as on 2026-09-03)

Ilia's 2026-09-04 rebase narrowed the PR onto upstream's rtk-ai#3469 byte-equality fix: compare_files decides identity on content1 == content2 first (upstream's check), IDENTICAL_FILES_MESSAGE / render_file_header are upstream's, and the invisible-difference message opens with upstream's wording. FileComparison is the third state the aligner needs (ran, then refused to list) that a bytes_equal bool cannot carry. src/core/guard.rs changes are doc-only; tests/diff_byte_accuracy_test.rs keeps every upstream assertion and adds a one-line case. Proof of additivity: git show upstream/develop:src/cmds/git/diff_cmd.rs \| grep -n 'FileComparison\|Unaligned\|myers_ops\|frame_legend' is blank.

Known residual: upstream rtk-ai#3268 is CHANGES_REQUESTED (KuSh, 2026-09-07): the frame legend misdescribes crossed ~ N→M pairs and is omitted when the crossing is the only pairing; two non-blocking wording notes. Legend/wording defects in a corner case, no content loss. Refreshes on Ilia's next push, as PR #153 did for the previous head.

Repro, real binaries

Before = ~/bin/rtk.exe built from develop (5809fb7); after = debug build of 091e4a5.

$ rtk rewrite -- "yadm status"                 before: rtk yadm status              after: rtk yadm status
$ rtk rewrite -- "git log --oneline | head -3" before: (no rewrite, exit 1)         after: rtk git log --oneline | head -3
$ rtk rewrite -- "ls -t | head -1"             before: (no rewrite, exit 1)         after: rtk ls -t | head -1
$ rtk rewrite -- "grep -n x f | wc -l"         before: (no rewrite, exit 1)         after: (no rewrite, exit 1)
$ rtk rewrite -- "npx eslint src"              before: rtk lint src                 after: rtk lint src

$ rtk diff a.txt b.txt        # one line inserted after line 4 of 12
before: 4a5                                    after: +   5 inserted
        > inserted                   exit 1                                          exit 1
$ rtk diff lf.txt crlf.txt    # alpha/beta, LF vs CRLF
before: lf.txt → crlf.txt
           files differ only in whitespace or line endings (no line-content change)   exit 1
after:  files differ only in whitespace or line endings (line endings: 0 CRLF vs 2 CRLF)  exit 1
$ rtk diff lf.txt lf.txt      before: [ok] Files are identical (exit 0)   after: same

Quality gate

x64 host toolchain: cargo fmt --all -- --check clean · cargo clippy --all-targets 0 warnings · cargo test --all exit 0 — 3430 unit tests passed, 0 failed, 8 ignored; all integration suites green. The first run, on the merge commit before the registry test removal, failed exactly that one test (Some("rtk ls -t | head -1") vs None).

Fork Delta

scripts/fork-delta.sh regenerated: 51 fixes (page said 61). Five healed by patch-id, seven new HEALED_SHAS entries (above).

Deliberately not done

🤖 Generated with Claude Code

aeppling and others added 30 commits July 31, 2026 11:12
Replace the RTK reference (meta commands, rtk proxy bypass, install
verification, branding, hook framing) with a minimal note stating that
condensed output is complete/authoritative and commands should be run
normally. Removes the runnable command blocks and bypass hint that led
agents to run extra commands and re-verify. Claude only.
…nks, raw fallback

Parse the stream into (prologue)(file-header)(hunk)* regions before
classifying: hunk extent comes from the @@ line budget (one old-budget per
parent, so @@@ combined headers parse too), content is classified only
inside hunks, and any structural disagreement (invalid body prefix, budget
over/under-run, budget owed at EOF, malformed @@) falls back to raw
passthrough. Detector precedence is a documented total order on
condense_unified_diff_strict.

Fixes, each with its reproducer from
claudedocs/diff-classifier-review-2026-08-29.md as a test:
- SQL/Lua '-- comment' removals (--- on the wire) no longer dropped
- added '++ text' lines no longer parsed as file headers
- format-patch mbox prose and the '-- ' signature no longer counted
- +++ /dev/null deletions named by their --- side
- binary / rename-only / mode-only sections reported instead of vanishing
- --color input stripped (was: silently empty output), non-UTF-8 stdin
  read lossily (was: hard error, no fallback)
- CRLF content bytes survive verbatim (split('\n'), not lines())
- b/ prefix stripped exactly once; timestamps tab-split from header names
- the '... +N more' trailer removed: it claimed truncation that never
  happened (all lines were printed above it)

Fixture corpus: 13 real-producer captures (git 2.54, GNU diff) in
tests/fixtures/diff -- multi-file, -U0, -W, rename/delete/binary,
log -p, show --cc, format-patch single/series/cover, diff -u/-ru/-rN,
CRLF. Property tests: every marked body line survives to the output,
counters equal rendered lines, the fallback fires on zero corpus fixtures.
…fixture hygiene

- Structural fallback now emits the caller's exact bytes (a lossy UTF-8
  decode or ANSI-stripped 'raw' is not raw); the decode-strip-parse-guard
  pipeline moved into condense_stdin so it is unit-testable.
- Dropped the mailer-padding tolerance: a line shorter than the hunk's
  prefix width now falls back instead of being guessed into context.
- Plain-diff fixtures recaptured with relative paths (no local usernames
  or session ids); copy-only and mode-only sections get real fixtures and
  a vanish-class test.
…ighten guards

- new file mode / deleted file mode sections (an empty file added or
  removed) get their own notes; previously they vanished silently whenever
  another file in the stream parsed cleanly. Real fixture captured, fix
  proven load-bearing by revert.
- Signature tolerance (rule 6) now requires the stream to have carried an
  mbox From separator; a bare '--' in a plain diff falls back raw.
- never_worse discrimination by token estimate instead of pointer
  identity; stdin decoded once (Cow) instead of twice; hunk-body prefix
  checked on the byte view without a per-line allocation.
- File-level facts outside hunks become note-only entries instead of
  vanishing while the stream condenses: 'Only in <dir>: <file>' and
  standalone 'Binary files ... differ' (GNU diff -r), '* Unmerged path'
  (git diff --ours during a merge), and 'Submodule <a>..<b>' headers.
  Suppressed inside mbox message regions, where column-0 prose is
  indistinguishable by value. Real fixtures captured for all four shapes;
  fix proven load-bearing by revert.
- is_mbox_from accepts 64-hex separators: SHA-256 repos' format-patch
  streams no longer fall back raw wholesale.
- .context() on the stdin read and raw-fallback write paths.
- Savings comment corrected to the measured corpus numbers (52-87%
  metadata-heavy, single digits content-heavy); exemption escalation
  unchanged.
…-8 gate

- '\ No newline at end of file' survives to the output (in-hunk and the
  common new-side position just after the budget closes): it is the only
  witness of a trailing-newline-only change, which otherwise renders as
  two byte-identical -/+ lines. Real fixture; proven load-bearing by
  revert.
- Non-UTF-8 stdin now always takes the raw-bytes branch, even when the
  stream parses: condensing would rewrite content bytes to U+FFFD, and
  byte fidelity outranks savings. (Base hard-errored here; raw
  passthrough is strictly better on both counts.)
- Doc-comment bounds recorded for the mbox header-pair spoof and the
  raw-fallback newline append.
- A ---/+++ pair opening a NEW section must be followed by a hunk header
  (every real producer's is); a stray marked pair left over from a lying
  budget now falls through to the marked-line detector and raw fallback
  instead of being consumed as a phantom header, losing both lines.
- never_worse guard in condense_stdin compares against the original
  input, not the ANSI-stripped intermediate.
- HUNKLESS_CORPUS pulls the four note-only fixtures into the no-fallback
  and never-larger property tests; savings comment names its metric.
Review round 2 (KuSh): no maintainer decision is pending on the savings
floor — CONTRIBUTING.md is authoritative at 20% as an admission
criterion. Drop the stale escalation sentence and cite that bar plus the
never-worse invariant directly.
…ar asserted

Rule 8's exemption narrows from the whole prologue to the mbox message
region only. A stream whose beginning was cut mid-hunk (head-clipped
capture, pipe that lost its first chunk) puts real hunk-body lines
before the first file header; the prologue exemption silently dropped
them while the intact tail condensed into a complete-looking result.
Now they force raw passthrough, honoring the parser's disagree->raw
contract. mbox commit prose (the format-patch --- separator, bullet
lists, quoted hunks) keeps its tolerance; no corpus fixture has
stream-start column-0 marked lines, so nothing real regresses.

Also pins the CONTRIBUTING.md 20% admission bar as a per-fixture
assertion on the metadata-heavy corpus streams, so the percentages
cited in the fidelity comment cannot rot.
… --no-prefix names

Structure is read through a per-line ANSI/CR-stripped view and content is
pushed raw, so escapes that are part of the user's content survive (the
file path was already byte-faithful on the same input). Rule 8's mbox
tolerance now ends at the first diffstat line: an orphaned hunk body in a
hand-edited series falls back raw instead of being dropped as prose, while
version notes between `---` and the diffstat stay prose. `diff --git X Y`
with X == Y marks a --no-prefix stream whose header names keep their
leading a/ b/ (creations and deletions included); the check is confined
to the two-path form. The new-side `\ No newline` marker is kept only on
the line right after its hunk closes. The dead `!in_prologue` conjunct
and the variable behind it are gone.

Real `git diff --cached --no-prefix` fixture added to the corpus.
…less region

`condense_unified_diff_strict` ends rule 8's mbox prose exemption at
format-patch's diffstat, detected by `contains(" | ")`. That matches
ordinary commit prose. It fires on this repo's own history: a bullet
reading "- The FEATURES.md `--line-numbers | -n` row was STALE" ends the
exemption, the bullets after it read as lost content, and the stream
falls back raw — 4097 bytes where 1634 condensed would do. Documenting
an option as `long | short` is standard notation, not an edge case.

Anchor the trigger on the count-and-signs right-hand side instead. Nine
real diffstat shapes still end the tolerance, including `Bin`, a bare
count for a pure rename, brace renames and paths containing a pipe.

`past_diffstat` is kept, not replaced. It is load-bearing beyond the
diffstat: it is the only mid-region check, so it is what catches a
stat-ful patch whose *first* section lost its headers while a later one
survived. Five designs that swapped it for a region-close check all lost
that shape — 60 real multi-file commits, 60 raw fallbacks before, 60
silent losses after.

A `--no-stat` patch has no diffstat, so there the exemption is settled
when the region closes, and only for a region that never reached a file
header. Such a region is bodyless by construction — a cover letter, an
`--always` empty commit — or a patch whose body lost its headers, and
only the second is loss. Shape tells them apart: over 111k marked lines
from 698 real diffs, no whole diff is entirely prose-shaped. Measured on
49 real two-patch series, 8 raw fallbacks before, 49 after.

The cost is honest: tightening the trigger gives up the streams the
loose match rescued by accident, when a pipe in a context line inside an
orphan body happened to force a fallback. Those rescues were a side
effect of the bug being fixed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ames, quoted paths

Review round 3 on the file-level-fact arms, plus a cold pass on top:

- `Only in <dir>: <file>` splits on the FIRST `: ` (GNU diff's separator
  follows the directory; a filename may carry its own).
- Standalone `Binary files X and Y differ` splits at the ` and ` where
  both sides agree past their first component, so a filename containing
  ` and ` is not cut, and is named through `header_name` so the `a/`/`b/`
  strip follows the same decision as a header pair.
- `* Unmerged path X` folds into the section git emits for X right after
  it: one `[file] X (unmerged) (+A -B)` entry instead of two.
- `Submodule <path> <a>..<b>` keeps only the path in the name slot (the
  tokens before the LAST `..` token, so a path containing `..` survives),
  and the sha-less `Submodule <path> contains ... content` dirty line is a
  fact too -- it used to be dropped silently beside a condensed sibling.
  Real fixture `git_diff_submodule_dirty_raw.txt` joins the corpus.
- `rename to` / `copy to` is git's exact path; the `+++` pair no longer
  re-derives it, which stripped a real `b/` directory under `--no-prefix`.
- `core.quotepath` wraps non-ASCII paths in quotes on every header line;
  names are dequoted before the prefix strip.
- The header-pair hunk gate applies to open hunkless sections as well:
  git only emits `---`/`+++` before the first `@@`, so a stray pair there
  is lost content and falls back raw instead of renaming the section.
- `diff --cc X` carries one path and leaves `prefixed` to its header pair.
- `past_diffstat` comment states the first-section-mangled shape it alone
  catches; the ` name | 3` bound says it fires always (the `---` separator
  is the marked line that follows); the stdin doc says the never-worse
  check is inlined and why.

A/B against 9106d48: 400 `git show` streams byte-identical; 290
format-patch series identical except 12 that fell back raw through a
prose pipe and now condense, zero new fallbacks.
…ule range kept

GNU diff translates `Only in` and `Binary files … differ` (git translates
none of its own lines). Rule 6 read the English spelling only, so on a
French machine `diff -ru g1 g2 | rtk diff -` dropped the three translated
fact lines as prose and, because a text section still parsed, returned
`Some` -- four files became one, silently.

Rule 3b now reads GNU diff's per-file `diff <opts> X Y` echo (printed
whenever it compares directories) as the mark of a `diff -r` stream. Such
a stream carries no prose, so a column-0 line no arm read there is a fact
in a language the parser does not speak, and rule 9 returns `None`
instead of dropping it. A line dropped before the echo settled the
question counts the same way once it does -- `diff -r` may list an
`Only in` first. Real fixture `diff_ru_fr_raw.txt` (`LC_ALL=fr_FR.UTF-8`,
diffutils 3.10) pins the raw fallback; the English `diff_ru_raw.txt`
still parses in full, as do `git log -p` streams whose prologue is prose.

The `Submodule <path> <a>..<b>` note now carries the range --
`[file] sub (submodule e139196..b0ac9b1)` -- for parity with the dirty
arm's `(submodule, modified content)`.
…dequoted renames

`\ No newline at end of file` describes the line directly above it. The
parser never renders context lines, so a marker git attached to an
unchanged last line landed under the last `-`/`+` line rendered and
claimed THAT line lacked a newline -- the one place the output stated
something untrue about the diff. The marker is now kept exactly when the
line above it was emitted (in-hunk after a `-`/`+`, or on the line right
after the budget closed on one), which keeps the witness of a
newline-only change and drops a marker that would describe the wrong
line. `emitted_at` replaces `closed_at`: the position test is the same
for both rules. Real fixture `git_diff_no_newline_raw.txt` carries both
shapes.

`# HG changeset patch` opens a message region like an mbox `From`, so
`hg export`'s column-0 headers and message no longer latch
`dropped_prologue` and send the whole changeset raw through its own
`diff -r <a> -r <b> <file>` echo. Real fixture `hg_export_raw.txt`
(Mercurial 7.0.1) joins the corpus.

`rename to`/`copy to` (and their `from`) go through `dequote`, so a
`core.quotepath` name has one spelling across a stream. The submodule
note keeps the range's direction qualifier:
`[file] sub (submodule e139196..b0ac9b1 rewind)`.

The body-line replay in `corpus_every_marked_body_line_survives` shares
the parser's per-parent presence rule (there is no second formula for
combined-diff columns); its doc now says so and names the oracle -- git's
header counts -- and it asserts a budget is never still owed at a
non-body line or at EOF, so under-consumption fails there too.
…ction)

Adds `rtk sqlfluff lint` for SQL linting workflows, particularly dbt
projects. Discovered as a savings opportunity via `rtk discover`.

- Injects `--format json` automatically; passes through if user sets it
- Groups violations by rule (top N) and by file with per-file breakdown
- Surfaces first violation location per rule and line numbers per file
- Shows fixable count and suggests `sqlfluff fix` when relevant
- Passes fix/format/version/parse subcommands through unchanged (capped)
- Registers hook rule in `discover/rules.rs` to auto-rewrite `sqlfluff lint`
- Preserves exit codes for CI/CD compatibility
- dbt-aware path compaction: keeps models/, macros/, seeds/ prefixes

Real-world tested on a production dbt project. Tolerates both v3+
`start_line_no` and legacy `line_no` schemas.

17 tests: happy path, edge cases, JSON parse fallback, real schema
regression, hook classification/rewrite, and token savings assertion (≥60% verified).
…wiring

Address the second-round review on PR rtk-ai#253:

- JSON parse failure now passes raw sqlfluff output through unchanged,
  with an stderr warning, honoring the non-negotiable fallback rule
  (rust-patterns.md) instead of emitting a truncated hybrid summary.
- "first at" rule locations are derived from the original sqlfluff JSON
  order, not the sorted worst-first file list, so the sample points at the
  earliest occurrence rather than the first file in the report.
- All report sorts are now deterministic: tied rule counts break
  alphabetically by rule code, tied files by path.
- rtk lint sqlfluff now routes through the shared structured filter, with
  the same format-flag handling as sqlfluff_cmd::run; a user-supplied
  non-JSON format keeps raw (truncated) output.
- Document the joined short-flag gap (-fhuman) as a known limitation to
  be fixed with the arg-tokenizer migration (rtk-ai#3681).
- Add regression tests for fallback passthrough (incl. large, uncapped),
  original-order first-location, and deterministic tie ordering.

Pre-existing, out of scope, tracked separately: ruff_cmd's identical
fallback deviation, a shared compact_path/grouping helper across the six
duplicated modules, and the bare-sqlfluff discover rule gap (same as ruff).
TheGlitching and others added 16 commits September 6, 2026 21:38
…, field aliases, README)

- F1: gate 'No issues found' on success; surface stderr on failure (lint_cmd)
- F2: early_exit_on_failure() so non-zero exit surfaces stderr (sqlfluff_cmd)
- F3: add description field + per-violation section (50-line cap, ruff-style)
- F4: '+N more rules' overflow after top-rules list
- F5: '+N more rules' overflow in per-file breakdown
- F6: dual-field line/col deserialization (start_line_no/line_no aliases)
- F7: README example with bare-path usage
- F8: pointer-only (lockstep comment already in lint_cmd)

Test fixture updated to include realistic sqlfluff fields (end_line_no,
end_line_pos, fixable) that real output always emits.
Resolved: awareness constants vs Pi/OMP rework, InitContext destructures,
bun/deno CLI additions, write_if_changed split.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DVD4ZD5wiSjSsNpKCK6h7q
…redirects, stage rewrite consolidation

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UAVhpAvWDmsEWuLehm9RAo
… GNU diff, hg and svn

Review round 7 asked for two things; a producer enumeration and two
adversarial review passes answered for thirty. Every item below has a
real capture in the corpus (81 fixtures now: git 2.47/2.54, diffutils
3.10 and 3.12, Mercurial 7.0, Subversion 1.14, PowerShell) and a test
that fails without the fix.

Silent loss (a file or content line missing while the output looked
complete) -- each now returns `None`, byte-exact raw passthrough:

- GNU sorts its output, so a fact the parser cannot read (`File X is a
  fifo ...`, `Symbolic links ... differ`, a translated `Only in`) can
  come before the first `Only in` / `Binary files` / `Files` line, and
  `-q` streams carry no echo at all. The latch is now `dropped_line` --
  any column-0 line dropped as prose outside a message region -- and is
  judged once after the loop against `gnu_stream`, which GNU's fact arms
  set as well as its echo (hg's echo does not: an `hg log -p --template`
  prologue is prose, not a fact).
- `hg export`'s region stayed open until the first header pair and
  swallowed `Binary file bin.dat has changed` on a binary-first
  changeset. hg's `diff -r` echo (one `-r` from `hg diff`, two from
  `hg export` / `hg log -p`) now closes the region, counts as reaching
  its body, and the line is a binary fact; rule 6 stays live inside an
  hg region. `hg log -p`'s `changeset:` line opens the region like
  `# HG changeset patch` does.
- `git diff --word-diff` / `--color-words` hunks whose lines are all
  indented carry their `[-x-]{+y+}` markers behind the indent, so the
  hunk was booked as context and the file vanished. A hunk that closes
  with no `-`/`+` line is not a unified-diff shape (whitespace-ignoring
  modes suppress the hunk) -> `None`.
- `git format-patch --submodule=log` puts `Submodule sub a..b:` where a
  file section would go, inside the message region where rule 6 is
  suppressed. The strict `<hex>..<hex>[ (<how>)]:` shape is admitted
  there (`is_submodule_range`); prose never ends a line that way.
- A stream cut off right after `diff --git` / `index` dropped the file
  it named: git never emits a header-only section, so one that closes
  with nothing behind it -> `None` (`FileEntry::from_git`; `flush`
  returns `Option`). git's `index` / `similarity index` lines are
  structural and no longer count as dropped prose.
- A plain `svn diff` names a binary only as `Index: b.dat` + `Cannot
  display: file marked as a binary type.`, both prose before: the
  binary vanished beside its text siblings. `Index: <path>` opens a
  section (rule 3c); the notice is its binary note; an `Index:` section
  that closes empty is `(no content)` (a copy/move target) unless a
  column-0 line was dropped inside it (a localized notice) -> `None`.
- A binary section followed by another producer's header pair was
  renamed in place and its `binary` note landed on the next file; a
  pair after a binary section opens its own section.

A crash: the shared-tail scan behind `diff --git X Y` and `Binary files
X and Y` compared bytes, and two different multi-byte characters can
share trailing bytes (`😀`/`🙀`, `é`/`©`): the slice landed mid-character
and the process aborted with no output at all. The scan backs off to a
character boundary on both sides.

Names, byte-equal to the real filename under the producer's own root:

- `dequote` decodes git's C quoting (`"caf\303\251.txt"` -> `café.txt`)
  instead of stripping the wrapper; a name that would split a `[file]`
  line (newline) or is not UTF-8 keeps git's own quoted spelling, with
  the prefix stripped inside the quotes, so `rename to`, `diff --cc` and
  the header pair agree on one spelling and two Latin-1 names stay two.
- `unquote_shell` decodes diffutils >= 3.11's shell quoting on `Only in`
  / `Binary files` names -- `'…'`, `$'…'` and the `"…"` form it picks
  for a name holding a `'`; a quoted directory may itself hold `: `, so
  the `Only in` split follows the quoting (`shell_word_len`). 3.10
  prints those names bare; a bare `Only in` with more than one `: `
  splits at the root the stream already named on its echo, header pairs
  or `Binary files` lines. Both generations are in the corpus.
- `diff --git X Y` is split where the sides share the longest tail at a
  `/` boundary (`shared_tail`); the first path component before the
  tail on each side is that side's prefix (`FileEntry::prefixes`
  replaces `prefixed`): `a/`/`b/`, `i/`/`w/` under
  `diff.mnemonicPrefix`, `--src-prefix`/`--dst-prefix`, none under
  `--no-prefix`. The header pair strips exactly those, so `* Unmerged
  path b/inb.txt` folds into its `i/b/inb.txt w/b/inb.txt` section, a
  binary under a directory named `x b/` keeps its path, and `git diff
  --no-index d1/f d2/f` names `d2/f`. `diff --cc <path>` is kept whole;
  `--no-index --no-prefix x.bin y.bin` names `y.bin`.
- GNU diff names files under the roots it was given, never prefixes:
  header pairs after a GNU echo and the standalone `Binary files` /
  `Files` arms keep them (`diff -ru a b` -> `b/c.txt`, `diff -ru .
  ../new` -> `../new/x`), splitting `X and Y` by the same shared tail.
- Timestamps are stripped from `---`/`+++` lines only, at the LAST tab
  and only when shaped like one of the real producers' (GNU ISO date,
  hg `Mon Sep 07 …`, svn `(revision 1)`, git's bare tab), so a name
  containing a tab survives even under `hg diff --nodates`.
- An `* Unmerged path` fact git printed unquoted and cut at a newline
  folds into its quoted section instead of a phantom entry.

Spurious raw fallbacks on well-formed streams, now condensed: `git log
--stat -p` / `git show --stat -p` (bare `---` followed by a diffstat
line is the separator -- which also drops the old ` name | 3` bound),
`git log --numstat -p` (`-<TAB>-<TAB>` binary rows), `hg log -p` with
and without `--template`, an hg binary-only changeset whose message has
a marked non-prose line, `--format=%B` prose starting with `diff ` (the
GNU echo arm keys on `diff -`), `diff -u` on directories (`Common
subdirectories:` dropped), an svn copy/move target.

Also: GNU `-s` / `-q` facts are entries; a PowerShell-written stream's
UTF-8 BOM is stripped; a submodule both dirty and moved is one entry;
the budget replay in property (a) asserts under-consumption; the docs
list rule 1b and every bound is executable in `documented_bounds_hold`.
…ry points

sqlfluff exits 1 whenever it finds violations, which is the normal case this
filter exists for. Two changes in the last push read that exit code as failure
and so disabled the filter exactly when it had something to compress:

- `sqlfluff_cmd` used `early_exit_on_failure()`, which dumps the injected JSON
  raw. On a 51-file corpus that is 9.8 KB where plain `sqlfluff lint` is 1.1 KB.
- `lint_cmd` substituted `result.stderr`, which is always empty: sqlfluff writes
  even fatal errors to stdout (verified against 2.3.5 and 4.3.0 - `Error:
  Unknown dialect 'NOPE'` on stdout, stderr empty, exit 2). Every violation was
  discarded in favour of a 25-byte `SQLFluff: failed (exit 1)`.

Both are one bug reached two ways, because both entry points restated the same
routing and format-flag logic and were then edited differently. Extract it into
`sqlfluff_cmd::plan`, which states once how rtk invokes sqlfluff and how it
reads the result back; `lint_cmd` now calls it instead of keeping a copy. The
exit code only disambiguates output the filter could not parse, so a fatal error
reaches the user verbatim while violations are still summarized.

Also in the report:

- Rank the `Violations:` section worst-file-first like every section above it.
  Iterating sqlfluff's emission order and taking the first 50 dropped exactly
  the file the summary ranked first.
- Build only the lines that get printed, instead of every line to keep fifty.
- Omit positions sqlfluff did not report rather than fabricating `:0:0`.
- Keep two path segments when no dbt root matches, so `migrations/orders.sql`
  and `reports/orders.sql` stay distinct in the section meant to be opened.
- Treat a missing `fixes` key as unknown rather than zero. sqlfluff 2.x omits it
  entirely, which silently suppressed the `sqlfluff fix` hint.
- Rename the savings test to the bound it actually asserts.

Tests cover both regressions against real captured output: 4.3.0 for the current
field names and fix data, 2.3.5 for the legacy names and the absent `fixes` key.
The consumer-flag cases were a hand-maintained list that grew one literal per
review round, so each new spelling was found by review rather than by a test.

Generate the spellings from SAFE_PIPE_CONSUMERS instead: every unambiguous
long-option prefix getopt_long accepts, each in bare, double-quoted,
single-quoted, backslash-escaped and =value form, and every unsafe short flag
bare, quoted, escaped and bundled. A consumer added to the table later is
covered on arrival.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…d-slim-instructions

feat(rewrite): rewrite in pipe when consummer is safe
feat: add rtk sqlfluff lint with JSON filter (~75% token reduction)
…ments-4pky96

fix(diff): region parser for condense_unified_diff — budget-owned hunks, raw fallback
…conflicts

Conflicted Sync of upstream/develop ab0cf40 (dev-0.49.0-rc.410) per CONTEXT.md.

- src/cmds/git/diff_cmd.rs: upstream verbatim. Upstream merged the fork's own
  region-parser rework (rtk-ai#3788, rounds 1-8), so every fork-side hunk was either
  an older round of the same work or the alignment half of the rtk-ai#3268 adoption
  (Myers compute_diff, Unaligned/Replaced, positional, frame_legend) interleaved
  with it. The rtk-ai#3268 half is superseded here and re-adopted from the PR's
  current head in the next commit, attribution preserved.
- src/cmds/js/lint_cmd.rs: upstream's sqlfluff dispatch restructure verbatim;
  the fork's rtk-ai#3567 adoption (bare-path guard in detect_linter) and its
  fork-authored amendment (failure passthrough in filter_generic_lint) stay,
  since upstream rtk-ai#3567 is still open. The generic arm keeps `result.success()`.
- src/discover/rules.rs: upstream's new pipeline_safety field taken; the
  fork's rtk-ai#3414 adoption (yadm removed from the git rule's rewrite_prefixes)
  stays, since upstream rtk-ai#3414 / rtk-ai#3408 are still open.
- src/discover/registry.rs: fork test test_rewrite_ls_pipe_skipped dropped. It
  came from e95207d (already in HEALED_SHAS) and asserted `ls -t | head -1`
  is never rewritten; upstream's per-rule PipelineSafety now marks ls a safe
  producer on purpose, so the assertion encoded a superseded design.

Writeup: claudedocs/sync-conflict-2026-09-07.md

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
develop now carries the byte-equality verdict (0cb34ac, 428af61), so this
branch no longer argues for it. The alignment fix and the reporting that
depends on it remain.

compute_diff compared line N to line N, so a single inserted or deleted
line reported every line after it as modified. This aligns by Myers' greedy
edit script, so one insertion reads as one insertion.

The script folds into hunks, one per run of differing lines with no
matched line between. Both renderers group by hunk: the classic fallback
prints one NcM per region, as diff does, because the classic format cannot
express which old line became which new line, and rendering the pairing
split a region into an NcM plus a trailing NaM that diff never prints.
Inside a hunk the condensed render pairs old and new lines by best
similarity rather than by position, so an insertion at the head of a run
no longer shifts every pairing after it into a rewrite that did not happen.

Op::Keep carries a run length. One entry per matched line made the script
scale with the file rather than with the change, 45MB of separators for a
million-line pair with 700 rewrites. The aligner's trace is one flat vector
with each round's bookkeeping stored inline, so MAX_TRACE_CELLS charges
what is allocated: a per-round Vec cost 5.8x the cells being counted on a
lopsided pair.

The bool develop passes into render_diff cannot express the third case the
aligner produces, a comparison that ran and then refused to build a listing
because it would cost more than the raw text. FileComparison replaces the
bool with Identical, InvisibleDifference and Lines, and DiffResult::unaligned
carries the refusal reason. An empty change list is not a synonym for
identical, and routing a refusal through the identical branch exits 0 on
files that differ.

The invisible-difference message keeps develop's wording, so the phrase
diff_byte_accuracy_test matches on survives, and then names the measured
cause instead of stopping at "no line-content change". It is shown whenever
the case arises. A fixed token allowance above raw could not be met: the
message's shortest form is ~20 tokens and a one-line pair ~2, so the ceiling
sat under the message's floor and dropped it on 90% of one-line pairs,
printing the two indistinguishable blobs it exists to replace.

The render drops the file-pair header and the blank line, names the files
in the frame legend by argument position instead of by path, and prints
the counts line only once the listing runs to a screenful. On 120
agent-sized diffs the framing cost more than the change list saved: the
body alone is 7% smaller than diff, and each line of chrome erased that.
…he cap a refusal hit

`pair_rewrites` pairs by similarity, so two similar lines swapped and both
edited pair crosswise. The condensed render listed them in file1 order with
one number each, which read as two in-place edits and described a file2 that
does not exist: `timeout = 60` rendered onto line 2, where `retries = 5` is.
A crossed hunk now renders each `~` as `~ N→M`. A hunk that only shifted
keeps the single number, since order already says where the new text goes,
so output size is unchanged outside a crossing.

A refusal by `POSITIONAL_BYTE_CAP` reached the count refusal's wording, so
two 3MB single-line files reported "1 lines ... too many to list". Both
`Unaligned` refusal variants carry which cap they hit, and the render names
it: the byte form states the size of the text it declined to list.

Tests: the crossed render as an exact string beside the shifted-only form,
a property that rebuilds file2 from the condensed listing over 3,000 random
similar-line pairs, and both byte refusal messages as exact strings.
…ff rounds

Writeup for the merge of upstream/develop ab0cf40 and the rtk-ai#3268 re-adoption
on top of it: every conflict, what upstream's side replaced, the one fork
test dropped, real-binary before/after, and the residual upstream rtk-ai#3268
finding the adopted head still carries.

HEALED_SHAS gains the fork's region-parser lineage now merged upstream under
PR rtk-ai#3788 (5a61595 as ee614e4, plus the five hunk fixes it subsumed) and the
ecef036 snapshot of rtk-ai#3268 superseded by the re-adopted head. Delta page
regenerated: 51 fixes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@kylehgc
kylehgc merged commit a73d599 into develop Sep 8, 2026
4 checks passed
@kylehgc
kylehgc deleted the sync/upstream-2026-09-07 branch September 8, 2026 00:59
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.

5 participants