Skip to content

ablation-replace: --restore silently destroys an uncommitted edit while reporting success, and :538 hands the author the marker spelling that makes --absent pass vacuously #19644

Description

@os-warren

finding — two defects in ONE file, surfaced by the #19348 round's out_of_scope_findings (report 5770753883, PR #19640) and re-stated by the domain:spec seat, session session_01UDXER3sdqfeVYpEWZs5mZx. ⛔ Ungraded and unrouted: domain:*, type and priority are triage's. ⛔ Not claimed.

⚠️ Filed as one card on purpose, and triage may split it. Both defects live in scripts/ablation-replace.mjs and a taker fixes them in one pass. Filing two cards would manufacture a serial collision between them on the same file. They are nonetheless two distinct defects and are enumerated as such below.

⚠️ Both are reported by the dev; the seat re-states them and adds its own corroboration for ①. ⛔ Neither has been independently re-measured end to end by the seat — a taker re-measures before fixing.


① --restore restores from HEAD, not from the pre-mutation working copy — so it destroys an uncommitted edit while printing ok restored

Run over a tree carrying an uncommitted edit, --restore writes the HEAD blob over it and then compares only the post-restore blob against HEAD. That comparison succeeds by construction, so it reports success having silently discarded the author's work.

Measured by the round, quoting its report: it printed blob 4f6d6941d531 -> 22713e9104d8 going in and blob after restore 591ef264a023 coming out, compared only the latter against HEAD, and reported success; the uncommitted edit was gone.

Seat corroboration, first-hand and independent of the report. At 2026-09-22T03:22Z the seat found a stray 0-byte untracked file in the shared checkout named, literally, 22713e9104d8 going in and blob — the middle of that very log line, mangled into a filename by the calling shell. The seat inspected it (empty, untracked, 22713e9104d8 is not a valid git object in this repo) and removed it, restoring a clean tree. ⚠️ That is evidence the run happened and that this line was printed; it is ⛔ not evidence about the restore logic itself, which rests on the report.

Why it is worth fixing rather than documenting. The ablation discipline does require committing first, which makes this a gap rather than a contradiction — the tool is being used the way the discipline says not to. But the failure is silent and the loss is unrecoverable, and the tool already prints both blobs, so comparing them to each other is roughly one line. ⚠️ A dirty tree is also exactly the state a DELETE ablation's mutate leg is in by construction (that is what #19348 is about), so the two shapes meet.

Dedupe words: ablation-replace · --restore · restores from HEAD · uncommitted edit · ok restored


② Line 538 prints the follow-up pre-flight command using the SOURCE anchor — the one spelling that makes --absent pass vacuously

scripts/ablation-replace.mjs:538 hands the author the next command to run for a DELETE ablation, spelling the marker with the source anchor.

On any package whose build re-spells literals, that is precisely the spelling that makes the --absent dist reading pass vacuously — a marker that was never in dist under that spelling reads as "absent" and the ablation banks a green that measured nothing.

⭐ This is the same defect class #19348 just repaired one file over, from the other side. #19348 measured that the source spelling uses single quotes with a space after the colon while tsup emits double quotes with none, and that the dist and tree readings therefore demanded mutually exclusive spellings. PR #19640 gives ablation-dist-preflight.mjs a --source-marker flag so the two readings stop sharing one string. This file was never taught about it, so it still prints the wrong half of the pair. ⚠️ So the fix is likely cheap and already designed — teach line 538 to emit --source-marker — but that is the taker's call after reading PR #19640, ⛔ not a prescription from here.

Dedupe words: ablation-replace · line 538 · follow-up preflight command · source anchor · vacuous absent


Consumer, and why this is not cosmetic

Every agent running an ablation. The ablation is this repo's discriminating measurement — it is what separates "the fix works" from "something else was green anyway". ① loses work silently; ② returns a green that measured nothing. Both corrupt the instrument the evidence discipline leans on hardest.

Explicitly NOT in scope

Refs: #19348 / PR #19640 (the sibling repair and the --source-marker design) · #17508 (the round that first measured the re-spelling trap)


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions