fix(init): a re-install backs up only what update would keep; refusals come before the backup - #223
Merged
Conversation
…s come before the backup - Edited = changed since pharn wrote it. init's prompt and its backup now classify each existing file through update's own decideFileAction, against pharn.records.json (stamp-checked against the config being replaced). A file still at its recorded hash is a clean upgrade: not marked, not backed up. Marks: (edited), (no pharn record), and (differs from upstream) when there is no usable store. - Each file is compared with its REAL source, so an edited PHARN-LICENSE / pharn/LICENSE (source: upstream LICENSE) is marked and backed up instead of silently overwritten. - The destination pre-flight (prepareInstall, exported) runs before the backup: a refused install writes nothing, .pharn-backup/ included. - The type pre-flight also refuses a directory at pharn.config.json or pharn.records.json (was: every file copied, then EISDIR, leaving no records and no config). - A live .claude/settings.json symlink is accepted (init never writes an existing settings file); a dangling one is refused with a file-specific message. Linked files and linked directories are named apart. Measured on Node 20.13 / 22 / 24: cpSync replaces a dangling leaf link, it never writes through. - The install manifest is built once per run and shared by the prompt, the pre-flight, the backup scan, the copy and the records (was: 5x). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0199owRmYfskqYQVQrVP679o
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Advanced Run ID: Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
11 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
Plan B of the review follow-ups (
.dev/features/init-reinstall-safety/). It covers six findings in a re-runpharn init:F9 — "edited" meant "differs from upstream". After any upstream bump, every file pharn itself had written was marked
(edited)and copied to.pharn-backup/. The prompt and the backup now useupdate's owndecideFileActionagainstpharn.records.json(stamp-checked):(edited): the file changed since pharn wrote it.(no pharn record): no record covers the file.(differs from upstream): there is no usable records file, so every difference counts.A file still at its recorded hash is a clean upgrade: it is not marked and not backed up.
F10 —
PHARN-LICENSE/pharn/LICENSEwas never compared. The scan looked for the same path in the clone, but the file's source isLICENSE. Each file is now compared with its real source (manifestSources).F20 — a refused install could still create a backup. The destination pre-flight (
prepareInstall, now exported) runs before the backup.F19 — a directory at
pharn.config.json/pharn.records.jsonleft a half-install. Every file was copied, then the write failed withEISDIR. The type pre-flight now refuses it before the first write.F8 (init half) —
.claude/settings.jsonsymlinks.F28 — the manifest was built 5× per run. It is now built once and shared by the prompt, pre-flight, backup scan, copy and records.
Type of change
feat— new stack option, wizard step, or command capabilityfix— bug fixdocs— docs-only changechore/refactor— tooling or internal restructure, no behavior changeArea(s) touched
commands/init | steps/install-archetype | steps/overwrite-check | lib/dest-drift | lib/install-capabilities | lib/install-manifest | docs
Checklist
.js-extension import convention.tests/*.test.tswhen wizard behavior changed. 35 new or changed cases fail on the base5b63e31, each for the reason the plan names.docs/page (docs/commands/init.md,docs/troubleshooting.md), plus CLAUDE.md and CHANGELOG.sourcesvalues are re-safeJoined under the clone, and a test pins an escaping value as a throw.Quality gates
npm run checkpasses locally (1605 tests). I ran it as root with the DAC-override capabilities dropped (CI-equivalent) and with no proxy variables set.npm run buildsucceeds.npm run test:coveragepasses (97.61 / 92.93 / 98.32 / 98.45).Notes for the reviewer
settings.jsonlink was wrong. It saidcpSyncwrites through such a link. Measured on Node 20.13.0, 22.22.2 and 24.21.0, it replaces the link with a regular file. The refusal still stands, for the true reason: the user's link would be lost silently. The comment, docs and test title say that.pharn/layout change "backs up everything". It doesn't: the new paths don't exist in a flat project yet. A test now pins that.readRecordsblocks on a FIFO atpharn.records.json.updatealready has this problem;initnow reads that file on every re-install too. The fix belongs inlib/install-records.ts.🤖 Generated with Claude Code
https://claude.ai/code/session_0199owRmYfskqYQVQrVP679o
Generated by Claude Code