Pipeline (3 operator asks): - bump-release.sh: canonical orchestrator (forks + sources + external) - upgrade-forks.sh --to=<tag>: rebase forks with diverged-mode guard - bump-graphics-recipes.sh: map-driven group-aware graphics bumps - check-external-versions.sh: drift checker for Qt6/KF6/Plasma/Mesa/Wayland - refresh-fork-upstream-map.sh: append-only map updater with --check - post-checkout-version-sync.sh + install-git-hooks.sh: opt-in branch hook - external_version_lib.py: shared version-parsing/bumping library - external-upstream-map.toml: ~80 external package entries - bump-fork.sh: deprecated (REDBEAR_I_KNOW_BUMP_FORK_IS_DEPRECATED=1) - RELEASE-BUMP-WORKFLOW.md: operator runbook Quality fixes (8 defects from two independent audits): - blake2b stable cache keys (was hash(), non-portable) - atomic cache writes via os.replace - version_sort_key pre-release demotion (was sorting after finals) - apply_ver_transform re.error tolerance - grep || true (pipefail abort) - cd failure detection in upgrade-forks - sed URL escape (injection hardening) - refresh-fork-upstream-map last-row drop fix Doc cleanup: - Archive 5 obsolete plans to local/docs/archived/ - Remove 14 stale/superseded docs - Update 18 docs to reference bump-release.sh and fix inbound links - TOOLS.md drift fixes
9.0 KiB
Red Bear OS — Optional Git Hooks
This directory documents the git hooks that operators can install for Red Bear OS. Per AGENTS.md "absolutely NEVER DELETE, NEVER IGNORE" rule, hooks are always opt-in — operators explicitly choose to install them. No hook is auto-installed.
Available hooks (2026-07-18, Phase 4.5 + release-bump pipeline)
post-checkout-version-sync.sh (release-bump automation, opt-in)
File: local/scripts/post-checkout-version-sync.sh
Purpose: When an operator switches to a release branch whose name is an
anchored semver (e.g. 0.3.1 → 0.3.2), automatically synchronise every
Cat 1 (in-house) and Cat 2 (upstream fork) crate version label to match the
new branch. This is the label-only half of a release bump — it rewrites
the version = "..." fields via sync-versions.sh --no-regen and does
nothing else. Source upgrades and lockfile regen remain explicit operator
steps (see local/docs/RELEASE-BUMP-WORKFLOW.md).
Exact guards (any fail → silent exit 0, no mutations):
$3 == 1— branch checkouts only (file checkouts are skipped).- New branch name matches
^[0-9]+\.[0-9]+\.[0-9]+$— silently skipsmaster,submodule/*,recovered/*, and detached HEAD. - No in-progress rebase / cherry-pick / merge (
.git/rebase-merge,.git/rebase-apply,.git/CHERRY_PICK_HEAD,.git/MERGE_HEADall absent). REDBEAR_NO_AUTO_SYNCenv var unset.- Working tree clean (
git status --porcelainempty) — else warns to stderr and skips.
What this hook NEVER does:
- No network access (no
git fetch, no upstream lookups). - No git mutations (no commit, no branch, no push, no stash).
- No lockfile regen (never calls
sync-versions.sh --regen). - No source upgrades (never rebases forks or touches
local/sources/*/). - Does not run on non-semver branches.
- Does not run on a dirty working tree.
- Never blocks a checkout — always exits 0, even on internal failure.
Action when all guards pass: reads the repo-root Cargo.toml
[package] version. If it differs from the branch version, runs
sync-versions.sh --no-regen (labels only) and prints the follow-up hint
pointing the operator at the explicit source-upgrade and lockfile-regen
commands. If already synced, exits silently.
Install (operator opt-in — NEVER auto-installed):
# Via the installer (preferred):
./local/scripts/install-git-hooks.sh # post-checkout only
./local/scripts/install-git-hooks.sh --all # + pre-push + commit-msg
# Or manually:
cp local/scripts/post-checkout-version-sync.sh .git/hooks/post-checkout
chmod +x .git/hooks/post-checkout
Bypass for a single checkout:
REDBEAR_NO_AUTO_SYNC=1 git checkout 0.3.2
pre-push-checks.sh (recommended for serious operators)
File: local/scripts/pre-push-checks.sh
Purpose: Run 7 pre-flight checks (4 core + 3 audit checks) before every
git push. Closes the "silent drift" gap identified in AGENTS.md
"Daily-upstream-safe workflow".
Checks:
sync-versions.sh --check— Cat 0 + Cat 1 + Cat 2 versionsverify-fork-versions.sh— Cat 2 fork supremacy + content checkverify-patch-content.py— no orphan patches inlocal/patches/verify-patch-content.py --report action— orphan-patch operator decisionsverify-patch-content.py --selftest— orphan-patch detector self-testverify-collision-detection.py— no config-vs-package conflictsverify-collision-detection.py --selftest— collision detector self-test
Install:
cp local/scripts/pre-push-checks.sh .git/hooks/pre-push
chmod +x .git/hooks/pre-push
# Or via the installer:
./local/scripts/install-git-hooks.sh --all
Bypass:
REDBEAR_SKIP_PRE_PUSH=1 git push(env var)git push --no-verify(standard git bypass)- Run with
--softfor warn-only mode
Why not pre-commit? Pre-push is preferred because:
- Pre-commit would block every local commit (even non-bump commits)
- Pre-push is the right safety boundary: "before I share work with origin"
- Operators committing 5x/hour to a feature branch don't need every commit to re-verify 4 checks; they need it on push
Future hooks (Phase 4.5+ forward work)
- pre-receive on the server — gitea can run a server-side hook that re-verifies every push. Combined with the client-side pre-push, this is defense in depth. Implementation requires gitea admin permission; operator-only.
- commit-msg hook — auto-prefix commit messages with Phase ID
(e.g.,
phase 4.5: ...) so future audits can group by phase. Optional, helps with audit doc generation.
How hooks relate to AGENTS.md
AGENTS.md "Daily-upstream-safe workflow" says:
"we can sources are provisioned via provision-release.sh and archived in sources/redbear-/ build successfully."
This means: before any fork-upstream sync, validate the state. The pre-push hook is the operator-side implementation of that check — it runs the same 4 checks that build-preflight.sh runs at build time, but on the operator's local repository state.
Why hooks are opt-in
Per AGENTS.md "absolutely NEVER DELETE, NEVER IGNORE" rule:
- Hooks can interfere with operator workflows (false positives block pushes)
- Some operators prefer manual run of pre-push-checks.sh
- Local hooks do not propagate (each clone must re-install)
- Some operators have multiple clones (different operator workstations)
The opt-in nature respects operator autonomy. The hook is provided
in local/scripts/ so operators can opt in by copying it to
.git/hooks/pre-push.
Audit
This directory was created in Phase 4.5 (Round 5) and extended in the release-bump pipeline (2026-07-18). The current hook inventory is:
| Hook | File | Function |
|---|---|---|
| post-checkout | local/scripts/post-checkout-version-sync.sh |
Auto-sync Cat 1+2 version labels on semver branch switch (label-only, no regen) |
| pre-push | local/scripts/pre-push-checks.sh |
Runs 7 pre-flight checks before push |
| commit-msg | local/scripts/commit-msg |
Auto-prepends phase X.Y: to commit messages |
| (server-side) | (gitea admin only) | Pre-receive — defense in depth; not yet implemented |
Installer (install-git-hooks.sh)
All three hooks are opt-in and can be installed individually with cp
(see each section above) or in one shot via the installer:
./local/scripts/install-git-hooks.sh # post-checkout only (default)
./local/scripts/install-git-hooks.sh --all # post-checkout + pre-push + commit-msg
./local/scripts/install-git-hooks.sh --uninstall # remove default set (restores .bak if present)
./local/scripts/install-git-hooks.sh --uninstall --all
The installer is idempotent: if a hook is already up to date it reports so
and does nothing; if an existing hook differs it backs the old one up to
<name>.bak (rotating older backups to <name>.bak.1, .2, …) before
overwriting. --uninstall reverses an install and restores the most recent
backup if one exists.
Full Tool Inventory (Round 14)
The build system has grown organically across 9+ rounds. Here is the complete tool inventory for reference.
| Tool | Type | Purpose | Modes |
|---|---|---|---|
patch-status.sh |
shell | Top-level consolidated report | --brief, --json |
sync-versions.sh |
shell | Cat 0+1+2 version sync + lockfile regen | --check, --regen, --dry-run, --no-regen, --regen-only |
verify-patch-content.sh |
shell↦py | Orphan patch detection | --strict, --report action|detail, --selftest |
verify-fork-versions.sh |
shell | Cat 2 fork supremacy check | diverged mode; REDBEAR_STRICT_DIVERGED_CHECK=1 |
verify-collision-detection.py |
python | Config files vs installs/files collision | --strict, --selftest (8 cases) |
pre-push-checks.sh |
shell | 7-check pre-push safety net | --soft for warn-only |
push-fork-branches.sh |
shell | Operator-reviewed fork push | --execute for actual push (default=print-only) |
unblock-base-push.sh |
shell | Base fork deadlock resolver | path-a, path-b, path-c for 3 operator paths |
commit-msg |
shell | Auto-phase-prefix hook | opt-in; install to .git/hooks/commit-msg |
build-preflight.sh |
shell | Build-time validation | Called by build-redbear.sh |
bump-release.sh |
shell | Canonical release-bump orchestrator | --with-sources, --with-external, --check, --dry-run |
check-external-versions.sh |
shell↦py | External desktop-stack version reporter | --strict, --no-fetch, --json |
bump-graphics-recipes.sh |
shell↦py | Map-driven external source bumper | --dry-run, --no-fetch |
post-checkout-version-sync.sh |
shell | Auto label-sync on semver branch switch | opt-in hook; bypass via REDBEAR_NO_AUTO_SYNC=1 |
install-git-hooks.sh |
shell | Idempotent opt-in hook installer | --all, --uninstall |
All scripts are under local/scripts/ and are designed to be
operator-friendly. Hooks are strictly opt-in per AGENTS.md
"absolutely NEVER DELETE, NEVER IGNORE" rule.