Files
RedBear-OS/local/docs/FORK-BUMP-PATCHING-POLICY.md
T
vasilito 538b1745d4 policy: document delicate patching during version and toolchain bumps
New local/docs/FORK-BUMP-PATCHING-POLICY.md, wired into AGENTS.md,
local/AGENTS.md and docs/README.md. Core rule: a version bump is a
REBASE, never a REPLACEMENT.

Written from the libredox 0.1.19 incident, which hit three failures at
once -- wholesale replacement that dropped the acpi re-export,
F_DUPFD_CLOEXEC, the mandated authors entry and the Single-Repo
repository URL; a version-named branch that also tripped the build's
fork-branch gate; and a stale fork-upstream-map.toml that failed
verify-fork-versions.sh with a fake-label violation. Covers the vendored
recipe-fork mirror image (metadata moves, build input does not -- how Qt
shipped 6.11.0 against a 6.11.1 recipe), patch handling during a bump,
and toolchain bumps as version bumps.

Also fixes the two bookkeeping gaps that failed this build:

- local/fork-upstream-map.toml: libredox 0.1.18 -> 0.1.19, never updated
  when the fork was bumped.
- verify-fork-versions.sh: record redoxfs's legitimate divergence in the
  declarative allowlist the script already provides for libredox, with
  the originating commit for each file -- a936d00 (Red Bear, Vec from
  alloc for no_std bootloader builds) for filesystem.rs and record.rs,
  852a971 (Red Bear, RecvFd EOPNOTSUPP) for mount/redox/mod.rs, and
  d807dd3 (upstream symlink fix imported ahead of the 0.9.1 tag) for
  mount/redox/scheme.rs. Documented rather than bypassed with
  REDBEAR_SKIP_FORK_VERIFY.
2026-08-03 13:12:47 +03:00

154 lines
7.5 KiB
Markdown

