Conversation
The key sync was add-and-bump only: an entry upstream dropped stayed forever, a script body never updated, and a range upstream lowered on purpose never followed. After one sync raak still carried 22 dependency entries upstream had removed, `pg-format` in three workspaces, a script whose target the same sync deleted, and `--target node24` after the Node 26 migration. Every record key (dependencies, devDependencies, scripts, engines, overrides, pnpm.overrides, pnpm.patchedDependencies) and `packageManager` now merge against the merge-base package.json (the recorded sync point, else git's merge-base). An entry the fork never touched follows upstream: update, downgrade or removal. An entry the fork added or changed stays, except that a strictly higher upstream version still bumps it (never for scripts). An entry the fork removed is not re-added. Without a base the old add-and-bump behaviour applies. A workspace upstream added since the base (raak: `oauth/`) used to arrive without its package.json, since every package.json is managed and the sync only visited locations the fork already had. Its package.json now lands verbatim when the merge brought the directory; a package.json the base had and the fork deleted stays deleted. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Managed files (package.json, the lockfile, the sync config) are always pinned, so `analyze` warned that `cdc/`, `sdk/`, `studio/` and `yjs/package.json` "match the previous upstream but changed upstream" although the package sync reconciles their keys. `findMaskingPins` skips them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The three-way merge removed a dependency or script upstream dropped whenever the fork's package.json entry still matched the merge-base, even when a fork-only module imported the package, a fork script ran its CLI, or a fork workflow ran the script. Before removing such an entry the sync now searches fork-authored content (files that differ from upstream after the file merge, plus scripts the fork added or changed) and keeps the entry when it finds a use. Packages are searched within their own workspace, scripts repo-wide. The sync also prints every package.json change (added, updated, removed) and warns about each entry it kept, with the file that uses it. Co-Authored-By: Claude Opus 5.5 (1M context) <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.
The three sync CLI items from raak's 2026-09-24 feedback list (the cella-side items are in cellajs/cella#1201 (cellajs/cella#1201)).
Three-way package.json key merge
packageJsonSyncwas add-and-bump only (safeMergeRecord): an entry upstream dropped stayed forever, a script body never updated, a range upstream lowered on purpose never followed. After one sync raak still carried 22 dependency entries upstream removed in cella#1190,pg-formatin three workspaces, ageoip:downloadscript whose target the same sync deleted, andboot:build --target node24after the Node 26 migration.Every record key and
packageManagernow merge against the merge-base package.json, read withgit show <base>:<path>where base isgetEffectiveMergeBase(the recorded sync point, else git's merge-base):scriptsexportsandpnpm.packageExtensionsstay add-only. README section updated.A new upstream workspace arrives with its package.json
Every package.json is managed (always ignored by the file merge) and the sync only visited locations the fork already had, so
oauth/arrived withREADME.md,src/andtsconfig.jsonbut nopackage.jsonwhilepnpm-workspace.yamlalready listed it. A location the fork lacks whose base also lacks it is a workspace upstream added since the last sync: its package.json is copied verbatim when the merge brought the directory and the path is not ignored. A package.json the base had and the fork deleted stays deleted.analyzeno longer flags managed package.jsons as masking pinsisPinned()treats managed files as pinned, andfindMaskingPinsdid not exclude them, soanalyzewarned aboutcdc/,sdk/,studio/andyjs/package.jsonalthough the package sync reconciles their keys.A dropped entry stays while fork code still uses it
The fork can use an inherited entry without touching it in package.json: an import in a fork-only module, a CLI in a fork script, a script name in a fork workflow. The three-way merge alone would remove it. Before removing a dependency or script upstream dropped, the sync searches fork-authored content, meaning files that differ from upstream after the file merge (package.json files and the lockfile excluded) plus scripts the fork added or changed. Upstream no longer uses what it dropped, so a match there is the fork's.
@types/*entry types, and the package's CLI names as whole words, read from its installedbin(typescriptis found throughtsc). Scoped to the workspace's directory; root dependencies search the whole repo.pnpm --filter backend geoip:download), searched repo-wide, workflows and lefthook included.A false match keeps the entry, which is the previous behaviour. Not covered: packages loaded from a computed
import(name), scripts started through a glob runner (run-s geoip:*), andpnpm.overrides/patchedDependencies, which code does not import.The sync now lists every package.json change and warns about each kept entry with the file that uses it:
Verification
pnpm ts,pnpm lint,pnpm buildand the fullvitest run(18 files, 180 tests) are green. New tests: dependency removal when untouched, kept when changed, not re-added when the fork removed it, downgrade follows upstream, script update when untouched, new-workspace copy, fork-deleted workspace package.json left out, managed files excluded from masking pins, a dependency kept while a fork module imports it, a devDependency kept through thetscbin a fork script runs, the search scoped to the workspace, a script kept while a fork workflow runs it. The four usage tests fail with the check disabled.🤖 Generated with Claude Code