* fix(3407): snapshot old release into gsd-pristine, not new saveLocalPatches() was wiping gsd-pristine/ then re-populating it from pristineCtx.packageSrc — the NEW release source tree. For files that changed between old and new releases, this wrote NEW-release bytes as the pristine baseline while backup-meta.json recorded OLD-release hashes. The resulting hash mismatch triggered the #3657 verifier guard on every such file, causing it to skip the three-way diff baseline and fall back to the over-broad heuristic — effectively nullifying the #2998 feature for any file that changed upstream. Fix: preserve existing gsd-pristine/ entries that are already correct (sha256 on disk matches originalHash from manifest). These were written by the previous install with old-release bytes and remain valid. For files where no correct entry exists, leave gsd-pristine/ absent so the verifier falls back cleanly to over-broad mode — safe, never false-fails. OK_PRISTINE_DRIFT_DETECTED (added by #3657) is intentionally kept: it guards installations that already have drifted pristine from pre-fix runs and protects against other future stale-pristine scenarios. It is not removed because its guard is correct; only its trigger frequency drops. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * chore: add changeset for #3801 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3407): hash-validated regeneration for missing gsd-pristine entries Codex adversarial review found that the #3407 fix left absent gsd-pristine/ entries permanently absent, causing persistent over-broad verification even when the file was unchanged between old and new releases. Add selective regeneration: for entries absent from gsd-pristine/, generate a candidate via populatePristineDir into a temp dir using new-release source, then only promote if sha256(candidate) === originalHash. When hashes match, the file was identical across releases so new-release bytes ARE the correct old-release pristine. Discard mismatches — over-broad fallback applies. Add regression test asserting regeneration occurs for unchanged-between- releases files whose pristine entry was absent. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(3407): address review — restore mkdtempSync resilience, tighten tests, fix counter accounting Addresses sonnet adversarial MAJOR (mkdtempSync outside try/finally caused uncaught exception on broken /tmp), MIN-01–MIN-05 (misleading prose, counter double-count, missing stale-pristine test, permissive assertion, vacuous antipattern-hunt), sonnet MINOR (rmSync EISDIR), NIT (unused import, test count). F1: move mkdtempSync inside try block with catch/warn for graceful degradation F2: fix misleading prose — gsd-pristine/ is populated lazily by saveLocalPatches, not a separate install-time step F3: fix counter double-counting — track stalePaths/regeneratedPaths as Sets; removed = stale NOT regenerated (non-overlapping counts); update log message accordingly F4: add stale-pristine recovery test — pre-populates gsd-pristine/ with new-release bytes (exact pre-fix bug artifact), asserts absent after fix run F5: tighten Test 3 assertion from permissive if(exists)/notEqual to strict assert.strictEqual(exists, false) F6: remove vacuous antipattern-hunt describe block (typeof checks only, no behavioral coverage) — rationale noted in comment F7: use fs.rmSync with force:true/recursive:true for EISDIR resilience; only count removed after confirming file is actually gone via existsSync F8: remove unused afterEach from destructured import F9: test count updated to reflect 4 tests in describe block Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
468 KiB
Executable File
468 KiB
Executable File