Baseline-aware three-way upgrade classification - #35
Merged
Conversation
Goal 2 of the brief — the largest lifecycle milestone. Every scaffolded
project now records a baseline in packkit.json: a content hash of each
generated file plus the package.json scripts/deps/protected-fields at
scaffold time. That lets `packkit upgrade` do a three-way comparison
(baseline vs current-on-disk vs newly-generated) and distinguish:
current == baseline, new != baseline → template-only change → safe to apply
current != baseline, new == baseline → your edit → preserve
current != baseline, new != baseline → both changed → conflict, review
applied across files, scripts, dependency sections, and protected fields.
Under the default (non-destructive) policy, template-only changes now
apply automatically — the user's edits are still never touched. Projects
without a baseline (older scaffolds) fall back to the conservative
"preserve anything that differs" model.
- Browser-safe content hash (src/core/hash.js, cyrb53) — the core still
runs in the web configurator, so no node:crypto. Deterministic; the
baseline is a pure function of the generated files, verified byte-stable
and identical from the bundled browser core.
- packkit.json is written last in every path (single-package + both
monorepo layouts) so the baseline covers the whole project, and excludes
itself.
- The plan now carries file `entries` (status/safeToApply/reason),
per-change classification on scripts/deps/fields, `baselineAvailable`,
and `diagnostics` (baseline-unavailable, malformed-package). The CLI
--json and upgradeProject() read that one diagnostics list — no
duplication.
Also folded in three coupled review fixes: upgrade policies are validated
(a typo like { scripts: 'replace' } throws instead of silently behaving
like add-only); a malformed package.json surfaces PACKAGE_JSON_PARSE_FAILED
instead of reading as "no changes"; --json gains an `ok` field.
Verified end to end: a scaffolded project with an edited README is
classified user-only-change and preserved on --apply while a deleted file
is re-added; determinism, digest round-trip, web configurator all green.
109 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Goal 2 of the upgrade-safety brief — and the reviewer's named "largest product opportunity." Every scaffolded project now records a baseline in
packkit.json(a content hash of each generated file + the package.json scripts/deps/protected-fields at scaffold time), sopackkit upgradecan do a real three-way comparison:--applyapplied across files, scripts, dependency sections, and protected fields. The default policy stays non-destructive — user edits are never touched — but now template-only changes to unedited files apply automatically, which turns upgrade from a conservative diff into a real lifecycle tool.
Older projects with no baseline fall back to the conservative "preserve anything that differs" rule.
Notes
src/core/hash.js, cyrb53) — the core runs in the web configurator, so nonode:crypto. Deterministic; verified the bundled browser core produces the same baseline.packkit.jsonis written last in all three generation paths so the baseline covers the whole project (and excludes itself). Determinism and digest round-trips are preserved.entries(status/safeToApply/reason), per-change classification on scripts/deps/fields,baselineAvailable, and a singlediagnosticslist thatupgradeProject()and--jsonboth read — no duplication.Folded-in review fixes (coupled to this code)
{ scripts: 'replace' }now throws instead of silently acting like add-only.PACKAGE_JSON_PARSE_FAILEDinstead of reading as "no changes."--jsongains anokfield.Verified
Scaffold → edit README → the plan classifies it
user-only-change(safeToApply false);--applypreserves it and re-adds a deleted file;--jsonis clean withbaselineAvailable: true. 109 tests pass, web configurator green.The rest of the review's P0 (JSON error exit codes, full-stack + runtime deployment contracts, ARCHITECTURE.md corrections) follows in focused PRs.
🤖 Generated with Claude Code