Skip to content

docs: document the fork customization workflow in SELF_UPDATE - #5929

Open
tzioup wants to merge 1 commit into
atomantic:mainfrom
tzioup:docs/fork-customization-workflow
Open

docs: document the fork customization workflow in SELF_UPDATE#5929
tzioup wants to merge 1 commit into
atomantic:mainfrom
tzioup:docs/fork-customization-workflow

Conversation

@tzioup

@tzioup tzioup commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

The branch-and-rebase workflow for fork users lives in exactly one place today: the UpdateTab
fork panel (client/src/components/apps/tabs/UpdateTab.jsx:443-444). That panel renders only when
isFork is true, and only if the user opens that tab. docs/SELF_UPDATE.md documents the update
mechanism thoroughly — the pull, the forced switch to main, pre-checkout stashing and recovery
— but never the workflow that mechanism implies.

This adds one section, ## Running a customized fork, after "Fork UI: three distinct buttons".
No code change.

It writes out the loop the tip states in short form, plus the half that is currently undocumented
anywhere: after rebasing your branch onto main you have to reinstall, rebuild and restart, since
update.sh always finishes on main and cannot do it for you. It also notes that install order
matters, because npm install rewrites client/package.json and re-stales an earlier build.

Finally it documents a side effect that reads as a fault and is not one: a clean rebase rewinds the
working tree to the branch's older base and rolls it forward, giving every touched file a new
mtime, so getInstallState() reports a stale build and stale deps in all four workspaces with no
dependency changed and no build input edited.

Test plan

No code paths change, so there is nothing to unit test. Every claim was reproduced on a fork
install running 2.56.0:

  • Rebased a private branch onto a freshly updated main. getInstallState() immediately returned
    staleBuild: true and staleDeps.stale: true for root, client, server and autofixer,
    each with reason: "manifest-newer", though the branch touches no manifest.
  • Ran npm run build alone: staleBuild cleared, staleDeps.stale stayed true.
  • Ran npm install across the four workspaces: staleDeps.stale cleared and staleBuild returned
    to true, because the install rewrote client/package.json. Rebuilding after the install cleared
    both, which is the order the new section prescribes.
  • Confirmed the running server executes the checked-out branch rather than main: with the same
    tree on disk, main's copy of installState.js computed staleBuild: true while the branch's
    computed false, and the live status endpoint agreed with the branch. getInstallState() has no
    cache and updateChecker.js:284 calls it per request, so the reading is live.
  • No docs linter exists in package.json; this is a prose-only change to one file.

The branch-and-rebase workflow for fork users lived only in the UpdateTab
fork panel, which renders only when `isFork` is true and which a fork user
sees only if they open that tab. SELF_UPDATE.md covered the update mechanism
(pull, the switch to main, pre-checkout stashing) but never the workflow it
implies.

Writes the loop out under a new "Running a customized fork" section: keep
main a clean mirror, private work on a branch, rebase after each sync, and
then reinstall, rebuild and restart, which update.sh cannot do because it
always finishes on main. Notes that install order matters, since npm install
rewrites client/package.json and re-stales an earlier build.

Also documents a confusing side effect nobody had written down: a clean
rebase rewinds and rolls forward the working tree, so every touched file
gets a new mtime and getInstallState reports a stale build plus stale deps
in all four workspaces even though no dependency changed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@atomantic atomantic left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Changes requested

The new section is accurate, well scoped, and correctly placed after "Fork UI: three distinct buttons". One blocking problem: the prescribed install command uses bare npm install, which contradicts the repo's own install path and can dirty tracked lockfiles.

Scope: docs-only — a docs/README.md index row plus a new "Running a customized fork" section in docs/SELF_UPDATE.md

⛔ Blocking (1)

  • docs/SELF_UPDATE.md:108 — Bare npm install contradicts the repo's own install path

💡 Non-blocking (2)

  • docs/SELF_UPDATE.md:112 — Ordering rationale is downstream of the line 108 fix
  • docs/SELF_UPDATE.md:106./update.sh drops Windows; every other mention in this file pairs the two

