Files
RedBear-OS/local/docs/HOOKS.md
T
vasilito 99e5641127 feat: release-bump pipeline + external graphics version sync
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
2026-07-18 14:45:41 +09:00

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.10.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):

  1. $3 == 1 — branch checkouts only (file checkouts are skipped).
  2. New branch name matches ^[0-9]+\.[0-9]+\.[0-9]+$ — silently skips master, submodule/*, recovered/*, and detached HEAD.
  3. No in-progress rebase / cherry-pick / merge (.git/rebase-merge, .git/rebase-apply, .git/CHERRY_PICK_HEAD, .git/MERGE_HEAD all absent).
  4. REDBEAR_NO_AUTO_SYNC env var unset.
  5. Working tree clean (git status --porcelain empty) — 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

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:

  1. sync-versions.sh --check — Cat 0 + Cat 1 + Cat 2 versions
  2. verify-fork-versions.sh — Cat 2 fork supremacy + content check
  3. verify-patch-content.py — no orphan patches in local/patches/
  4. verify-patch-content.py --report action — orphan-patch operator decisions
  5. verify-patch-content.py --selftest — orphan-patch detector self-test
  6. verify-collision-detection.py — no config-vs-package conflicts
  7. verify-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 --soft for 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.