538b1745d4
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, andd807dd3(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.
154 lines
7.5 KiB
Markdown
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 |
|