Test evidence

  • git apply --check (full patch) — the docs/README.md hunk no longer applies against base c88fb24 — a MANAGED_APP_UPDATES.md row landed between the SELF_UPDATE.md and DEPS.md rows after this branch was cut. Pure context drift, so a rebase is required
  • git apply --check --include=docs/SELF_UPDATE.md — applies cleanly; --include=docs/README.md is the only failing half
  • ⏭️ npx vitest — the disposable review worktree has no node_modules in root/client/server and the stage forbids package downloads, so the attempt was refused at the registry

Notes

  • No docs-index or markdown-link guard test exists under scripts/ or server/ that this change would exercise, so the untested surface is prose only — verification here was by reading the applied section against the code it describes.
  • The docs/README.md hunk needs a rebase before this can merge. That is context drift from a change that landed after the branch was cut, not an authoring error.
Claims verified against the code
  • update.sh always ends on main — it force-checks-out main and then installs, builds, and restarts there (update.sh:132-143)
  • npm run build and npm run pm2:restart exist (package.json:18, package.json:22)
  • getInstallState() lives in server/services/installState.js and is mtime-based
  • DEP_WORKSPACES = ['.', 'client', 'server', 'autofixer'] renders . as root, matching the "all four workspaces" claim, and manifest-newer is a real reason string (server/services/installState.js:46,174)
  • client/package.json genuinely is a staleBuild input — isClientSourceNewer() stats every file directly under client/ (server/services/installState.js:118-135), so the install-then-build ordering claim is mechanically correct
  • gh repo sync fast-forward and the 409 FORK_DIVERGED response match server/routes/update.js:179 and the existing docs/SELF_UPDATE.md:74
  • the UpdateTab fork tip the section references exists (UpdateTab.jsx:444)

Comment thread docs/SELF_UPDATE.md
```bash
git checkout main && ./update.sh
git checkout <your-branch> && git rebase main
for d in . client server autofixer; do (cd "$d" && npm install); done

@atomantic atomantic Sep 3, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking — Bare npm install contradicts the repo's own install path

PortOS's install path deliberately uses npm install --no-save in all four of these workspaces — update.sh:96 and :102, update.ps1:137 and :144 — with an in-tree comment stating why: "This is an installation/reconciliation path, not dependency authoring. --no-save still honors package-lock.json but prevents older npm versions from rewriting newer lockfile metadata (for example libc fields)."

All four lockfiles are tracked in git (package-lock.json, client/, server/, autofixer/), so a fork user who copy-pastes this line can have npm rewrite tracked lockfiles on their private branch. The wrong outcome is exactly the friction this section exists to prevent: on the next cycle git checkout main && ./update.sh finds a dirty tree, stashes it (update.sh:132-143), and hands the user back a git checkout <branch> && git stash pop recovery step — and the rebase now carries lockfile churn the branch never intended.

Suggested change
for d in . client server autofixer; do (cd "$d" && npm install); done
for d in . client server autofixer; do (cd "$d" && npm install --no-save); done

Comment thread docs/SELF_UPDATE.md
npm run build && npm run pm2:restart
```

Order matters. `npm install` rewrites `client/package.json`, so building before installing leaves

@atomantic atomantic Sep 3, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Non-blocking — Ordering rationale is downstream of the line 108 fix

npm install --no-save does not write client/package.json, so once the command above uses --no-save the stated cause ("npm install rewrites client/package.json") no longer holds and this paragraph documents a mechanism the prescribed command no longer triggers.

The install-before-build order is still worth keeping — a dependency change must land before the bundle is built — so restate the reason rather than deleting it. Tying it to the reinstall touching build inputs under client/ generally, which isClientSourceNewer() (server/services/installState.js:118-135) stats wholesale, keeps the paragraph true either way.

Comment thread docs/SELF_UPDATE.md
`update.sh` always finishes on `main`, so it cannot do this half for you:

```bash
git checkout main && ./update.sh

@atomantic atomantic Sep 3, 2026

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Non-blocking./update.sh drops Windows; every other mention in this file pairs the two

Line 5 (update.sh / update.ps1), line 19, and line 47 all name both, and update.ps1 implements the identical flow — so a Windows fork user copy-pasting ./update.sh gets nothing.

Prefer the cross-platform entry point the root manifest already provides: npm run update (package.json:44) dispatches to update.ps1 on win32 and update.sh elsewhere. Otherwise mirror this file's existing convention and write ./update.sh / update.ps1. The prose on line 103 has the same omission.

Suggested change
git checkout main && ./update.sh
git checkout main && npm run update

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants