Skip to content

fix(sdk): keep a cut-short last line out of the coarse blame prefix - #478

Merged
yifanxuaaa merged 1 commit into
mainfrom
fix/coarse-blame-prefix-eof
Oct 27, 2026
Merged

yifanxuaaa merged 1 commit into
mainfrom
fix/coarse-blame-prefix-eof

Conversation

@yifanxuaaa

Copy link
Copy Markdown
Contributor

Summary

Follow-up to #468 (the prefix-at-EOF defect it reserved).

  • When a changed file exceeds blame's 2,000-line / 48 KiB comparison bounds and the newer version is a byte prefix of the older one ending in an unterminated line, the common prefix covered that whole line, so coarse fs.blame credited it to the older line it was cut from. Cutting a last line alpha beta to alpha, or dropping the final newline, kept the older Commit.
  • equal_edges() now gives up the prefix's last byte when the prefix is the whole newer text, the older text is longer and the newer text does not end with LF. Lines ending earlier in the prefix always end with an LF shared by both versions, so they are unaffected. The suffix is empty in this case, so the edges cannot overlap. At most one extra one-byte range read per changed coarse comparison.
  • api/docs/agent.md and core/docs/architecture/82-sdk-call-channel.md state the prefix rule next to the suffix rule from fix(sdk): keep partial suffix lines out of coarse blame #468.

Production LOC: 102,266 -> 102,269 (delta +3), all in layerfs-store-service (method in the commit message). No tests deleted.

Test plan

  • New sdk_blame_coarse cases: last line cut short (older with and without final LF) and dropped final newline fail before the fix, pass after; dropping whole last lines (control) passes both.
  • layerfs-store-service + layerfs-api tests: 145 passed in 63 binaries, under a 120 s wall limit (macOS arm64, Rust 1.85.1).
  • Scoped warning-denying Clippy, cargo fmt --check, check_product_boundary.py --skip-sdk, git diff --check.
  • Linux CI fast lane (reports only).
  • Not run: mount/nightly lanes. Durable: NOT_RUN — disabled by owner until explicit reauthorization.

Generated with Devin

Follow-up to #468. When the newer version of a changed file is a byte
prefix of the older one and ends in an unterminated line, the coarse
comparison's common prefix covers that whole line, so blame credited it
to the older line it was cut from: cutting `alpha beta` to `alpha` at
EOF, or dropping the final newline, kept the older Commit.

A line ending at the common prefix is the same line only if it ends
with LF (inside the prefix, equal in both) or both versions end there.
Lines ending before the prefix end always end with LF. So when the
prefix is the whole newer text, the older text is longer and the newer
text does not end with LF, equal_edges gives up the prefix's last byte
and the line becomes changed text. The suffix is empty in that case,
so the two edges still cannot overlap. At most one more one-byte range
read per changed coarse comparison.

Tests (sdk_blame_coarse): a last line cut short, with and without
a final LF in the older text, and a dropped final newline fail before
and pass after; dropping whole last lines keeps every origin (control).
api/docs/agent.md and 82-sdk-call-channel.md state the prefix rule.

Checks (macOS arm64, Rust 1.85.1): layerfs-store-service and
layerfs-api tests 145 passed in 63 binaries under a 120 s wall limit;
scoped warning-denying Clippy, fmt, check_product_boundary.py
--skip-sdk and git diff --check pass. Linux, mount and nightly lanes
not run. Durable: NOT_RUN - disabled by owner until explicit
reauthorization. No tests deleted.

Production LOC: 102,266 -> 102,269 (delta +3)
  engine 61,365 -> 61,368 (+3): layerfs-store-service 10,060 -> 10,063;
  core 38,255 and api 2,646 unchanged.
  Reference absent (retired R9c; last counted 65,417 at tree 498dd19).
  Method: tools/production_loc.py (blob 3341e4d) --root <snapshot>
  --json on archives of the parent d0419f6 and the staged tree.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@yifanxuaaa
yifanxuaaa merged commit e6d99d6 into main Oct 27, 2026
3 checks passed
@yifanxuaaa
yifanxuaaa deleted the fix/coarse-blame-prefix-eof branch October 27, 2026 18:01
jiangkoumo added a commit to jiangkoumo/layerfs that referenced this pull request Oct 28, 2026
…-AI-Lab#427)

Brings main up to 582bc78 (Ephemeral-AI-Lab#488, Ephemeral-AI-Lab#481 forced unmount after a stalled
Join, Ephemeral-AI-Lab#479, Ephemeral-AI-Lab#471, Ephemeral-AI-Lab#473, Ephemeral-AI-Lab#445 fs modes, Ephemeral-AI-Lab#475, Ephemeral-AI-Lab#478, Ephemeral-AI-Lab#476 Docker API
negotiation, Ephemeral-AI-Lab#396, Ephemeral-AI-Lab#419, Ephemeral-AI-Lab#418, Ephemeral-AI-Lab#415, Ephemeral-AI-Lab#477, Ephemeral-AI-Lab#468).

Two conflicts, both from Ephemeral-AI-Lab#481 (forced unmount of a normal unmount stalled
at Join):
- engine/crates/layerfs-daemon/src/control/force.rs: guard() keeps this
  branch's ExportKept check (an NFS export kept after a failed teardown
  answers with its stored custody first) and takes main's comment and its
  forceable() exception for a retained FUSE session. The non-Linux
  `let _ = token;` stays removed: ExportKept uses the token on every
  platform.
- engine/crates/layerfs-node/src/workspace.rs: unmount() keeps this
  branch's per-Workspace unmount lease (repeat a published outcome, drop
  the admission guard before the daemon call, publish the outcome before
  cleanup) and takes main's `force` option inside it: forced, one
  api.unmount(token, true) whose None answer is Unmounted::Closed;
  otherwise unmount_checked with `discard` as before.

Production LOC: first-parent 9478190 108596 -> 109158
(tools/production_loc.py --root .; the delta is main's own changes)
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