# Delicate Patching During a Version Bump (ABSOLUTE)
**Status:** ABSOLUTE — do not violate.
**Established:** 2026-08-03, after the libredox 0.1.19 bump silently dropped
committed fork work and left the upstream map stale.
**Scope:** every Cat 2 fork under `local/sources/`, every vendored recipe fork
under `local/recipes/<name>/source/`, and every patch in `local/patches/`.
Related: `LOCAL-FORK-SUPREMACY-POLICY.md`, `PATCH-GOVERNANCE.md`,
`RELEASE-BUMP-WORKFLOW.md`, `VERSIONING.md`,
`local/AGENTS.md` § "No-fake-version-label rule".
---
## The core rule
> **A version bump is a REBASE, never a REPLACEMENT.**
>
> Moving a fork to a newer upstream means taking upstream's new commits *onto*
> the fork. It never means taking upstream's tree and re-adding whatever
> Red Bear work you happen to remember.
Everything below follows from that one sentence.
## Why this exists — the libredox 0.1.19 incident
`local/sources/libredox` was moved from upstream 0.1.18 to 0.1.19 on a branch
named `bump-0.1.19`. Three separate policy failures compounded:
1. **Wholesale replacement lost committed work.** The bump rebuilt the fork
from upstream 0.1.19 and re-applied only *some* Red Bear commits. Silently
dropped:
- the `redox_syscall`-gated `pub mod acpi` re-export of `AcpiVerb`,
- `F_DUPFD_CLOEXEC`,
- the `vasilito` entry in `authors`, which `local/AGENTS.md` §
"Fork authorship attribution" **requires**,
- `repository = "https://gitea.redbearos.org/vasilito/RedBear-OS"`, which
the **Single-Repo Rule** requires.
This is the exact failure mode `local/AGENTS.md` documents for the
deprecated `bump-fork.sh`, which is why that tool is guarded.
2. **A stray version-named branch.** `bump-0.1.19` violates
`local/AGENTS.md` § BRANCH AND SUBMODULE POLICY ("create a branch named
after a version — this is a **policy violation**"). It also tripped the
build's fork-branch gate, so nothing could be built at all.
3. **Bookkeeping was left behind.** `local/fork-upstream-map.toml` still said
`0.1.18` while `Cargo.toml` said `0.1.19+rb0.3.2`, so
`verify-fork-versions.sh` failed the build with a fake-label violation.
The correct resolution was to **merge upstream 0.1.19 into
`submodule/libredox`**, which kept every Red Bear change and gained upstream's
multiple-fds work, then update the map.
## Mandatory sequence for bumping a Cat 2 fork
Use `local/scripts/bump-release.sh` (see `RELEASE-BUMP-WORKFLOW.md`); it
automates most of this. When doing it by hand, all of it applies.
1. **Work on the canonical branch.** `submodule/<name>`, never a new branch.
A version is not a branch name — it is a `Cargo.toml` field.
2. **Inventory the fork's own commits first.**
```bash
git -C local/sources/<fork> log --oneline <upstream-tag>..HEAD
```
Every one of those commits must still be represented afterwards.
3. **Rebase or merge onto the new upstream tag.** Prefer
`upgrade-forks.sh --to=<tag>`. A conflict is information, not an obstacle —
resolving it is how fork work gets carried forward. Taking upstream's side
in a conflict is correct only when upstream *rewrote* that code
("Red Bear adapts to upstream"); it is never correct as a bulk shortcut.
4. **Diff the result against the old fork tip, ignoring comments:**
```bash
git diff <old-fork-tip> HEAD -- <paths> | grep -E '^[+-]' \
| grep -vE '^[+-][+-]' | grep -vE '^[+-]\s*(//|$)'
```
Anything that disappears here is lost work. Put it back.
5. **Re-check the policy-mandated `Cargo.toml` fields**, which wholesale
replacement always clobbers because they come from upstream:
- `authors` must still list every Red Bear contributor,
- `repository` must still be the Gitea URL,
- `version` must be `<new-upstream>+rb<branch>` — `+rb`, never `-rb`.
6. **Update `local/fork-upstream-map.toml` in the same commit.** A fork whose
`Cargo.toml` and map disagree is a fake label and fails the build.
7. **Account for divergence.** After a bump, `verify-fork-versions.sh` compares
content against the upstream tag. Every diverging file must be explained by
either a patch in `local/patches/<fork>/` or an entry in the script's
per-fork declarative allowlist, **with a comment naming the commit and why**.
Do not reach for `REDBEAR_SKIP_FORK_VERIFY=1` — that hides the very drift
the check exists to catch.
8. **Type-check before committing:**
```bash
cargo check --target x86_64-unknown-redox --offline
```
9. **Bump the parent gitlink** and say in the message what moved and why.
10. **Delete the stray branch** if one was created, after confirming its
content is reachable elsewhere (`git branch -a --contains <sha>`).
## Vendored recipe forks (`local/recipes/<name>/source/`)
Same principle, different machinery — see `VERSIONING.md`. `recipe.toml` is the
source of truth; `source.tar`, `source/`, and `.redbear-src-version` are derived
and must be re-derived by `sync-recipe-source.sh`, never hand-edited to match.
The failure mode here is the mirror image: the metadata moves and the **build
input does not**. A `tar=` bump that never propagates into the vendored
`source/` silently keeps compiling the old version — that is how Qt shipped
6.11.0 while the recipe declared 6.11.1, and KDE built 6.10.0 against recipes
declaring 6.28.0.
`PATCH-REJECT` / `SHIM-REJECT` from the sync engine means **re-port by hand onto
the new upstream**. It never means freeze at the old version, and never means
apply with fuzz.
## Patches during a bump
- **Never delete a patch to make a bump apply.** Rebase it.
(`PATCH-GOVERNANCE.md` § 1 — this rule exists because an agent once deleted
8 patches and 9 BINS entries and destroyed a day of driver work.)
- **A patch that no longer applies is a question, not a verdict.** Run the
orphan-patch decision tree in `AGENTS.md` § "Orphan-Patch Supersession
Decision Tree" before concluding anything: superseded, integrated elsewhere,
or a genuine gap.
- **Never apply with fuzz to force a bump through.** The build uses `--fuzz=0`
deliberately.
- **Re-validate after reordering**, since patches carry line-number context:
remove `source/`, re-fetch, rebuild.
## Toolchain bumps are version bumps too
A compiler upgrade changes the *inputs* to every package even though no recipe
version moves, and the content-hash cache does **not** track the toolchain — so
a stale cache will happily serve objects built by the previous compiler.
- Rebuild with `--no-cache` after a toolchain swap.
- Expect default-language-standard changes. GCC 13→16 moved the default C
dialect from gnu17 to gnu23, where an empty parameter list means "no
arguments" instead of "unspecified" — see `PACKAGE-BUILD-QUIRKS.md`.
- Version-glob toolchain paths in build files. `mk/prefix.mk` hardcoded
`13.2.0` in a `rm`, which silently no-ops after an upgrade and leaves a
conflicting `limits.h` behind.
## Red flags — stop and re-read this document
| Symptom | What it usually means |
|---|---|
| `ERROR: <fork> Cargo.toml declares version=X but the upstream map has it tracking Y` | Step 6 skipped |
| `ERROR: <fork> has files that diverge from upstream <tag>` | Step 7 skipped — divergence undocumented |
| `REFUSING TO BUILD — FORKS NOT ON CANONICAL BRANCHES` | A stray branch was created (step 1) |
| A fork's `authors` lost its Red Bear entries | Wholesale replacement (step 5) |
| A bump commit whose only change is the version field | Fake label — no real rebase happened |
| Reaching for `REDBEAR_SKIP_FORK_VERIFY=1` | The check is right and the bump is wrong |