Skip to content
workspaceguardrails
  • Home
  • Open Source[4]
  • System Policies[0]
  • Git Hooks[21]
  • Anti-Patterns[293]
  • Hook Configs[20]
  • Sandbox Configs[27]
  • Tools & Scripts[14]
  • AI Governance[20]
  • LLM Gateway
  • Static Analysis
  • Playground
  • Integration Guide
  1. Home
  2. Tools & Scripts
    The Digital and AI Workspace Guardrails Platform2026 ◆ Independent AI Labs
    Skip to content
    workspaceguardrails
    • Home
    • Open Source[4]
    • System Policies[0]
    • Git Hooks[21]
    • Anti-Patterns[293]
    • Hook Configs[20]
    • Sandbox Configs[27]
    • Tools & Scripts[14]
    • AI Governance[20]
    • LLM Gateway
    • Static Analysis
    • Playground
    • Integration Guide
    1. Home
    2. Tools & Scripts
      The Digital and AI Workspace Guardrails Platform2026 ◆ Independent AI Labs
      Skip to content
      workspaceguardrails
      • Home
      • Open Source[4]
      • System Policies[0]
      • Git Hooks[21]
      • Anti-Patterns[293]
      • Hook Configs[20]
      • Sandbox Configs[27]
      • Tools & Scripts[14]
      • AI Governance[20]
      • LLM Gateway
      • Static Analysis
      • Playground
      • Integration Guide
      1. Home
      2. Tools & Scripts

        Tooling

        Scripts available in the workspace-ci repository for bootstrapping, auditing, and managing CI infrastructure across the workspace.

        14 of 14 scripts

        generate-hooks

        Generate native git hooks from .pre-commit-config.yaml.

        Hook Lifecycle
        Make target
        install-hooks

        generate-hooks

        scripts/generate-hooks

        generate-hooks: Generate native git hooks from .pre-commit-config.yaml. Replaces the pre-commit Python package with zero-dependency bash hooks. Usage: generate-hooks [--config PATH] [--output-dir PATH] [--dry-run]

        generate-hooks [--config PATH] [--output-dir PATH] [--dry-run]
        --config
        Path to .pre-commit-config.yaml (default: ./.pre-commit-config.yaml)
        --output-dir
        Directory to write hooks into (default: .git/hooks)
        --dry-run
        Print generated hooks to stdout without writing files

        Output: Writes executable bash scripts to .git/hooks/{pre-commit,commit-msg,pre-push}.

        #!/usr/bin/env bash
        # generate-hooks: Generate native git hooks from .pre-commit-config.yaml.
        # Replaces the pre-commit Python package with zero-dependency bash hooks.
        #
        # Usage: generate-hooks [--config PATH] [--output-dir PATH] [--dry-run]
        set -euo pipefail
        
        _SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
        _CI_ROOT="$(cd "$_SCRIPT_DIR/.." && pwd)"
        if ! source "$_CI_ROOT/lib/ci.sh"; then
            echo "ERROR: failed to source $_CI_ROOT/lib/ci.sh" >&2
            exit 2
        fi
        # checks_quality.sh provides ci_resolve_tier and ci_autocreate_project_enforcement.
        # Sourced here (not via checks.sh) so generate-hooks can run without the full
        # check-function surface: keeps the bootstrap minimal.
        if ! source "$_CI_ROOT/lib/checks_quality.sh"; then
            echo "ERROR: failed to source $_CI_ROOT/lib/checks_quality.sh" >&2
            exit 2
        fi
        
        # ── Defaults ──────────────────────────────────────────────────────────────
        _config=".pre-commit-config.yaml"
        _output_dir=""
        _dry_run=0
        
        while [[ $# -gt 0 ]]; do
            case "$1" in
                --config)     _config="$2"; shift 2 ;;
                --output-dir) _output_dir="$2"; shift 2 ;;
                --dry-run)    _dry_run=1; shift ;;
                -h|--help)
                    echo "Usage: generate-hooks [--config PATH] [--output-dir PATH] [--dry-run]"
                    echo ""
                    echo "Generate native git hooks from .pre-commit-config.yaml."
                    echo "Only repo:local / language:system hooks are supported."
                    exit 0
                    ;;
                *) ci_fail "Unknown option: $1"; exit 1 ;;
            esac
        done
        
        [[ -f "$_config" ]] || { ci_fail "Config not found: $_config"; exit 1; }
        
        # ── Best bash shebang ─────────────────────────────────────────────────────
        # Generated hooks source lib/ci.sh which uses `local -n` namerefs (bash 4.3+).
        # macOS ships bash 3.2 at /bin/bash, so prefer Homebrew bash 5.x when present.
        # Check /opt/homebrew (Apple Silicon) then /usr/local (Intel) then fall back.
        _ci_best_bash="#!/usr/bin/env bash"
        for _hb in /opt/homebrew/bin/bash /usr/local/bin/bash; do
            if [[ -x "$_hb" ]] && "$_hb" --version | grep -qE 'bash, version [5-9]\.'; then
                _ci_best_bash="#!$_hb"
                break
            fi
        done
        
        # ── Paths ─────────────────────────────────────────────────────────────────
        if [[ -z "$_output_dir" ]]; then
            _git_dir="$(git rev-parse --git-dir)" || { ci_fail "Not a git repo"; exit 1; }
            _output_dir="$_git_dir/hooks"
        fi
        [[ -d "$_output_dir" ]] || mkdir -p "$_output_dir"
        
        _repo_root="$(git rev-parse --show-toplevel)"
        _ci_rel="$(ci_relative_path "$_repo_root" "$_CI_ROOT")"
        
        # ── Tier resolution ───────────────────────────────────────────────────────
        # Resolve the workspace root by walking up from the CI dir. Then resolve
        # this consumer's tier via
        # the project_enforcement.yaml registry (autocreated from template if
        # missing).
        _workspace_root="$(cd "$_CI_ROOT/../.." && pwd)"
        _registry=""
        if [[ -d "$_workspace_root/$CI_BOOT_NAME" ]]; then
            _reg_rc=0
            _registry="$(ci_autocreate_project_enforcement "$_workspace_root")" || _reg_rc=$?
        fi
        _repo_rel=""
        if [[ "$_repo_root" == "$_workspace_root"* ]]; then
            _repo_rel="${_repo_root#"$_workspace_root"/}"
            [[ "$_repo_rel" == "$_repo_root" ]] && _repo_rel="."
        fi
        _tier="$(ci_resolve_tier "$_repo_rel" "$_registry")"
        
        if [[ "$_tier" == "vendored" ]]; then
            ci_info "Project tier=vendored: skipping hook installation."
            exit 0
        fi
        
        ci_info "Project tier=$_tier"
        
        # ── Parse config ──────────────────────────────────────────────────────────
        _hooks="$(awk -f "$_CI_ROOT/lib/parse_precommit_config.awk" "$_config")"
        if [[ -z "$_hooks" ]]; then
            ci_warn "No hooks found in $_config"
            exit 0
        fi
        
        # ── Helper: append line to temp file ──────────────────────────────────────
        _tmp=""
        w() { printf '%s\n' "$1" >> "$_tmp"; }
        
        # ── Generate each stage ──────────────────────────────────────────────────
        for _stage in pre-commit commit-msg pre-push; do
            _awk_rc=0
            _stage_hooks="$(printf '%s\n' "$_hooks" | awk -F'\034' -v s="$_stage" '$4 == s')" || _awk_rc=$?
            [[ -z "$_stage_hooks" ]] && continue
        
            _tmp="$(mktemp)"
        
            # ── Header ────────────────────────────────────────────────────────────
            cat > "$_tmp" << EOF
        ${_ci_best_bash}
        # AUTO-GENERATED by ${_ci_rel}/scripts/generate-hooks: do not edit.
        # Source: $_config | $(date -u +%Y-%m-%dT%H:%M:%SZ)
        # Re-generate: ${_ci_rel}/scripts/generate-hooks
        set -euo pipefail
        
        # Capability scrub (audit C5): the workspace guard loans ambient and
        # inheritable capabilities (CAP_DAC_OVERRIDE et al.) to git so it can
        # write root-owned .git trees. Without this scrub those caps propagate
        # into everything this hook spawns (pytest, node, repo scripts), letting
        # agent code rewrite root-owned hooks, projects/CI, and exemption files.
        # Re-exec once with inheritable and ambient caps cleared; git commands
        # run later re-acquire their own loan from the guard wrapper per call.
        if [[ -z "\${_CI_CAPS_SCRUBBED:-}" ]]; then
            if _setpriv="\$(command -v setpriv)"; then
                export _CI_CAPS_SCRUBBED=1
                exec setpriv --inh-caps=-all --ambient-caps=-all bash "\$0" "\$@"
            fi
        fi
        
        # PATH sanitize (hook-git resolution): git exports GIT_EXEC_PATH and prepends
        # its exec dir (/usr/lib/git-core) to PATH for hook children. That dir holds
        # the VANILLA distro git with no file capabilities: any 'git' resolved from
        # there bypasses the workspace guard, never receives the CAP_DAC_OVERRIDE
        # loan, and fails writing the root-owned .git tree (EACCES on
        # .git/index.lock) -- this broke check-unstaged's 'git add -A'. Filter the
        # exec-path entry out so every hook-spawned git resolves to the guard
        # wrapper (/usr/bin/git) and re-acquires the loan per call, at any depth.
        _git_exec_path="\$(command git --exec-path)"
        if [[ -n "\$_git_exec_path" ]]; then
            _sanitized_path=""
            _saved_ifs="\$IFS"
            IFS=':'
            for _p in \$PATH; do
                [[ "\$_p" == "\$_git_exec_path" ]] && continue
                _sanitized_path="\${_sanitized_path:+\$_sanitized_path:}\$_p"
            done
            IFS="\$_saved_ifs"
            export PATH="\$_sanitized_path"
        fi
        
        _ROOT="\$(git rev-parse --show-toplevel)"
        cd "\$_ROOT"
        if ! source "\${_ROOT}/${_ci_rel}/lib/ci.sh"; then
            echo "ERROR: failed to source \${_ROOT}/${_ci_rel}/lib/ci.sh" >&2
            exit 2
        fi
        # Prepend boot dirs discovered by the boot-path resolver.
        # ci_resolve_boot_path walks up from \$_ROOT, finds each \$CI_BOOT_NAME
        # dir (python-env/bin and bin), and accumulates them with
        # moon.yml::project.inherited_boot_dirs entries. The result is
        # prepended to \$PATH so hooks resolve tools from the nearest boot dir
        # first, walking up to workspace root.
        _boot_path="\$(ci_resolve_boot_path "\$_ROOT")"
        [[ -n "\$_boot_path" ]] && export PATH="\${_boot_path}:\$PATH"
        EOF
        
            # quality_exceptions.yaml preflight: ALWAYS enforced, all tiers.
            # Hard-fails the hook chain if the file is missing: the contract says
            # every project must have this file at its root, even if
            # exceptions: [] is empty. Runs at the very top of every hook so the
            # error is the first thing the user sees.
                w ''
            w '# === quality_exceptions.yaml preflight (mandatory) ==='
                w 'if [[ ! -f "$_ROOT/quality_exceptions.yaml" ]]; then'
                w '    ci_fail "quality_exceptions.yaml missing at $_ROOT"'
                w "    echo \"  Fix: copy \${_ROOT}/${_ci_rel}/templates/quality_exceptions.template.yaml\""
                w '    echo "       to $_ROOT/quality_exceptions.yaml and replace __PROJECT_NAME__."'
                w '    exit 1'
                w 'fi'
        
            # Exemption-file compliance: ALWAYS enforced, all tiers, every stage.
            # Hard-fails if any file listed in the CI canonical manifest
            # (config/exemption_files.yaml) is missing or not root-owned. The
            # marker comment lets check-required-hooks-present
            # verify this built-in block survived rendering.
                w ''
                w '# === exemption-file compliance (mandatory) ==='
                w '# CI-BUILTIN-EXEMPTION-COMPLIANCE'
                w '_exemptions_lib="$_ROOT/'"${_ci_rel}"'/lib/ci_exemptions.sh"'
                w '_exemptions_manifest="$_ROOT/'"${_ci_rel}"'/config/exemption_files.yaml"'
                w 'if [[ ! -f "$_exemptions_lib" || ! -f "$_exemptions_manifest" ]]; then'
                w '    ci_fail "CI exemption infrastructure missing (lib/ci_exemptions.sh or config/exemption_files.yaml)"'
                w '    exit 1'
                w 'fi'
                w 'if ! source "$_exemptions_lib"; then'
                w '    ci_fail "failed to source $_exemptions_lib"'
                w '    exit 1'
                w 'fi'
                w '_exemption_fail=0'
                w 'for _rel in $(sed -n "s/^  - path: //p" "$_exemptions_manifest"); do'
                w '    _exemption_state="$(ci_exemption_file_state "$_ROOT/$_rel")"'
                w '    if [[ "$_exemption_state" != "ok" ]]; then'
                w '        ci_fail "exemption file not compliant: $_rel (state: $_exemption_state)"'
                w '        _exemption_fail=1'
                w '    fi'
                w 'done'
                w 'if [[ "$_exemption_fail" -eq 1 ]]; then'
                w "    echo \"  Fix: files must be root-owned regular files; edit via 'sudo workspace-yaml-edit'\""
                w '    exit 1'
                w 'fi'
        
            # CI-repo catalog provenance: in the CI work repo itself (detected by
            # scripts/generate-hooks at the project root), EVERY config/*.yaml is
            # policy: catalogs and schemas included. Agent-owned catalogs are a
            # self-gate-weakening hole, so all of them must be root-owned regular
            # files, edited only via the root-gated yaml editor.
                w ''
                w '# === CI catalog provenance (CI repo only, mandatory) ==='
                w '# CI-BUILTIN-CATALOG-PROVENANCE'
                w 'if [[ -f "$_ROOT/scripts/generate-hooks" && -d "$_ROOT/config" ]]; then'
                w '    _catalog_fail=0'
                w '    for _catalog in "$_ROOT"/config/*.yaml; do'
                w '        [[ -e "$_catalog" ]] || continue'
                w '        _catalog_state="$(ci_exemption_file_state "$_catalog")"'
                w '        if [[ "$_catalog_state" != "ok" ]]; then'
                w '            ci_fail "CI catalog not compliant: ${_catalog#$_ROOT/} (state: $_catalog_state)"'
                w '            _catalog_fail=1'
                w '        fi'
                w '    done'
                w '    if [[ "$_catalog_fail" -eq 1 ]]; then'
                w "        echo \"  Fix: chown root:root config/*.yaml; edit via 'sudo workspace-yaml-edit'\""
                w '        exit 1'
                w '    fi'
                w 'fi'
        
            # Compliance-report preamble (pre-commit only, non-blocking).
            # Always runs the compliance audit at the top of every commit
            # so the developer sees the current tier/violations before the hook
            # chain proceeds. Never blocks: the report is advisory.
            if [[ "$_stage" == "pre-commit" ]]; then
                w ''
                w '# === CI compliance report (advisory, non-blocking) ==='
                w "_compliance_script=\"\${_ROOT}/${_ci_rel}/scripts/compliance-report\""
                w 'if [[ -x "$_compliance_script" ]]; then'
                w '    _compliance_rc=0'
                w '    _compliance_output="$("$_compliance_script" "$_ROOT" 2>&1)" || _compliance_rc=$?'
                w '    if echo "$_compliance_output" | grep -qE "^FAILED|violation\\(s\\)"; then'
                w '        printf "\\n\\033[0;31m═══ CI COMPLIANCE (advisory, does not block commit) ═══\\033[0m\\n"'
                w '        printf "\\033[0;31m%s\\033[0m\\n" "$_compliance_output"'
                w '        printf "\\033[0;31m═══════════════════════════════════════════════════════════\\033[0m\\n\\n"'
                w '    else'
                w '        printf "\\n\\033[0;32m═══ CI COMPLIANCE ═══\\033[0m\\n"'
                w '        printf "%s\\n\\n" "$_compliance_output"'
                w '    fi'
                w 'fi'
            fi
        
            # Staged files list (pre-commit only)
            if [[ "$_stage" == "pre-commit" ]]; then
                w ''
                w '_STAGED="$(git diff --cached --name-only --diff-filter=ACMR)"'
            fi
        
            # ── Emit each hook ────────────────────────────────────────────────────
            while IFS=$'\034' read -r h_id h_name h_entry h_stage h_pass_fn h_always h_files h_exclude h_args h_types_or; do
                [[ -z "$h_id" ]] && continue
                h_vid="${h_id//-/_}"
        
                # Full command = entry + args
                # Replace `bash -c` with `"$BASH" -c` so child shells use the same
                # bash as the hook's shebang (Homebrew bash 5.x on macOS), not the
                # system /bin/bash 3.2 which lacks nameref support.
                h_cmd="${h_entry//bash -c/\"\$BASH\" -c}"
                [[ -n "$h_args" ]] && h_cmd="$h_cmd $h_args"
        
                # If a hook has an empty entry (e.g. when .pre-commit-config.yaml
                # references an upstream pre-commit-hooks repo whose entries
                # this generator does not resolve), refuse to emit the hook.
                if [[ -z "${h_entry// /}" ]]; then
                    ci_fail "Hook '$h_id' has empty entry: cannot generate. \
        Possible causes: (a) the .pre-commit-config.yaml references an upstream \
        pre-commit-hooks repo this generator does not resolve; \
        (b) a YAML parse glitch dropped the entry. \
        Fix the config (move to a local 'repo: local' entry with a real entry: command) \
        and re-run."
                    exit 1
                fi
        
                # Convert types_or to a files regex (extension-based matching)
                if [[ -n "$h_types_or" ]]; then
                    _type_exts=()
                    for _type in $h_types_or; do
                        case "$_type" in
                            javascript) _type_exts+=('\.(js|mjs|cjs)$') ;;
                            jsx)        _type_exts+=('\.jsx$') ;;
                            ts)         _type_exts+=('\.(ts|mts|cts)$') ;;
                            tsx)        _type_exts+=('\.tsx$') ;;
                            css)        _type_exts+=('\.css$') ;;
                            json)       _type_exts+=('\.json$') ;;
                            markdown)   _type_exts+=('\.md$') ;;
                            yaml)       _type_exts+=('\.ya?ml$') ;;
                            python)     _type_exts+=('\.py$') ;;
                            rust)       _type_exts+=('\.rs$') ;;
                            toml)       _type_exts+=('\.toml$') ;;
                            *)          ci_warn "Hook $h_id: unknown type '$_type', skipping" ;;
                        esac
                    done
                    # Merge into a single alternation pattern
                    if [[ ${#_type_exts[@]} -gt 0 ]]; then
                        _types_pattern="$(IFS='|'; echo "${_type_exts[*]}")"
                        # If files is already set, combine with types (both must match)
                        if [[ -n "$h_files" ]]; then
                            h_files="(${h_files}).*(${_types_pattern})"
                        else
                            h_files="$_types_pattern"
                        fi
                    fi
                fi
        
                # Validate: regex patterns must not contain single quotes (breaks generated grep)
                if [[ "$h_files" == *"'"* || "$h_exclude" == *"'"* ]]; then
                    ci_fail "Hook $h_id: files/exclude patterns must not contain single quotes"
                    exit 1
                fi
        
                # Classify
                _is_formatter=0
                [[ "$h_id" == "ruff-format" || "$h_id" == "ruff" || "$h_id" == "ci-lint" ]] && _is_formatter=1
        
                _need_gate=0  # skip hook if no staged files match
                [[ -n "$h_files" && "$h_always" != "true" && "$_stage" == "pre-commit" ]] && _need_gate=1
        
                _need_pass=0  # pass staged filenames as arguments
                [[ "$h_pass_fn" == "true" && "$_stage" == "pre-commit" ]] && _need_pass=1
        
                w ''
                w "# === Hook: $h_id ==="
        
                # ── File matching (pre-commit only) ───────────────────────────────
                if [[ $_need_gate -eq 1 || $_need_pass -eq 1 ]]; then
                    if [[ -n "$h_files" ]]; then
                        w "_rc_${h_vid}=0"
                        w "_match=\"\$(echo \"\$_STAGED\" | grep -E '${h_files}')\" || _rc_${h_vid}=\$?"
                    else
                        w '_match="$_STAGED"'
                    fi
                    if [[ -n "$h_exclude" ]]; then
                        w "_rc_ex_${h_vid}=0"
                        w "_match=\"\$(echo \"\$_match\" | grep -vE '${h_exclude}')\" || _rc_ex_${h_vid}=\$?"
                    fi
                    w 'if [[ -n "$_match" ]]; then'
                fi
        
                w "ci_info \"Running: ${h_name}...\""
        
                # ── Execute ──────────────────────────────────────────────────────
                if [[ "$_stage" == "commit-msg" ]]; then
                    w "${h_cmd} \"\$1\" || { ci_fail \"$h_name\"; exit 1; }"
        
                elif [[ $_is_formatter -eq 1 ]]; then
                    w '_rc=0'
                    w "${h_cmd} || _rc=\$?"
                    w 'if [[ -n "$(git diff --stat)" ]]; then'
                    w '    git add -A'
                    w "    ci_fail \"${h_name} modified files. Re-run: git commit\""
                    w '    exit 1'
                    w 'fi'
                    w "[[ \$_rc -ne 0 ]] && { ci_fail \"$h_name\"; exit 1; }"
        
                elif [[ $_need_pass -eq 1 ]]; then
                    # shellcheck disable=SC2086
                    w "${h_cmd} \$_match || { ci_fail \"$h_name\"; exit 1; }"
        
                elif [[ "$h_id" == "check-boot-venv-layout" || "$h_id" == "check-dead-code" ]]; then
                    # Non-blocking advisory checks: rc-capture pattern.
                    # Failures are surfaced as warnings, never hard-fail.
                    w '_bl_rc=0'
                    w "${h_cmd} || _bl_rc=\$?"
                    w 'if [[ $_bl_rc -ne 0 ]]; then'
                    w "    ci_warn \"${h_name} failed (exit \$_bl_rc): non-blocking, continuing\""
                    w 'fi'
        
                else
                    w "${h_cmd} || { ci_fail \"$h_name\"; exit 1; }"
                fi
        
                # Close file gate
                if [[ $_need_gate -eq 1 || $_need_pass -eq 1 ]]; then
                    w 'fi'
                fi
        
            done <<< "$_stage_hooks"
        
            w ''
            w "ci_pass \"All $_stage hooks passed.\""
        
            # ── Output ────────────────────────────────────────────────────────────
            if [[ $_dry_run -eq 1 ]]; then
                echo ""
                ci_info "=== $_output_dir/$_stage ==="
                cat "$_tmp"
                rm -f "$_tmp"
            else
                # Hooks are root-owned by design: only root ever rewrites them.
                # Refuse with the root regeneration path instead of dying on the
                # EPERM from mv.
                if [[ -f "$_output_dir/$_stage" && ! -w "$_output_dir/$_stage" ]]; then
                    rm -f "$_tmp"
                    # -w fails for root too when the file carries chattr +i; tell the
                    # two cases apart so the message names the right fix command.
                    _attrs_rc=0
                    _attrs="$(lsattr "$_output_dir/$_stage")" || _attrs_rc=$?
                    if [[ $_attrs_rc -eq 0 && "${_attrs%% *}" == *i* ]]; then
                        ci_fail "hook $_stage is immutable (chattr +i). Clear it first: sudo chattr -i $_output_dir/$_stage"
                    else
                        ci_fail "hook $_stage is root-owned. Regenerate as root: sudo make -C projects/CI install-hooks CONSUMER=<repo>"
                    fi
                    exit 1
                fi
                mv "$_tmp" "$_output_dir/$_stage"
                chmod +x "$_output_dir/$_stage"
                ci_pass "Generated $_output_dir/$_stage"
            fi
        done
        
        if [[ $_dry_run -eq 0 ]]; then
            echo ""
            ci_pass "All hooks generated from $_config"
        fi
        

        Share feedback

        You voted thumbs down

        cleanup-precommit

        Remove all traces of the pre-commit Python package (keeps .pre-commit-config.yaml).

        Hook Lifecycle

        cleanup-precommit

        scripts/cleanup-precommit

        cleanup-precommit: Remove all traces of the pre-commit Python package. Does NOT remove .pre-commit-config.yaml by default (it's our config source). Usage: cleanup-precommit [--remove-config]

        cleanup-precommit [--remove-config]
        --remove-config
        Also delete .pre-commit-config.yaml (off by default: it's our config source)

        Output: Deletes pre-commit hooks, virtualenvs, and cache. Exits 0.

        #!/usr/bin/env bash
        # cleanup-precommit: Remove all traces of the pre-commit Python package.
        # Does NOT remove .pre-commit-config.yaml by default (it's our config source).
        #
        # Usage: cleanup-precommit [--remove-config]
        set -euo pipefail
        
        _SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
        _CI_ROOT="$(cd "$_SCRIPT_DIR/.." && pwd)"
        if ! source "$_CI_ROOT/lib/ci.sh"; then
            echo "ERROR: failed to source $_CI_ROOT/lib/ci.sh" >&2
            exit 2
        fi
        
        _remove_config=0
        [[ "${1:-}" == "--remove-config" ]] && _remove_config=1
        
        # Remove pre-commit cache
        if [[ -d "$HOME/.cache/pre-commit" ]]; then
            rm -rf "$HOME/.cache/pre-commit"
            ci_pass "Removed ~/.cache/pre-commit"
        else
            ci_info "No pre-commit cache found"
        fi
        
        # Remove old hook backup
        if [[ -f ".git/hooks/pre-commit.legacy" ]]; then
            rm -f ".git/hooks/pre-commit.legacy"
            ci_pass "Removed .git/hooks/pre-commit.legacy"
        fi
        
        # Uninstall pre-commit package via hermetic boot-dir uv only; never
        # ambient system binaries. uv resolves the project venv itself when run
        # from the project root.
        _uv="$(ci_uv_bin)" || exit 1
        if (cd "$CI_PROJECT_ROOT" && env -u VIRTUAL_ENV "$_uv" pip uninstall pre-commit); then
            ci_pass "Uninstalled pre-commit (uv, project venv)"
        else
            ci_info "pre-commit not installed in project venv (or no venv yet)"
        fi
        
        # Optionally remove config
        if [[ $_remove_config -eq 1 ]]; then
            rm -f .pre-commit-config.yaml
            ci_pass "Removed .pre-commit-config.yaml"
        fi
        
        echo ""
        ci_info "NOTE: If pre-commit is in pyproject.toml dev dependencies, remove it manually."
        ci_pass "Pre-commit cleanup complete."
        

        Share feedback

        You voted thumbs down

        bootstrap-gitleaks

        Fetch the gitleaks binary and place it on PATH (idempotent, validated by SHA256).

        Bootstrap
        Make target
        install-gitleaks

        bootstrap-gitleaks

        scripts/bootstrap-gitleaks

        bootstrap-gitleaks: fetch the gitleaks binary and place it on PATH. This project depends on `gitleaks` for the pre-commit secret-content scanner. This script is idempotent: if a compatible binary is already present at the target path, it exits 0 without redownloading. Default install location: $CI_PROJECT_ROOT/$CI_BOOT_NAME/bin/gitleaks where $CI_BOOT_NAME is platform-aware (.boot-linux on Linux, .boot-macos on macOS), set at source-time by lib/ci.sh. Override with $GITLEAKS_BIN to drop somewhere else. Override the version with $GITLEAKS_VERSION (default below). CI_PROJECT_ROOT (this repo's own root) is delegated to lib/ci.sh. Per the boot contract, this script installs to CI's own boot dir: NOT the workspace root. Sibling repos reach this binary via the boot-path resolver (lib/ci.sh::ci_resolve_boot_path) which reads moon.yml::project.inherited_boot_dirs. See: docs/specifications/SPEC-BOOT-LAYOUT.md

        bootstrap-gitleaks

        Output: Installs gitleaks to $CI_PROJECT_ROOT/${boot_dir}/bin (boot_dir read from config/boot_layout.yaml; default .boot-linux) if absent/upgrade-needed; no-op otherwise.

        #!/usr/bin/env bash
        # bootstrap-gitleaks: fetch the gitleaks binary and place it on PATH.
        #
        # This project depends on `gitleaks` for the pre-commit secret-content scanner.
        # This script is idempotent: if a compatible binary is already present at the
        # target path, it exits 0 without redownloading.
        #
        # Default install location:
        #   $CI_PROJECT_ROOT/$CI_BOOT_NAME/bin/gitleaks
        # where $CI_BOOT_NAME is platform-aware (.boot-linux on Linux, .boot-macos
        # on macOS), set at source-time by lib/ci.sh.
        # Override with $GITLEAKS_BIN to drop somewhere else.
        #
        # Override the version with $GITLEAKS_VERSION (default below).
        #
        # CI_PROJECT_ROOT (this repo's own root) is delegated to lib/ci.sh. Per the
        # boot contract, this script installs to CI's own boot dir: NOT the
        # workspace root. Sibling repos reach this binary via the
        # boot-path resolver (lib/ci.sh::ci_resolve_boot_path) which reads
        # moon.yml::project.inherited_boot_dirs. See:
        #   docs/specifications/SPEC-BOOT-LAYOUT.md
        
        set -euo pipefail
        
        GITLEAKS_VERSION="${GITLEAKS_VERSION:-8.21.2}"
        #
        # Supply-chain pinning: SHA256 verification is MANDATORY and always on.
        # The checksum is fetched at runtime from the checksums.txt sidecar file
        # published alongside the tarballs on the GitHub release page. No hardcoded
        # hashes are used -- the sidecar is the trusted source of truth, fetched
        # from the same release origin as the tarball.
        
        _ci_lib="$(cd "$(dirname "${BASH_SOURCE[0]}")/../lib" && pwd)"
        # shellcheck source=lib/ci.sh
        if ! source "$_ci_lib/ci.sh"; then
            echo "ERROR: failed to source $_ci_lib/ci.sh" >&2
            exit 2
        fi
        if [[ -z "${CI_PROJECT_ROOT:-}" ]]; then
            echo "ERROR: CI_PROJECT_ROOT not set after sourcing ci.sh" >&2
            exit 2
        fi
        
        _log() { printf '[bootstrap-gitleaks] %s\n' "$*" >&2; }
        
        main() {
            local target_dir target arch tarball url
            target_dir="${CI_PROJECT_ROOT}/${CI_BOOT_NAME}/bin"
            target="${GITLEAKS_BIN:-${target_dir}/gitleaks}"
        
            if ! mkdir -p "$(dirname "$target")"; then
                _log "mkdir failed for $(dirname "$target")"
                return 1
            fi
        
            if [[ -x "$target" ]]; then
                local v_out v_err v_rc=0
                v_out="$(mktemp)"
                v_err="$(mktemp)"
                "$target" version >"$v_out" 2>"$v_err" || v_rc=$?
                if [[ "$v_rc" -eq 0 ]]; then
                    local cur
                    cur="$(head -1 "$v_out")"
                    rm -f "$v_out" "$v_err"
                    if [[ "$cur" == *"$GITLEAKS_VERSION"* ]]; then
                        _log "gitleaks ${GITLEAKS_VERSION} already at $target"
                        return 0
                    fi
                    _log "found existing gitleaks ($cur), upgrading to ${GITLEAKS_VERSION}"
                else
                    local err_msg
                    err_msg="$(head -1 "$v_err")"
                    rm -f "$v_out" "$v_err"
                    _log "existing binary at $target did not respond to 'version' (rc=$v_rc): $err_msg"
                    _log "re-downloading fresh copy"
                fi
            fi
        
            case "$(uname -m)" in
                x86_64|amd64)  arch="x64" ;;
                aarch64|arm64) arch="arm64" ;;
                *) _log "unsupported arch: $(uname -m)"; return 1 ;;
            esac
        
            case "$(uname -s)" in
                Linux) goos="linux" ;;
                Darwin) goos="darwin" ;;
                *) _log "unsupported platform: $(uname -s)"; return 1 ;;
            esac
        
            tarball="gitleaks_${GITLEAKS_VERSION}_${goos}_${arch}.tar.gz"
            url="https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/${tarball}"
        
            local tmp
            tmp="$(mktemp -d)"
            # Use ${tmp:-} so the trap is safe under `set -u` once `tmp` (a local)
            # goes out of scope after main() returns.
            # shellcheck disable=SC2064
            trap "rm -rf \"\${tmp:-$tmp}\"" EXIT
        
            _log "fetching ${url}"
            if ! curl -fsSL --retry 3 --retry-delay 2 -o "${tmp}/${tarball}" "$url"; then
                _log "curl failed for $url"
                return 1
            fi
        
            # Mandatory SHA256 verification: fetch the checksums.txt sidecar from
            # the same GitHub release URL as the tarball. The sidecar contains
            # lines of "<hash>  <filename>" -- we extract the line matching our
            # tarball name and compare the hash against sha256sum of the download.
            # No hardcoded hashes.
            local checksums_url="https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_checksums.txt"
            _log "fetching checksum sidecar: ${checksums_url}"
            local sha_rc=0
            curl -fsSL --retry 3 --retry-delay 2 -o "${tmp}/checksums.txt" "$checksums_url" || sha_rc=$?
            if [[ "$sha_rc" -ne 0 ]]; then
                _log "failed to fetch checksums sidecar (rc=$sha_rc): $checksums_url"
                _log "cannot verify tarball integrity without sidecar; refusing to install"
                return 1
            fi
        
            local expected_sha
            expected_sha="$(awk -v tb="$tarball" '$2 == tb {print $1}' "${tmp}/checksums.txt")"
            if [[ -z "$expected_sha" ]]; then
                _log "no checksum entry for $tarball in sidecar; refusing to install"
                return 1
            fi
        
            local actual_sha
            actual_sha="$(ci_sha256 "${tmp}/${tarball}")"
            if [[ "$actual_sha" != "$expected_sha" ]]; then
                _log "checksum mismatch: expected $expected_sha, got $actual_sha"
                return 1
            fi
            _log "checksum OK ($expected_sha)"
        
            _log "extracting ${tarball} to ${tmp}"
            if ! tar -xzf "${tmp}/${tarball}" -C "$tmp" gitleaks; then
                _log "tar extraction failed"
                return 1
            fi
            _log "installing gitleaks to ${target}"
            if ! install -m 0755 "${tmp}/gitleaks" "$target"; then
                _log "install (copy) failed to $target"
                return 1
            fi
        
            local v_out2 v_rc2=0
            v_out2="$(mktemp)"
            "$target" version >"$v_out2" 2>&1 || v_rc2=$?
            if [[ "$v_rc2" -ne 0 ]]; then
                _log "post-install verification failed: '$target version' returned rc=$v_rc2"
                rm -f "$v_out2"
                return 1
            fi
            _log "installed: $(head -1 "$v_out2") => $target"
            rm -f "$v_out2"
        }
        
        main "$@"

        Share feedback

        You voted thumbs down

        bootstrap-cloc

        Fetch the cloc single-file Perl script and place it on PATH (idempotent, SHA256-verified against a pinned hash).

        Bootstrap
        Make target
        install-cloc

        bootstrap-cloc

        scripts/bootstrap-cloc

        bootstrap-cloc: fetch the cloc single-file Perl script and place it on PATH. This project depends on `cloc` (Count Lines of Code) for the code-stats script. cloc is distributed as a single self-contained Perl script, so bootstrapping it is a download + checksum verify + drop into the boot bin dir. This script is idempotent: if a compatible binary is already present at the target path, it exits 0 without redownloading. Default install location: $CI_PROJECT_ROOT/$CI_BOOT_NAME/bin/cloc where $CI_BOOT_NAME is platform-aware (.boot-linux on Linux, .boot-macos on macOS), set at source-time by lib/ci.sh. Override with $CLOC_BIN to drop somewhere else. Override the version with $CLOC_VERSION (default below). Supply-chain pinning: SHA256 verification is MANDATORY and always on. Unlike gitleaks, cloc does NOT publish a checksums sidecar file alongside its release assets (verified via the GitHub releases API). The hash below is therefore hardcoded against the pinned CLOC_VERSION. Bumping the version requires recomputing the hash (sha256sum of the .pl asset). cloc is a Perl script; a working `perl` is a runtime dependency and is declared in config/system-deps.yaml. This script verifies perl presence before installing so the failure mode is obvious at bootstrap time. CI_PROJECT_ROOT (this repo's own root) is delegated to lib/ci.sh. Per the boot contract, this script installs to CI's OWN boot dir: NOT the workspace root. Sibling repos reach this binary via the boot-path resolver (lib/ci.sh::ci_resolve_boot_path) which reads moon.yml::project.inherited_boot_dirs. See: docs/specifications/SPEC-BOOT-LAYOUT.md

        bootstrap-cloc

        Output: Installs cloc to $CI_PROJECT_ROOT/${boot_dir}/bin/cloc (boot_dir read from config/boot_layout.yaml; default .boot-linux) if absent/upgrade-needed; no-op otherwise. cloc ships no checksum sidecar, so the hash is pinned in-script; perl presence is checked before install.

        #!/usr/bin/env bash
        # bootstrap-cloc: fetch the cloc single-file Perl script and place it on PATH.
        #
        # This project depends on `cloc` (Count Lines of Code) for the code-stats
        # script. cloc is distributed as a single self-contained Perl script, so
        # bootstrapping it is a download + checksum verify + drop into the boot bin
        # dir. This script is idempotent: if a compatible binary is already present
        # at the target path, it exits 0 without redownloading.
        #
        # Default install location:
        #   $CI_PROJECT_ROOT/$CI_BOOT_NAME/bin/cloc
        # where $CI_BOOT_NAME is platform-aware (.boot-linux on Linux, .boot-macos
        # on macOS), set at source-time by lib/ci.sh.
        # Override with $CLOC_BIN to drop somewhere else.
        #
        # Override the version with $CLOC_VERSION (default below).
        #
        # Supply-chain pinning: SHA256 verification is MANDATORY and always on.
        # Unlike gitleaks, cloc does NOT publish a checksums sidecar file alongside
        # its release assets (verified via the GitHub releases API). The hash below
        # is therefore hardcoded against the pinned CLOC_VERSION. Bumping the
        # version requires recomputing the hash (sha256sum of the .pl asset).
        #
        # cloc is a Perl script; a working `perl` is a runtime dependency and is
        # declared in config/system-deps.yaml. This script verifies perl presence
        # before installing so the failure mode is obvious at bootstrap time.
        #
        # CI_PROJECT_ROOT (this repo's own root) is delegated to lib/ci.sh. Per the
        # boot contract, this script installs to CI's OWN boot dir: NOT the
        # workspace root. Sibling repos reach this binary via the boot-path
        # resolver (lib/ci.sh::ci_resolve_boot_path) which reads
        # moon.yml::project.inherited_boot_dirs. See:
        #   docs/specifications/SPEC-BOOT-LAYOUT.md
        
        set -euo pipefail
        
        CLOC_VERSION="${CLOC_VERSION:-2.02}"
        # SHA256 of cloc-2.02.pl (759966 bytes), fetched from:
        #   https://github.com/AlDanial/cloc/releases/download/v2.02/cloc-2.02.pl
        # Recompute with: sha256sum <(curl -fsSL <url>)  when bumping CLOC_VERSION.
        CLOC_SHA256="373b4424acdf4bfb38e735a85c8a0e5731ee789e2fd95df2618d254cbdb7f355"
        
        _ci_lib="$(cd "$(dirname "${BASH_SOURCE[0]}")/../lib" && pwd)"
        # shellcheck source=lib/ci.sh
        if ! source "$_ci_lib/ci.sh"; then
            echo "ERROR: failed to source $_ci_lib/ci.sh" >&2
            exit 2
        fi
        if [[ -z "${CI_PROJECT_ROOT:-}" ]]; then
            echo "ERROR: CI_PROJECT_ROOT not set after sourcing ci.sh" >&2
            exit 2
        fi
        
        _log() { printf '[bootstrap-cloc] %s\n' "$*" >&2; }
        
        main() {
            local target_dir target
            target_dir="${CI_PROJECT_ROOT}/${CI_BOOT_NAME}/bin"
            target="${CLOC_BIN:-${target_dir}/cloc}"
        
            if ! mkdir -p "$(dirname "$target")"; then
                _log "mkdir failed for $(dirname "$target")"
                return 1
            fi
        
            # cloc is a Perl script: refuse to install without a working perl.
            local _perl_path=""
            if ! _perl_path="$(command -v perl 2>&1)"; then
                _log "perl not found on PATH; cloc is a Perl script and requires it"
                _log "install perl (declared in config/system-deps.yaml) then re-run"
                return 1
            fi
        
            if [[ -x "$target" ]]; then
                local v_out v_rc=0
                v_out="$(mktemp)"
                "$target" --version >"$v_out" 2>&1 || v_rc=$?
                if [[ "$v_rc" -eq 0 ]]; then
                    local cur
                    cur="$(head -1 "$v_out")"
                    rm -f "$v_out"
                    if [[ "$cur" == *"$CLOC_VERSION"* ]]; then
                        _log "cloc ${CLOC_VERSION} already at $target"
                        return 0
                    fi
                    _log "found existing cloc ($cur), upgrading to ${CLOC_VERSION}"
                else
                    rm -f "$v_out"
                    _log "existing binary at $target did not respond to '--version' (rc=$v_rc)"
                    _log "re-downloading fresh copy"
                fi
            fi
        
            local asset="cloc-${CLOC_VERSION}.pl"
            local url="https://github.com/AlDanial/cloc/releases/download/v${CLOC_VERSION}/${asset}"
        
            local tmp
            tmp="$(mktemp -d)"
            # shellcheck disable=SC2064
            trap "rm -rf \"\${tmp:-$tmp}\"" EXIT
        
            _log "fetching ${url}"
            if ! curl -fsSL --retry 3 --retry-delay 2 -o "${tmp}/${asset}" "$url"; then
                _log "curl failed for $url"
                return 1
            fi
        
            # Mandatory SHA256 verification against the pinned hash.
            local actual_sha
            actual_sha="$(ci_sha256 "${tmp}/${asset}")"
            if [[ "$actual_sha" != "$CLOC_SHA256" ]]; then
                _log "checksum mismatch: expected $CLOC_SHA256, got $actual_sha"
                _log "if you bumped CLOC_VERSION, recompute the hash (see script header)"
                return 1
            fi
            _log "checksum OK ($CLOC_SHA256)"
        
            _log "installing cloc to ${target}"
            if ! install -m 0755 "${tmp}/${asset}" "$target"; then
                _log "install (copy) failed to $target"
                return 1
            fi
        
            local v_out2 v_rc2=0
            v_out2="$(mktemp)"
            "$target" --version >"$v_out2" 2>&1 || v_rc2=$?
            if [[ "$v_rc2" -ne 0 ]]; then
                _log "post-install verification failed: '$target --version' returned rc=$v_rc2"
                rm -f "$v_out2"
                return 1
            fi
            _log "installed: $(head -1 "$v_out2") => $target"
            rm -f "$v_out2"
        }
        
        main "$@"
        

        Share feedback

        You voted thumbs down

        bootstrap-uv

        Fetch the uv binary and place it on PATH (idempotent; SHA256 opt-in via UV_VERIFY_SHA256=1).

        Bootstrap

        bootstrap-uv

        scripts/bootstrap-uv

        bootstrap-uv: fetch the uv binary and place it on PATH. This project uses `uv` for dependency management (uv sync -> per-repo .venv/) and for cross-project Python invocation (uv run --project). This script is idempotent: if a compatible binary is already present at the target path, it exits 0 without redownloading. Default install location: $CI_PROJECT_ROOT/$CI_BOOT_NAME/bin/uv where $CI_BOOT_NAME is platform-aware (.boot-linux on Linux, .boot-macos on macOS), set at source-time by lib/ci.sh. Override with $UV_BIN to drop somewhere else. Override the version with $UV_VERSION (default below). The per-repo private venv (`.venv/`) is created by `uv sync` (run from the repo root AFTER this script installs the uv binary): NOT by this script. This script installs ONLY the uv BINARY (and uvx if the release ships it). See: docs/specifications/SPEC-BOOT-LAYOUT.md Overrideable env vars: $UV_VERSION : release tag to fetch (default: 0.11.23, the version confirmed in AGENTS.md §2). $UV_BIN : override install target path. Supply-chain pinning: SHA256 verification is MANDATORY and always on. The checksum is fetched at runtime from the .sha256 sidecar file published alongside the tarball on the GitHub release page. No hardcoded hashes are used -- the sidecar is the trusted source of truth, fetched from the same release origin as the tarball.

        bootstrap-uv

        Output: Installs uv (and uvx if shipped) to $CI_PROJECT_ROOT/${boot_dir}/bin (boot_dir read from config/boot_layout.yaml; default .boot-linux) if absent/upgrade-needed; no-op otherwise. The per-repo .venv/ is created later by `uv sync`, NOT by this script.

        #!/usr/bin/env bash
        # bootstrap-uv: fetch the uv binary and place it on PATH.
        #
        # This project uses `uv` for dependency management (uv sync -> per-repo
        # .venv/) and for cross-project Python invocation (uv run --project).
        # This script is idempotent: if a compatible binary is already present at
        # the target path, it exits 0 without redownloading.
        #
        # Default install location:
        #   $CI_PROJECT_ROOT/$CI_BOOT_NAME/bin/uv
        # where $CI_BOOT_NAME is platform-aware (.boot-linux on Linux, .boot-macos
        # on macOS), set at source-time by lib/ci.sh.
        # Override with $UV_BIN to drop somewhere else.
        #
        # Override the version with $UV_VERSION (default below).
        #
        # The per-repo private venv (`.venv/`) is created by `uv sync` (run from the
        # repo root AFTER this script installs the uv binary): NOT by this script.
        # This script installs ONLY the uv BINARY (and uvx if the release ships it).
        # See: docs/specifications/SPEC-BOOT-LAYOUT.md
        #
        # Overrideable env vars:
        #   $UV_VERSION        : release tag to fetch (default: 0.11.23, the
        #                         version confirmed in AGENTS.md §2).
        #   $UV_BIN            : override install target path.
        #
        # Supply-chain pinning: SHA256 verification is MANDATORY and always on.
        # The checksum is fetched at runtime from the .sha256 sidecar file
        # published alongside the tarball on the GitHub release page. No hardcoded
        # hashes are used -- the sidecar is the trusted source of truth, fetched
        # from the same release origin as the tarball.
        
        set -euo pipefail
        
        UV_VERSION="${UV_VERSION:-0.11.23}"
        
        _ci_lib="$(cd "$(dirname "${BASH_SOURCE[0]}")/../lib" && pwd)"
        # shellcheck source=lib/ci.sh
        if ! source "$_ci_lib/ci.sh"; then
            echo "ERROR: failed to source $_ci_lib/ci.sh" >&2
            exit 2
        fi
        if [[ -z "${CI_PROJECT_ROOT:-}" ]]; then
            echo "ERROR: CI_PROJECT_ROOT not set after sourcing ci.sh" >&2
            exit 2
        fi
        
        _log() { printf '[bootstrap-uv] %s\n' "$*" >&2; }
        
        main() {
            local target_dir target arch platform tarball url subdir
            target_dir="${CI_PROJECT_ROOT}/${CI_BOOT_NAME}/bin"
            target="${UV_BIN:-${target_dir}/uv}"
        
            if ! mkdir -p "$(dirname "$target")"; then
                _log "mkdir failed for $(dirname "$target")"
                return 1
            fi
        
            if [[ -x "$target" ]]; then
                local v_out v_err v_rc=0
                v_out="$(mktemp)"
                v_err="$(mktemp)"
                "$target" --version >"$v_out" 2>"$v_err" || v_rc=$?
                if [[ "$v_rc" -eq 0 ]]; then
                    local cur
                    cur="$(head -1 "$v_out")"
                    rm -f "$v_out" "$v_err"
                    if [[ "$cur" == *"${UV_VERSION}"* ]]; then
                        _log "uv ${UV_VERSION} already at $target"
                        return 0
                    fi
                    _log "found existing uv ($cur), upgrading to ${UV_VERSION}"
                else
                    local err_msg
                    err_msg="$(head -1 "$v_err")"
                    rm -f "$v_out" "$v_err"
                    _log "existing binary at $target did not respond to '--version'"
                    _log "rc=$v_rc: $err_msg: re-downloading fresh copy"
                fi
            fi
        
            case "$(uname -m)" in
                x86_64|amd64)  arch="x86_64" ;;
                aarch64|arm64) arch="aarch64" ;;
                *) _log "unsupported arch: $(uname -m)"; return 1 ;;
            esac
        
            case "$(uname -s)" in
                Linux)  platform="unknown-linux-gnu" ;;
                Darwin) platform="apple-darwin" ;;
                *) _log "unsupported platform: $(uname -s)"; return 1 ;;
            esac
        
            tarball="uv-${arch}-${platform}.tar.gz"
            url="https://github.com/astral-sh/uv/releases/download/${UV_VERSION}/${tarball}"
            # uv release tarballs extract into a subdir named uv-<arch>-<platform>.
            subdir="uv-${arch}-${platform}"
        
            local tmp
            tmp="$(mktemp -d)"
            # Use ${tmp:-} so the trap is safe under `set -u` once `tmp` (a local)
            # goes out of scope after main() returns.
            # shellcheck disable=SC2064
            trap "rm -rf \"\${tmp:-$tmp}\"" EXIT
        
            _log "fetching ${url}"
            local dl_rc=0
            curl -fsSL --retry 3 --retry-delay 2 -o "${tmp}/${tarball}" "$url" || dl_rc=$?
            if [[ "$dl_rc" -ne 0 ]]; then
                _log "curl failed for $url (rc=$dl_rc)"
                return 1
            fi
        
            # Mandatory SHA256 verification: fetch the .sha256 sidecar from the
            # same GitHub release URL as the tarball. The sidecar file contains
            # "<hash>  <filename>" -- we extract the hash and compare against
            # sha256sum of the downloaded tarball. No hardcoded hashes.
            local sha_url="${url}.sha256"
            _log "fetching checksum sidecar: ${sha_url}"
            local sha_rc=0
            curl -fsSL --retry 3 --retry-delay 2 -o "${tmp}/${tarball}.sha256" "$sha_url" || sha_rc=$?
            if [[ "$sha_rc" -ne 0 ]]; then
                _log "failed to fetch SHA256 sidecar from $sha_url (rc=$sha_rc)"
                _log "cannot verify tarball integrity without sidecar; refusing to install"
                return 1
            fi
        
            local expected_sha
            expected_sha="$(awk '{print $1}' "${tmp}/${tarball}.sha256")"
            if [[ -z "$expected_sha" ]]; then
                _log "SHA256 sidecar is empty or malformed; refusing to install"
                return 1
            fi
        
            local actual_sha
            actual_sha="$(ci_sha256 "${tmp}/${tarball}")"
            if [[ "$actual_sha" != "$expected_sha" ]]; then
                _log "checksum mismatch: expected $expected_sha, got $actual_sha"
                return 1
            fi
            _log "checksum OK ($expected_sha)"
        
            _log "extracting ${tarball} to ${tmp}"
            if ! tar -xzf "${tmp}/${tarball}" -C "$tmp"; then
                _log "tar extraction failed"
                return 1
            fi
        
            # Locate the uv binary inside the extracted subdir; fall back to the
            # archive root in case a future release flattens the layout.
            local uv_src="${tmp}/${subdir}/uv"
            if [[ ! -f "$uv_src" ]]; then
                uv_src="${tmp}/uv"
            fi
            if [[ ! -f "$uv_src" ]]; then
                _log "uv binary not found after extraction"
                _log "looked in ${subdir}/uv and at archive root of ${tmp}"
                return 1
            fi
        
            _log "installing uv to ${target}"
            if ! install -m 0755 "$uv_src" "$target"; then
                _log "install (copy) failed: $uv_src -> $target"
                return 1
            fi
        
            # Copy uvx if the release ships it (same subdir, then archive root).
            local uvx_src="${tmp}/${subdir}/uvx"
            if [[ ! -f "$uvx_src" ]]; then
                uvx_src="${tmp}/uvx"
            fi
            if [[ -f "$uvx_src" ]]; then
                local uvx_target
                uvx_target="$(dirname "$target")/uvx"
                if ! install -m 0755 "$uvx_src" "$uvx_target"; then
                    _log "install (copy) of uvx failed: $uvx_src -> $uvx_target"
                    return 1
                fi
                _log "uvx also installed to $uvx_target"
            fi
        
            local v_out2 v_err2 v_rc2=0
            v_out2="$(mktemp)"
            v_err2="$(mktemp)"
            "$target" --version >"$v_out2" 2>"$v_err2" || v_rc2=$?
            if [[ "$v_rc2" -ne 0 ]]; then
                _log "post-install verification failed: '$target --version' rc=$v_rc2"
                _log "stderr: $(head -1 "$v_err2")"
                rm -f "$v_out2" "$v_err2"
                return 1
            fi
            _log "installed: $(head -1 "$v_out2") => $target"
            rm -f "$v_out2" "$v_err2"
        }
        
        main "$@"

        Share feedback

        You voted thumbs down

        bootstrap-rust

        Bootstrap a $RUST_TOOLCHAIN Rust toolchain into CI's own .boot-linux/rust and symlink binaries into .boot-linux/bin (idempotent, isolated via RUSTUP_HOME/CARGO_HOME).

        Bootstrap

        bootstrap-rust

        scripts/bootstrap-rust

        bootstrap-rust: bootstrap a $RUST_TOOLCHAIN Rust toolchain into CI's own $CI_BOOT_NAME/rust/ and create symlinks in $CI_BOOT_NAME/bin/. This project uses `rustc`/`cargo` for any native-Rust tooling. This script is idempotent: if $CI_PROJECT_ROOT/${boot_dir}/rust/bin/rustc AND cargo are already present and respond to `--version`, it refreshes symlinks and components, then exits 0 without reinstalling. If the existing toolchain is broken (rustc fails to report its version), it is removed and reinstalled from scratch. Default install location: $CI_PROJECT_ROOT/$CI_BOOT_NAME/rust/ with symlinks in: $CI_PROJECT_ROOT/$CI_BOOT_NAME/bin/ where $CI_BOOT_NAME is platform-aware (.boot-linux on Linux, .boot-macos on macOS), set at source-time by lib/ci.sh. Repo-private: does NOT touch $HOME/.rustup or $HOME/.cargo: the toolchain is fully isolated via RUSTUP_HOME / CARGO_HOME env exports pointing at $CI_BOOT_NAME/rust. Sibling repos reach these binaries via the boot-path resolver (lib/ci.sh::ci_resolve_boot_path) which reads moon.yml::project.inherited_boot_dirs. Reference spec: docs/specifications/SPEC-BOOT-LAYOUT.md Overrideable env vars: $RUST_TOOLCHAIN : rustup toolchain channel to install (default: "stable").

        bootstrap-rust

        Output: Installs rustc/cargo/rustup into $CI_PROJECT_ROOT/${boot_dir}/rust and symlinks toolchain + llvm-tools-preview binaries into ${boot_dir}/bin (boot_dir read from config/boot_layout.yaml; default .boot-linux). Refreshes symlinks + components and exits 0 if a working toolchain is already present; reinstalls if rustc is present but fails --version. Repo-private: does NOT touch $HOME/.rustup or $HOME/.cargo.

        #!/usr/bin/env bash
        # bootstrap-rust: bootstrap a $RUST_TOOLCHAIN Rust toolchain into CI's own
        # $CI_BOOT_NAME/rust/ and create symlinks in $CI_BOOT_NAME/bin/.
        #
        # This project uses `rustc`/`cargo` for any native-Rust tooling. This script
        # is idempotent: if $CI_PROJECT_ROOT/${boot_dir}/rust/bin/rustc AND cargo
        # are already present and respond to `--version`, it refreshes symlinks and
        # components, then exits 0 without reinstalling. If the existing toolchain
        # is broken (rustc fails to report its version), it is removed and
        # reinstalled from scratch.
        #
        # Default install location:
        #   $CI_PROJECT_ROOT/$CI_BOOT_NAME/rust/
        # with symlinks in:
        #   $CI_PROJECT_ROOT/$CI_BOOT_NAME/bin/
        # where $CI_BOOT_NAME is platform-aware (.boot-linux on Linux, .boot-macos
        # on macOS), set at source-time by lib/ci.sh.
        #
        # Repo-private: does NOT touch $HOME/.rustup or $HOME/.cargo: the toolchain
        # is fully isolated via RUSTUP_HOME / CARGO_HOME env exports pointing at
        # $CI_BOOT_NAME/rust. Sibling repos reach these binaries via the boot-path
        # resolver (lib/ci.sh::ci_resolve_boot_path) which reads
        # moon.yml::project.inherited_boot_dirs.
        #
        # Reference spec: docs/specifications/SPEC-BOOT-LAYOUT.md
        #
        # Overrideable env vars:
        #   $RUST_TOOLCHAIN : rustup toolchain channel to install (default: "stable").
        
        set -euo pipefail
        
        RUST_TOOLCHAIN="${RUST_TOOLCHAIN:-stable}"
        
        _ci_lib="$(cd "$(dirname "${BASH_SOURCE[0]}")/../lib" && pwd)"
        # shellcheck source=lib/ci.sh
        if ! source "$_ci_lib/ci.sh"; then
            echo "ERROR: failed to source $_ci_lib/ci.sh" >&2
            exit 2
        fi
        if [[ -z "${CI_PROJECT_ROOT:-}" ]]; then
            echo "ERROR: CI_PROJECT_ROOT not set after sourcing ci.sh" >&2
            exit 2
        fi
        
        _log() { printf '[bootstrap-rust] %s\n' "$*" >&2; }
        
        # _link_if_stale <target> <link>
        #   Create the symlink only when missing or pointing elsewhere, so re-runs
        #   against a root-locked bin dir are no-ops instead of Permission denied.
        _link_if_stale() {
            local target="$1" link="$2"
            if [[ -L "$link" && "$(readlink "$link")" == "$target" ]]; then
                return 0
            fi
            ln -sf "$target" "$link"
        }
        
        # _create_symlinks <target_dir> <rust_home>
        #   Mirror active-toolchain bin + llvm-tools-preview bin into ${target_dir}
        #   via relative symlinks so the tree is relocatable.
        _create_symlinks() {
            local _td="$1" _rh="$2"
            local tc_out tc_err tc_rc=0
            tc_out="$(mktemp)"; tc_err="$(mktemp)"
            "$_rh/bin/rustup" show active-toolchain >"$tc_out" 2>"$tc_err" || tc_rc=$?
            if [[ $tc_rc -ne 0 ]]; then
                _log "rustup show active-toolchain failed (rc=$tc_rc):"
                cat "$tc_err" >&2
                rm -f "$tc_out" "$tc_err"
                return 1
            fi
            local toolchain_name
            toolchain_name="$(awk 'NR==1{print $1}' "$tc_out")"
            rm -f "$tc_out" "$tc_err"
            if [[ -z "$toolchain_name" ]]; then
                # Reasonable default: rustup names toolchains <channel>-<host-triple>.
                local _rust_arch
                case "$(uname -m)" in
                    x86_64|amd64) _rust_arch="x86_64" ;;
                    aarch64|arm64) _rust_arch="aarch64" ;;
                    *)             _rust_arch="$(uname -m)" ;;
                esac
                local _host_vendor
                case "$(uname -s)" in
                    Linux)  _host_vendor="unknown-linux-gnu" ;;
                    Darwin) _host_vendor="apple-darwin" ;;
                    *)      _host_vendor="unknown-linux-gnu" ;;
                esac
                toolchain_name="${RUST_TOOLCHAIN}-${_rust_arch}-${_host_vendor}"
            fi
        
            local host_triple
            local _rust_arch
            case "$(uname -m)" in
                x86_64|amd64) _rust_arch="x86_64" ;;
                aarch64|arm64) _rust_arch="aarch64" ;;
                *)             _rust_arch="$(uname -m)" ;;
            esac
            case "$(uname -s)" in
                Linux)  host_triple="$_rust_arch-unknown-linux-gnu" ;;
                Darwin) host_triple="$_rust_arch-apple-darwin" ;;
                *)      host_triple="$_rust_arch-unknown-linux-gnu" ;;
            esac
            local toolchain_dir toolchain_bin toolchain_llvm_bin
            toolchain_dir="rust/toolchains/${toolchain_name}"
            toolchain_bin="${toolchain_dir}/bin"
            toolchain_llvm_bin="${toolchain_dir}/lib/rustlib/${host_triple}/bin"
        
            mkdir -p "$_td"
            _link_if_stale "../rust/bin/rustup" "${_td}/rustup"
        
            local bin
            for bin in cargo rustc rustfmt cargo-clippy cargo-fmt \
                       clippy-driver rustdoc; do
                if [[ -x "${CI_PROJECT_ROOT}/${CI_BOOT_NAME}/${toolchain_bin}/${bin}" ]]; then
                    _link_if_stale "../${toolchain_bin}/${bin}" "${_td}/${bin}"
                fi
            done
        
            local llvm_dir="${CI_PROJECT_ROOT}/${CI_BOOT_NAME}/${toolchain_llvm_bin}"
            if [[ -d "$llvm_dir" ]]; then
                local entry bin_name
                for entry in "$llvm_dir"/*; do
                    [[ -d "$entry" ]] && continue
                    [[ -x "$entry" ]] || continue
                    bin_name="$(basename "$entry")"
                    _link_if_stale "../${toolchain_llvm_bin}/${bin_name}" "${_td}/${bin_name}"
                done
                _log "LLVM tool symlinks created"
            else
                _log "LLVM tools dir not found at ${toolchain_llvm_bin}; skipping"
            fi
            _log "Rust symlinks created in ${_td}"
        }
        
        # _install_components <target_dir> <rust_home>
        #   Add the extra components the workspace relies on (coverage + source).
        _install_components() {
            local _td="$1" _rh="$2"
            local c_out c_err c_rc=0
            c_out="$(mktemp)"; c_err="$(mktemp)"
            "$_rh/bin/rustup" component add llvm-tools-preview rust-src \
                >"$c_out" 2>"$c_err" || c_rc=$?
            if [[ $c_rc -ne 0 ]]; then
                _log "rustup component add failed (rc=$c_rc):"
                cat "$c_err" >&2
                rm -f "$c_out" "$c_err"
                return 1
            fi
            rm -f "$c_out" "$c_err"
            _log "components installed: llvm-tools-preview, rust-src"
        }
        
        main() {
            local target_dir rust_home
            target_dir="${CI_PROJECT_ROOT}/${CI_BOOT_NAME}/bin"
            rust_home="${CI_PROJECT_ROOT}/${CI_BOOT_NAME}/rust"
        
            mkdir -p "$target_dir"
            mkdir -p "$rust_home"
        
            # Isolate rustup/cargo state inside $CI_BOOT_NAME/rust (NOT $HOME).
            # Exported BEFORE the idempotency check so rustup proxies (rustc/cargo)
            # can resolve their home directory and find the active toolchain.
            export RUSTUP_HOME="$rust_home"
            export CARGO_HOME="$rust_home"
        
            # Idempotency: existing toolchain must actually respond to --version.
            if [[ -x "$rust_home/bin/rustc" && -x "$rust_home/bin/cargo" ]]; then
                local v_out v_err v_rc=0
                v_out="$(mktemp)"; v_err="$(mktemp)"
                "$rust_home/bin/rustc" --version >"$v_out" 2>"$v_err" || v_rc=$?
                if [[ $v_rc -eq 0 ]]; then
                    _log "Rust already installed: $(head -1 "$v_out")"
                    rm -f "$v_out" "$v_err"
                    _create_symlinks "$target_dir" "$rust_home"
                    _install_components "$target_dir" "$rust_home"
                    return 0
                fi
                _log "toolchain broken (rc=$v_rc): $(head -1 "$v_err")"
                _log "removing $rust_home and reinstalling"
                rm -f "$v_out" "$v_err"
                rm -rf "$rust_home"
                mkdir -p "$rust_home"
            fi
        
            # Rust needs a C linker. Short-circuit AND of absent compilers is the
            # real check: `command -v` returning nonzero IS the signal, not a swallow.
            if ! command -v cc && ! command -v gcc && ! command -v clang; then
                _log "no C compiler (cc/gcc/clang) found: required by Rust toolchain"
                return 1
            fi
        
            local tmp
            tmp="$(mktemp -d)"
            # Use ${tmp:-} so the trap is safe under `set -u` once `tmp` (a local)
            # goes out of scope after main() returns.
            # shellcheck disable=SC2064
            trap "rm -rf \"\${tmp:-$tmp}\"" EXIT
        
            local rustup_url="https://sh.rustup.rs"
            _log "fetching $rustup_url"
            local dl_rc=0
            curl -fsSL --retry 3 --retry-delay 2 \
                -o "$tmp/rustup-init.sh" "$rustup_url" || dl_rc=$?
            if [[ $dl_rc -ne 0 ]]; then
                _log "curl failed (rc=$dl_rc): $rustup_url"
                return 1
            fi
        
            _log "running rustup-init (toolchain=$RUST_TOOLCHAIN)"
            local ru_out ru_err ru_rc=0
            ru_out="$(mktemp)"; ru_err="$(mktemp)"
            bash "$tmp/rustup-init.sh" -y --no-modify-path \
                --default-toolchain "$RUST_TOOLCHAIN" >"$ru_out" 2>"$ru_err" \
                || ru_rc=$?
            if [[ $ru_rc -ne 0 ]]; then
                _log "rustup-init failed (rc=$ru_rc):"
                cat "$ru_err" >&2
                rm -f "$ru_out" "$ru_err"
                return 1
            fi
            rm -f "$ru_out" "$ru_err"
        
            # Post-install verify: both binaries must exist and answer --version.
            local p_out p_err p_rc=0
            p_out="$(mktemp)"; p_err="$(mktemp)"
            if [[ ! -x "$rust_home/bin/rustc" ]]; then
                _log "rustc not found after install: $rust_home/bin/rustc"
                rm -f "$p_out" "$p_err"
                return 1
            fi
            "$rust_home/bin/rustc" --version >"$p_out" 2>"$p_err" || p_rc=$?
            if [[ $p_rc -ne 0 ]]; then
                _log "rustc --version failed (rc=$p_rc): $(head -1 "$p_err")"
                rm -f "$p_out" "$p_err"
                return 1
            fi
            _log "rustc: $(head -1 "$p_out")"
            : >"$p_out"; p_rc=0
            if [[ ! -x "$rust_home/bin/cargo" ]]; then
                _log "cargo not found after install: $rust_home/bin/cargo"
                rm -f "$p_out" "$p_err"
                return 1
            fi
            "$rust_home/bin/cargo" --version >"$p_out" 2>"$p_err" || p_rc=$?
            if [[ $p_rc -ne 0 ]]; then
                _log "cargo --version failed (rc=$p_rc): $(head -1 "$p_err")"
                rm -f "$p_out" "$p_err"
                return 1
            fi
            _log "cargo: $(head -1 "$p_out")"
            rm -f "$p_out" "$p_err"
        
            _create_symlinks "$target_dir" "$rust_home"
            _install_components "$target_dir" "$rust_home"
        }
        
        main "$@"

        Share feedback

        You voted thumbs down

        bootstrap-workspace-guard

        Build and install the capability-based git guard binary from the sibling WORKSPACE-GUARD repo.

        Bootstrap
        Make target
        build-guard

        bootstrap-workspace-guard

        scripts/bootstrap-workspace-guard

        Bootstrap: Build and install capability-based workspace guard (git) Called from CI Makefile: lives in the CI repo, builds from sibling WORKSPACE-GUARD.

        bootstrap-workspace-guard [build-only|install-host-exec|check-host-exec|uninstall|purge-guard-state]
        build-only
        Compile workspace-guard and workspace-git-ssh (no root needed)
        install-host-exec
        Install or reconcile host-exec git guard (requires root)
        check-host-exec
        Report host-exec guard installation status
        uninstall
        Restore stock git; preserve host-provision state
        purge-guard-state
        Destroy all guard state (requires GUARD_PURGE_CONFIRM=1)

        Output: Builds/installs/removes the git-guard binary. Status text on stdout.

        #!/usr/bin/env bash
        # Bootstrap: Build and install capability-based workspace guard (git)
        # Called from CI Makefile: lives in the CI repo, builds from sibling WORKSPACE-GUARD.
        set -euo pipefail
        
        _SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
        _CI_ROOT="$(cd "$_SCRIPT_DIR/.." && pwd)"
        WORKSPACE_ROOT="$(cd "$_CI_ROOT/../.." && pwd)"
        
        _guard_dir="$_CI_ROOT/../WORKSPACE-GUARD"
        
        RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'
        CYAN='\033[0;36m'; BOLD='\033[1m'; NC='\033[0m'
        log_info()  { echo -e "${GREEN}[INFO]${NC} $*"; }
        log_warn()  { echo -e "${YELLOW}[WARN]${NC} $*"; }
        log_error() { echo -e "${RED}[ERROR]${NC} $*"; }
        
        MODE="${1:-install-host-exec}"  # install-host-exec | check-host-exec | uninstall | purge-guard-state | build-only
        
        _guard_removed_target_error() {
            local removed_target="$1" replacement="$2"
            log_error "make $removed_target is removed. Use: make $replacement"
            exit 1
        }
        
        divert_is_active() {
            dpkg-divert --list /usr/bin/git | grep -q 'git.distrib'
        }
        
        _has_chattr() {
            local _path=""
            _path="$(command -v chattr 2>&1)" && return 0
            return 1
        }
        
        _has_func() {
            local _func="$1" _out=""
            _out="$(declare -F "$_func" 2>&1)" && return 0
            return 1
        }
        
        guard_is_installed() {
            [[ -f /usr/bin/git.original ]] \
                || divert_is_active \
                || [[ -f /usr/lib/workspace-guard/deployment-class ]]
        }
        
        _restore_stock_git() {
            if _has_chattr; then
                test -f /usr/bin/git       && chattr -i /usr/bin/git
                test -f /usr/bin/git.original && chattr -i /usr/bin/git.original
            fi
            rm -f /usr/bin/git
            if divert_is_active; then
                dpkg-divert --rename --remove /usr/bin/git
                log_info "Removed dpkg-divert"
            fi
            if [[ -f /usr/bin/git.original ]]; then
                mv /usr/bin/git.original /usr/bin/git
                chown root:root /usr/bin/git
                chmod 0755 /usr/bin/git
                _guard_best_effort setcap -r /usr/bin/git
                log_info "Restored /usr/bin/git from git.original"
            elif [[ -f /usr/bin/git.distrib ]]; then
                mv /usr/bin/git.distrib /usr/bin/git
                chown root:root /usr/bin/git
                chmod 0755 /usr/bin/git
                _guard_best_effort setcap -r /usr/bin/git
                log_info "Restored /usr/bin/git from git.distrib"
            else
                log_error "No git backup found: cannot restore"
                log_error "Reinstall git: sudo apt install --reinstall git"
                return 1
            fi
            return 0
        }
        
        _cleanup_git_guard_sidecars() {
            if _has_func guard_scrub_pam_artifacts; then
                guard_scrub_pam_artifacts || {
                    local _scrub_rc=$?
                    printf 'guard optional scrub failed (rc=%s)\n' "$_scrub_rc" >&2
                }
            fi
            rm -f /etc/apt/apt.conf.d/99workspace-guard
            rm -f /etc/apt/apt.conf.d/99git-guard
            if _has_func guard_remove_git_install_artifacts; then
                guard_remove_git_install_artifacts
            fi
            rm -rf /usr/lib/ami-git-guard
            rm -rf /var/log/workspace-guard
            rm -rf /var/log/ami-git-guard
        }
        
        uninstall_guard() {
            local state_dir="/usr/lib/workspace-guard"
            if _has_func guard_state_dir; then
                state_dir="$(guard_state_dir)"
            fi
            log_info "Uninstalling git guard (preserving host provision state under $state_dir)..."
            if ! guard_is_installed; then
                log_info "Git guard not installed; removing git-install artifacts only"
                if _has_chattr; then
                    [[ -f /usr/bin/git ]] && _guard_best_effort chattr -i /usr/bin/git
                    [[ -f /usr/bin/git.original ]] && _guard_best_effort chattr -i /usr/bin/git.original
                fi
                _cleanup_git_guard_sidecars
                if [[ -x /usr/bin/git ]]; then
                    _guard_best_effort setcap -r /usr/bin/git
                fi
                log_info "Cleanup complete (provision state preserved)"
                git --version
                return 0
            fi
            _restore_stock_git || return 1
            _cleanup_git_guard_sidecars
            log_info "Git guard uninstalled: stock /usr/bin/git restored; provision state preserved"
            git --version
        }
        
        rollback_guard() {
            log_warn "Installation failed: rolling back..."
            if _has_chattr; then
                if [[ -f /usr/bin/git ]]; then
                    rc=0; chattr -i /usr/bin/git || rc=$?
                    if [ $rc -ne 0 ]; then
                        echo "chattr -i /usr/bin/git: no-op or failed (rc=$rc)" >&2
                    fi
                fi
                if [[ -f /usr/bin/git.original ]]; then
                    rc=0; chattr -i /usr/bin/git.original || rc=$?
                    if [ $rc -ne 0 ]; then
                        echo "chattr -i /usr/bin/git.original: no-op or failed (rc=$rc)" >&2
                    fi
                fi
            fi
            rm -f /usr/bin/git
            if divert_is_active; then
                rc=0; dpkg-divert --rename --remove /usr/bin/git || rc=$?
                if [ $rc -ne 0 ]; then
                    echo "dpkg-divert --remove /usr/bin/git: no-op or failed (rc=$rc)" >&2
                fi
            fi
            if [[ -f /usr/bin/git.original ]]; then
                if _has_chattr; then
                    rc=0; chattr -i /usr/bin/git.original || rc=$?
                    if [ $rc -ne 0 ]; then
                        echo "chattr -i /usr/bin/git.original: no-op or failed (rc=$rc)" >&2
                    fi
                fi
                mv /usr/bin/git.original /usr/bin/git
                chown root:root /usr/bin/git
                chmod 0755 /usr/bin/git
                _guard_best_effort setcap -r /usr/bin/git
                log_info "Restored /usr/bin/git from git.original"
            elif [[ -f /usr/bin/git.distrib ]]; then
                mv /usr/bin/git.distrib /usr/bin/git
                chown root:root /usr/bin/git
                chmod 0755 /usr/bin/git
                _guard_best_effort setcap -r /usr/bin/git
                log_info "Restored /usr/bin/git from git.distrib"
            fi
            rm -f /etc/apt/apt.conf.d/99workspace-guard
            if _has_func guard_remove_git_install_artifacts; then
                guard_remove_git_install_artifacts
            else
                rm -rf /usr/lib/workspace-guard
            fi
        }
        
        _run_guard_install_with_drift_check() {
            local guard_bin="${1:-}"
            if [[ -z "$guard_bin" ]]; then
                guard_bin="$(_resolve_guard_bin)" || {
                    log_error "Guard binary not found; run make build-guard first"
                    return 1
                }
            fi
            local -a _drift=()
            if [[ "${GUARD_FORCE_RECONCILE:-}" == "1" ]]; then
                log_info "GUARD_FORCE_RECONCILE=1: reconciling regardless of drift status"
                export GUARD_RECONCILE=1
            else
                _guard_read_lines _drift guard_install_drift_reasons "$guard_bin"
                if [[ ${#_drift[@]} -eq 0 ]]; then
                    log_info "Git guard healthy; nothing to do."
                    return 0
                fi
                log_warn "Git guard drift detected; reconciling:"
                printf '  - %s\n' "${_drift[@]}"
                export GUARD_RECONCILE=1
            fi
            install_guard_binary "$guard_bin" || return 1
        }
        
        # Source the build and install helpers from lib/. These were extracted
        # from this file to keep it under the 512-line source-length gate
        # (AGENTS.md Rule 4). The helpers depend on globals defined above
        # (WORKSPACE_ROOT, _CI_ROOT, _guard_dir, CYAN, BOLD, RED, NC, log_*,
        # divert_is_active, rollback_guard) and inherit `set -euo pipefail`.
        # Use `source ... || exit 1` per AGENTS.md Rule 14 (no bare source).
        # shellcheck source=lib/guard-build.sh
        source "$_CI_ROOT/lib/guard-build.sh" || exit 1
        # shellcheck source=lib/guard-drift.sh
        source "$_CI_ROOT/lib/guard-drift.sh" || exit 1
        # shellcheck source=lib/guard-host-exec.sh
        source "$_CI_ROOT/lib/guard-host-exec.sh" || exit 1
        # shellcheck source=lib/guard-install.sh
        source "$_CI_ROOT/lib/guard-install.sh" || exit 1
        
        install_guard() {
            build_guard_binary || return 1
            _run_guard_install_with_drift_check "$GUARD_BIN" || return 1
        }
        
        check_guard() {
            local ref_bin=""
            ref_bin="$(_guard_capture_line _resolve_guard_bin)"
            local -a _drift=()
            _guard_read_lines _drift guard_install_drift_reasons "$ref_bin"
        
            if [[ ${#_drift[@]} -eq 0 ]]; then
                log_info "Rust guard status: HEALTHY"
                if [[ -f /usr/bin/git ]]; then
                    log_info "  /usr/bin/git: $(stat -c '%a %U:%G' /usr/bin/git)"
                fi
                if [[ -f /usr/bin/git.original ]]; then
                    log_info "  /usr/bin/git.original: $(stat -c '%a %U:%G' /usr/bin/git.original)"
                fi
                local _mode _cls
                _mode="$(_guard_reference_mode "$ref_bin")"
                _cls="$(_guard_capture_line guard_read_deployment_class)"
                log_info "  mode: $_mode"
                [[ -n "$_cls" ]] && log_info "  deployment-class: $_cls"
                return 0
            fi
        
            if [[ "${_drift[0]}" == "guard not installed:"* ]]; then
                log_info "Rust guard status: NOT INSTALLED"
            else
                log_info "Rust guard status: DRIFTED"
            fi
            log_warn "Drift items:"
            printf '  - %s\n' "${_drift[@]}"
            log_info "Fix: sudo make guard-refresh"
        }
        
        case "$MODE" in
            uninstall) uninstall_guard ;;
            purge-guard-state) purge_guard_state ;;
            check-host-exec) check_guard ;;
            check) _guard_removed_target_error check-guard check-guard-host-exec ;;
            build-only) build_guard_binary ;;
            install-host-exec)
                GUARD_BIN="$(_resolve_guard_bin)" || {
                    log_error "Guard binary not found; make build-guard should run first"
                    exit 1
                }
                _run_guard_install_with_drift_check "$GUARD_BIN"
                ;;
            install-only|install|reinstall)
                _guard_removed_target_error install-guard install-guard-host-exec
                ;;
            *) log_error "Unknown mode: $MODE"; exit 1 ;;
        esac
        

        Share feedback

        You voted thumbs down

        audit-workspace

        Discover all git repos under a root and report working-tree, sync, and CI integration status.

        Workspace
        Make target
        audit

        audit-workspace

        scripts/audit-workspace

        audit-workspace -- Discover all git repos under a root and report status. Reports: working tree state, remote sync, CI integration level. Usage: audit-workspace [ROOT]

        audit-workspace [ROOT]
        ROOT
        Workspace root to scan (default: auto-detected)

        Output: One row per discovered repo with state/sync/CI columns.

        #!/usr/bin/env bash
        # audit-workspace -- Discover all git repos under a root and report status.
        # Reports: working tree state, remote sync, CI integration level.
        #
        # Usage: audit-workspace [ROOT]
        set -euo pipefail
        
        _SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
        _CI_ROOT="$(cd "$_SCRIPT_DIR/.." && pwd)"
        if ! source "$_CI_ROOT/lib/ci.sh"; then
            echo "ERROR: failed to source $_CI_ROOT/lib/ci.sh" >&2
            exit 2
        fi
        
        # Capture stdout of <cmd...>, fall back to <default> string on failure.
        # stderr is captured to a temp file and printed only on failure (real signal,
        # no swallow). Use for UI display strings where a command failure should
        # degrade to a static default rather than abort the audit.
        _capture_or_default() {
            local default="$1"; shift
            local out err rc=0
            out="$(mktemp)"; err="$(mktemp)"
            "$@" >"$out" 2>"$err" || rc=$?
            if [[ $rc -ne 0 ]]; then
                if [[ -s "$err" ]]; then
                    printf '[audit-workspace] %s (rc=%d): %s\n' "$*" "$rc" \
                        "$(head -1 "$err")" >&2
                fi
                printf '%s' "$default"
            else
                cat "$out"
            fi
            rm -f "$out" "$err"
        }
        
        _ROOT="${1:-$(git rev-parse --show-toplevel || pwd)}"
        _ROOT="$(cd "$_ROOT" && pwd)"
        
        # Skip patterns for repo discovery
        _SKIP_DIRS="tmp|node_modules|\.venv|__pycache__|research|python-ta-reference|\.boot-linux|\.boot-macos|dist|build"
        
        # Load blocked patterns for L4 check
        _blocked_combined=""
        _blocked_config="$CI_CONFIG_DIR/blocked_commit_patterns.yaml"
        if [[ -f "$_blocked_config" ]]; then
            while IFS= read -r _line; do
                if [[ "$_line" =~ pattern:[[:space:]]*[\"\']?(.+)[\"\']?$ ]]; then
                    _pat="${BASH_REMATCH[1]}"
                    _pat="${_pat%\"}" ; _pat="${_pat%\'}"
                    _pat="${_pat#\"}" ; _pat="${_pat#\'}"
                    [[ -n "$_blocked_combined" ]] && _blocked_combined="${_blocked_combined}|"
                    _blocked_combined="${_blocked_combined}${_pat}"
                fi
            done < "$_blocked_config"
        fi
        
        # -- Discover repos --
        _repos=()
        _gitdirs=()
        ci_capture_pipe _gitdirs 'find "$1" -name ".git" -type d | sort' "$_ROOT"
        for _gitdir in "${_gitdirs[@]}"; do
            _repo="$(dirname "$_gitdir")"
            # Skip matches
            if echo "$_repo" | grep -qE "$_SKIP_DIRS"; then
                continue
            fi
            _repos+=("$_repo")
        done
        
        
        if [[ ${#_repos[@]} -eq 0 ]]; then
            ci_warn "No git repos found under $_ROOT"
            exit 0
        fi
        
        _total_repos=${#_repos[@]}
        _fully_integrated=0
        _total_score=0
        _max_possible=0
        
        # -- Helper: relative time --
        _age() {
            local ts="$1"
            local now
            now="$(date +%s)"
            local diff=$(( now - ts ))
            if [[ $diff -lt 3600 ]]; then
                echo "$((diff / 60))m ago"
            elif [[ $diff -lt 86400 ]]; then
                echo "$((diff / 3600))h ago"
            else
                echo "$((diff / 86400))d ago"
            fi
        }
        
        # -- Audit each repo --
        for _repo in "${_repos[@]}"; do
            _rel="${_repo#"$_ROOT"/}"
            [[ "$_repo" == "$_ROOT" ]] && _rel="(root)"
        
            echo ""
            ci_info "=== $_rel ==="
        
            # 1. Identity
            _branch="$(_capture_or_default "detached" git -C "$_repo" rev-parse --abbrev-ref HEAD)"
            _last_hash="$(_capture_or_default "none" git -C "$_repo" log -1 --format=%h)"
            _last_subj="$(_capture_or_default "" git -C "$_repo" log -1 --format=%s)"
            _last_ts="$(_capture_or_default "0" git -C "$_repo" log -1 --format=%at)"
            _last_age="$(_age "$_last_ts")"
            echo "Branch: $_branch | Last: $_last_hash ${_last_subj:0:60} ($_last_age)"
        
            # 2. Working tree
            _unstaged="$(git -C "$_repo" diff --name-only | wc -l | tr -d ' ')"
            _staged="$(git -C "$_repo" diff --cached --name-only | wc -l | tr -d ' ')"
            _untracked="$(git -C "$_repo" ls-files --others --exclude-standard | wc -l | tr -d ' ')"
            _stash="$(git -C "$_repo" stash list | wc -l | tr -d ' ')"
            if [[ $_unstaged -eq 0 && $_staged -eq 0 && $_untracked -eq 0 ]]; then
                echo "Tree:   clean"
            else
                echo "Tree:   dirty (unstaged:$_unstaged staged:$_staged untracked:$_untracked stash:$_stash)"
            fi
        
            # 3. Remote sync
            _rc_remotes=0
            _remotes="$(git -C "$_repo" remote)" || _rc_remotes=$?
            if [[ -z "$_remotes" ]]; then
                echo "Remotes: none"
            else
                echo "Remotes:"
                while IFS= read -r _remote; do
                    _url="$(_capture_or_default "?" git -C "$_repo" remote get-url "$_remote")"
                    _tracking="$(_capture_or_default "" git -C "$_repo" rev-parse --abbrev-ref "$_branch@{upstream}")"
                    if [[ -z "$_tracking" || "$_tracking" == *"@{upstream}"* ]]; then
                        printf "  %-8s (%s) : no tracking branch\n" "$_remote" "$_url"
                        continue
                    fi
                    _ahead="$(_capture_or_default "?" git -C "$_repo" rev-list --count "$_tracking..HEAD")"
                    _behind="$(_capture_or_default "?" git -C "$_repo" rev-list --count "HEAD..$_tracking")"
                    if [[ "$_ahead" == "0" && "$_behind" == "0" ]]; then
                        _sync="up-to-date"
                    elif [[ "$_ahead" != "0" && "$_behind" != "0" ]]; then
                        _sync="DIVERGED (ahead $_ahead, behind $_behind)"
                    elif [[ "$_ahead" != "0" ]]; then
                        _sync="ahead $_ahead"
                    else
                        _sync="behind $_behind"
                    fi
                    printf "  %-8s (%s) : %s\n" "$_remote" "$_url" "$_sync"
                done <<< "$_remotes"
            fi
        
            # 4. CI Integration
            _score=0
            _max=7
            _max_possible=$((_max_possible + _max))
            _checks=()
        
            # L0: Config
            if [[ -f "$_repo/.pre-commit-config.yaml" ]]; then
                _checks+=("[x] L0: .pre-commit-config.yaml")
                _score=$((_score + 1))
            else
                _checks+=("[ ] L0: .pre-commit-config.yaml (missing)")
            fi
        
            # L1: Native hooks
            if [[ -f "$_repo/.git/hooks/pre-commit" ]] && grep -q 'generate-hooks\|ci\.sh' "$_repo/.git/hooks/pre-commit"; then
                _checks+=("[x] L1: Native hooks installed")
                _score=$((_score + 1))
            elif [[ -f "$_repo/.git/hooks/pre-commit" ]]; then
                _checks+=("[ ] L1: Native hooks (pre-commit exists but not CI-generated)")
            else
                _checks+=("[ ] L1: Native hooks (not installed)")
            fi
        
            # L2: Makefile migrated
            if [[ -f "$_repo/Makefile" ]] && grep -q 'generate-hooks' "$_repo/Makefile"; then
                _checks+=("[x] L2: Makefile migrated")
                _score=$((_score + 1))
            elif [[ -f "$_repo/Makefile" ]] && grep -q 'pre-commit install' "$_repo/Makefile"; then
                _checks+=("[ ] L2: Makefile (still uses pre-commit install)")
            elif [[ -f "$_repo/Makefile" ]]; then
                _checks+=("[ ] L2: Makefile (no hooks target)")
            else
                _checks+=("[ ] L2: Makefile (no Makefile)")
            fi
        
            # L3: Commit msg enforced
            if [[ -f "$_repo/.pre-commit-config.yaml" ]] && grep -q 'check-commit-message\|ci_check_commit_message' "$_repo/.pre-commit-config.yaml"; then
                _checks+=("[x] L3: Commit message format enforced")
                _score=$((_score + 1))
            else
                _checks+=("[ ] L3: Commit message format (not configured)")
            fi
        
            # L4: History clean
            if [[ -n "$_blocked_combined" ]]; then
                _rc_blocked=0
                _violations="$(git -C "$_repo" log --format=%B HEAD | grep -ciE "$_blocked_combined")" || _rc_blocked=$?
                if [[ "$_violations" -eq 0 ]]; then
                    _checks+=("[x] L4: History clean")
                    _score=$((_score + 1))
                else
                    _checks+=("[ ] L4: History clean ($_violations blocked pattern(s) found)")
                fi
            else
                _checks+=("[ ] L4: History clean (no blocked patterns config)")
            fi
        
            # L5: Pre-push hooks
            if [[ -f "$_repo/.git/hooks/pre-push" ]] && grep -q 'generate-hooks\|ci\.sh' "$_repo/.git/hooks/pre-push"; then
                _checks+=("[x] L5: Pre-push hooks")
                _score=$((_score + 1))
            else
                _checks+=("[ ] L5: Pre-push hooks (not installed)")
            fi
        
            # L6: Test suite on push
            if [[ -f "$_repo/.pre-commit-config.yaml" ]] && grep -q 'run-tests\|ci-check-push\|verify-coverage' "$_repo/.pre-commit-config.yaml"; then
                _checks+=("[x] L6: Test suite on push")
                _score=$((_score + 1))
            else
                _checks+=("[ ] L6: Test suite on push (not configured)")
            fi
        
            echo ""
            echo "CI Integration: $_score/$_max"
            for _c in "${_checks[@]}"; do
                echo "  $_c"
            done
        
            _total_score=$((_total_score + _score))
            [[ $_score -eq $_max ]] && _fully_integrated=$((_fully_integrated + 1))
        done
        
        # -- Summary --
        echo ""
        echo "==========================================="
        ci_info "Workspace: $_ROOT"
        echo "Repos: $_total_repos | Fully integrated: $_fully_integrated/$_total_repos | Score: $_total_score/$_max_possible"
        echo "==========================================="
        
        if [[ $_fully_integrated -lt $_total_repos ]]; then
            exit 1
        fi
        exit 0
        

        Share feedback

        You voted thumbs down

        walk-projects

        Emit one nested .git repo path per line, relative to the workspace root.

        Workspace

        walk-projects

        scripts/walk-projects

        walk-projects: emit one nested .git repo path per line, relative to the workspace root. Used by every workspace-level *-recursive Makefile target so the find-and-iterate logic exists in one place. Usage: bash scripts/walk-projects [WORKSPACE_ROOT] Output (one path per line, relative to workspace root): projects/my-project projects/other-project/packages/sub # nested repos handled ... The output excludes the workspace-root repo itself (the umbrella), which is iterated separately by callers when needed.

        walk-projects

        Output: Repo paths on stdout, one per line. Used by recursive Makefile targets.

        #!/usr/bin/env bash
        # walk-projects: emit one nested .git repo path per line, relative to the
        # workspace root.
        #
        # Used by every workspace-level *-recursive Makefile target so the
        # find-and-iterate logic exists in one place.
        #
        # Usage:
        #   bash scripts/walk-projects [WORKSPACE_ROOT]
        #
        # Output (one path per line, relative to workspace root):
        #   projects/my-project
        #   projects/other-project/packages/sub      # nested repos handled
        #   ...
        #
        # The output excludes the workspace-root repo itself (the umbrella), which
        # is iterated separately by callers when needed.
        
        set -euo pipefail
        
        _workspace_root="${1:-}"
        if [[ -z "$_workspace_root" ]]; then
            # Walk up from CWD looking for the three workspace markers
            _cur="$(pwd)"
            while [[ "$_cur" != "/" ]]; do
                if [[ (-d "$_cur/.boot-linux" || -d "$_cur/.boot-macos") \
                      && -d "$_cur/projects" ]]; then
                    _workspace_root="$_cur"
                    break
                fi
                _cur="$(dirname "$_cur")"
            done
        fi
        
        if [[ -z "$_workspace_root" || ! -d "$_workspace_root/projects" ]]; then
            echo "walk-projects: cannot locate workspace root" >&2
            exit 1
        fi
        
        # Find every .git directory under projects/, emit the parent path
        # relative to the workspace root. Includes nested repos at any depth,
        # except repos whose tier resolves to vendored (third-party mirrors the
        # workspace does not manage).
        _self_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
        if ! source "$_self_dir/../lib/checks_quality.sh"; then
            echo "walk-projects: failed to source $_self_dir/../lib/checks_quality.sh" >&2
            exit 1
        fi
        _registry="$_workspace_root/ci/config/project_enforcement.yaml"
        
        cd "$_workspace_root"
        find projects -type d -name .git | while IFS= read -r _gitdir; do
            _repo="$(dirname "$_gitdir")"
            # Skip staging dirs that merely carry a copied .git/config: the wiki
            # prod build (web/scripts/stage-umbrella-repo.mjs) materializes
            # projects/WORKSPACE-VM with only .git/config inside, which is not a
            # repository. A real repository always has .git/HEAD.
            [[ -f "$_gitdir/HEAD" ]] || continue
            # Skip the deployed CI mirror (deploy-ci: _DEPLOY_DIR=projects/CI): it
            # is root-owned by design and its hook/exemption lifecycle is owned by
            # deploy-ci, not by the *-recursive consumer targets.
            [[ "$_repo" == "projects/CI" ]] && continue
            _tier="$(ci_resolve_tier "$_repo" "$_registry")"
            [[ "$_tier" == "vendored" ]] && continue
            echo "$_repo"
        done
        

        Share feedback

        You voted thumbs down

        code-stats

        Codebase statistics across the workspace via cloc (lines, files, per-repo and per-language breakdown).

        Workspace
        Make target
        code-stats

        code-stats

        scripts/code-stats

        code-stats -- Codebase statistics across the workspace. Walks every nested .git repo under the workspace root and runs cloc to produce: total lines (code/comment/blank/files), per-repo breakdown, and per-language breakdown. Respects .gitignore by default. Usage: code-stats # workspace-wide (default) code-stats --repo PATH # single repo code-stats --root PATH # workspace rooted at PATH code-stats --by-language # only show language table code-stats --by-repo # only show repo table code-stats --all-files # ignore .gitignore (count vendored too) code-stats --top N # show top N rows in tables (default: 25) code-stats --json # emit machine-readable JSON code-stats --no-umbrella # skip WORKSPACE-VM (workspace-root repo) Exit codes: 0 ok 1 cloc not found / invalid args 2 no repos found

        code-stats [--repo PATH] [--root PATH] [--by-language] [--by-repo] [--all-files] [--top N] [--json] [--no-umbrella]
        --repo
        Restrict to a single repo PATH (default: workspace-wide)
        --root
        Workspace root PATH (default: auto-detected)
        --by-language
        Show only the per-language table
        --by-repo
        Show only the per-repo table
        --all-files
        Ignore .gitignore (count vendored files too)
        --top
        Show top N rows in tables (default: 25)
        --json
        Emit machine-readable JSON instead of tables
        --no-umbrella
        Skip the workspace-root repo itself

        Output: cloc report on stdout (total + per-repo + per-language). Exits 0 on success, 1 if cloc missing, 2 if no repos found.

        #!/usr/bin/env bash
        # code-stats -- Codebase statistics across the workspace.
        #
        # Walks every nested .git repo under the workspace root and runs cloc to
        # produce: total lines (code/comment/blank/files), per-repo breakdown, and
        # per-language breakdown. Respects .gitignore by default.
        #
        # Usage:
        #   code-stats                      # workspace-wide (default)
        #   code-stats --repo PATH          # single repo
        #   code-stats --root PATH          # workspace rooted at PATH
        #   code-stats --by-language        # only show language table
        #   code-stats --by-repo            # only show repo table
        #   code-stats --all-files          # ignore .gitignore (count vendored too)
        #   code-stats --top N              # show top N rows in tables (default: 25)
        #   code-stats --json               # emit machine-readable JSON
        #   code-stats --no-umbrella        # skip WORKSPACE-VM (workspace-root repo)
        #
        # Exit codes:
        #   0  ok
        #   1  cloc not found / invalid args
        #   2  no repos found
        set -euo pipefail
        
        _SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
        # shellcheck source=../lib/ci.sh
        _ci_lib="$_SCRIPT_DIR/../lib/ci.sh"
        if ! source "$_ci_lib"; then
            echo "ERROR: failed to source $_ci_lib" >&2
            exit 2
        fi
        
        # ---------------------------------------------------------------------------
        # Locate cloc: prefer CI's own .boot-linux (CI owns the cloc bootstrap), then
        # the workspace root's boot dir, then .boot-macos, then fall back to PATH.
        # ---------------------------------------------------------------------------
        _find_cloc() {
            local _cands=(
                "${CI_PROJECT_ROOT:-}/.boot-linux/bin/cloc"
                "$CI_WORKSPACE_ROOT/.boot-linux/bin/cloc"
                "$CI_WORKSPACE_ROOT/.boot-macos/bin/cloc"
            )
            for _c in "${_cands[@]}"; do
                [[ -x "$_c" ]] && { echo "$_c"; return 0; }
            done
            local _cloc_path=""
            if _cloc_path="$(command -v cloc 2>&1)"; then
                echo "$_cloc_path"
                return 0
            fi
            return 1
        }
        
        # Resolve cloc; empty string if not found. _find_cloc returns 0/1 only
        # (writes path to stdout on success, no output on failure); no stderr
        # normally. Command substitution's exit status IS the inner command's,
        # so `if CLOC="$(...)"` is rc-capture: enters the if-branch on rc=0.
        CLOC=""
        if CLOC="$(_find_cloc)"; then
            :
        else
            CLOC=""
        fi
        if [[ -z "$CLOC" ]]; then
            ci_fail "cloc not found. Install via: bash scripts/bootstrap-cloc  (or: make install-cloc)"
            exit 1
        fi
        
        # ---------------------------------------------------------------------------
        # Arg parsing
        # ---------------------------------------------------------------------------
        _mode="all"          # all | by-language | by-repo
        _root="$CI_WORKSPACE_ROOT"
        _single_repo=""
        _respect_gitignore=1
        _top_n=25
        _json=0
        _skip_umbrella=0
        
        while [[ $# -gt 0 ]]; do
            case "$1" in
                --repo)         _single_repo="$2"; shift 2 ;;
                --root)         _root="$2"; shift 2 ;;
                --by-language)  _mode="by-language"; shift ;;
                --by-repo)      _mode="by-repo"; shift ;;
                --all-files)    _respect_gitignore=0; shift ;;
                --top)          _top_n="$2"; shift 2 ;;
                --json)         _json=1; shift ;;
                --no-umbrella)  _skip_umbrella=1; shift ;;
                -h|--help)      sed -n '2,20p' "$0" | sed 's/^# \?//'; exit 0 ;;
                *)              ci_fail "unknown arg: $1"; exit 1 ;;
            esac
        done
        
        _root="$(cd "$_root" && pwd)"
        _tmpdir="$(mktemp -d)"
        trap 'rm -rf "$_tmpdir"' EXIT
        
        # Skip patterns for nested repo discovery (mirrors audit-workspace).
        _SKIP_DIRS="tmp|node_modules|\.venv|__pycache__|research|python-ta-reference|\.boot-linux|\.boot-macos|dist|build|target|\.cache|\.local"
        
        # ---------------------------------------------------------------------------
        # Repo discovery
        # ---------------------------------------------------------------------------
        _repos=()
        if [[ -n "$_single_repo" ]]; then
            _single_repo="$(cd "$_single_repo" && pwd)"
            _repos+=("$_single_repo")
        else
            if [[ "$_skip_umbrella" -eq 0 && -d "$_root/.git" ]]; then
                _repos+=("$_root")
            fi
            _gitdirs=()
            ci_capture_pipe _gitdirs 'find "$1" -name ".git" -type d | sort' "$_root"
            for _gitdir in "${_gitdirs[@]}"; do
                _repo="$(dirname "$_gitdir")"
                [[ "$_repo" == "$_root" ]] && continue
                # Prod wiki stages README/Makefile under projects/WORKSPACE-VM; not a real repo.
                [[ "$_repo" == "$_root/projects/WORKSPACE-VM" ]] && continue
                echo "$_repo" | grep -qE "$_SKIP_DIRS" && continue
                _repos+=("$_repo")
            done
        fi
        
        if [[ ${#_repos[@]} -eq 0 ]]; then
            ci_warn "No git repos found under $_root"
            exit 2
        fi
        
        # ---------------------------------------------------------------------------
        # Run cloc per repo, collect results
        # ---------------------------------------------------------------------------
        # Per-repo aggregate file: tab-separated columns
        #   rel_path  files  blank  comment  code
        _per_repo="$_tmpdir/per_repo.tsv"
        # Per-(repo, language) detail file: tab-separated columns
        #   rel_path  language  files  blank  comment  code
        _per_repo_lang="$_tmpdir/per_repo_lang.tsv"
        
        # Track failures to distinguish "0 lines" from "skipped".
        _failed_repos=()
        
        if [[ $_json -eq 1 ]]; then
            printf '[code-stats] scanning %s repo(s) under %s...\n' \
                "${#_repos[@]}" "${_root#$HOME/~}" >&2
        else
            ci_info "Scanning ${#_repos[@]} repo(s) under ${_root#$HOME/~}..."
        fi
        
        for _repo in "${_repos[@]}"; do
            _is_umbrella=0
            if [[ "$_repo" == "$_root" ]]; then
                _is_umbrella=1
                _rel="WORKSPACE-VM"
            else
                _rel="${_repo#"$_root"/}"
                [[ "$_rel" == projects/* ]] && _rel="${_rel#projects/}"
            fi
        
            if [[ $_json -eq 1 ]]; then
                printf '[code-stats] cloc: %s (running; large repos may take several minutes)...\n' \
                    "$_rel" >&2
            fi
        
            # No --quiet: cloc progress goes to stderr (visible during long repos).
            _cloc_args=(--json --not-match-f='package-lock\.json')
            # Always use --exclude-dir instead of --vcs=git because the workspace
            # guard blocks ``git -c safe.directory=* ls-files`` (the command cloc
            # invokes internally under --vcs=git).  The expanded exclude list covers
            # the same heavy/vendored directories that .gitignore would filter.
            if [[ $_respect_gitignore -eq 1 ]]; then
                _cloc_args+=(
                    --exclude-dir=node_modules,.venv,__pycache__,target,dist,build,.cache,.local,.boot-linux,.boot-macos,.git,.next,.turbo,coverage,res
                )
            else
                _cloc_args+=(
                    --exclude-dir=node_modules,.venv,__pycache__,target,dist,build,.cache,.local,.boot-linux,.boot-macos,.git,.next,.turbo,coverage
                )
            fi
        
            _out="$_tmpdir/$(echo "$_rel" | tr '/' '_').json"
            _co_rc=0
            _co_out="$(mktemp)"; _co_err="$(mktemp)"
            if [[ $_is_umbrella -eq 1 ]]; then
                # Umbrella tracks only root-level files; nested projects/ repos are separate .git trees.
                _filelist="$_tmpdir/umbrella_files.txt"
                git -C "$_repo" ls-files >"$_filelist" 2>"$_co_err" || _co_rc=$?
                if [[ $_co_rc -eq 0 && -s "$_filelist" ]]; then
                    ( cd "$_repo" && "$CLOC" "${_cloc_args[@]}" --list-file="$_filelist" --report-file="$_out" . ) \
                        >"$_co_out" 2>"$_co_err" || _co_rc=$?
                elif [[ $_co_rc -eq 0 ]]; then
                    _co_rc=1
                    printf 'no tracked files\n' >"$_co_err"
                fi
            else
                ( cd "$_repo" && "$CLOC" "${_cloc_args[@]}" --report-file="$_out" . ) \
                    >"$_co_out" 2>"$_co_err" || _co_rc=$?
            fi
            if [[ $_co_rc -ne 0 ]]; then
                if [[ -s "$_co_err" ]]; then
                    printf '[code-stats] cloc failed on %s (rc=%d): %s\n' \
                        "$_rel" "$_co_rc" "$(head -1 "$_co_err")" >&2
                else
                    printf '[code-stats] cloc failed on %s (rc=%d, no stderr)\n' \
                        "$_rel" "$_co_rc" >&2
                fi
                rm -f "$_co_out" "$_co_err"
                _failed_repos+=("$_rel")
                continue
            fi
            rm -f "$_co_out" "$_co_err"
            [[ ! -s "$_out" ]] && continue
        
            # Parse JSON output. cloc's JSON shape:
            # { "header": {...}, "<Lang>": {nFiles, blank, comment, code}, ..., "SUM": {...} }
            # Use a small Python helper for robustness (jq isn't always present).
            _py_rc=0
            uv run python - "$_out" "$_rel" "$_per_repo" "$_per_repo_lang" <<'PY' || _py_rc=$?
        import json, sys, os
        src, rel, per_repo, per_lang = sys.argv[1:]
        with open(src) as f:
            data = json.load(f)
        total = data.pop("SUM", None)
        data.pop("header", None)
        if total:
            with open(per_repo, "a") as fh:
                fh.write(f"{rel}\t{total['nFiles']}\t{total['blank']}\t{total['comment']}\t{total['code']}\n")
        with open(per_lang, "a") as fh:
            for lang, vals in data.items():
                if not isinstance(vals, dict) or "code" not in vals:
                    continue
                fh.write(f"{rel}\t{lang}\t{vals['nFiles']}\t{vals['blank']}\t{vals['comment']}\t{vals['code']}\n")
        PY
        done
        
        if [[ ${#_failed_repos[@]} -gt 0 && $_json -eq 0 ]]; then
            ci_warn "cloc failed on ${#_failed_repos[@]} repo(s): ${_failed_repos[*]}"
        fi
        
        # ---------------------------------------------------------------------------
        # Render
        # ---------------------------------------------------------------------------
        # Use Python for table formatting: awk's number formatting + sort across
        # multiple keys gets ugly fast and we already depend on python above.
        uv run python - "$_per_repo" "$_per_repo_lang" "$_mode" "$_top_n" "$_json" "$_root" <<'PY'
        import sys, json, os
        per_repo_path, per_lang_path, mode, top_n, as_json, root = sys.argv[1:]
        top_n = int(top_n)
        as_json = as_json == "1"
        
        def read_tsv(path, cols):
            rows = []
            if not os.path.exists(path):
                return rows
            with open(path) as f:
                for line in f:
                    line = line.rstrip("\n")
                    if not line:
                        continue
                    parts = line.split("\t")
                    if len(parts) != len(cols):
                        continue
                    row = {}
                    for c, v in zip(cols, parts):
                        row[c] = int(v) if c in {"files","blank","comment","code"} else v
                    rows.append(row)
            return rows
        
        repos = read_tsv(per_repo_path, ["repo","files","blank","comment","code"])
        langs_raw = read_tsv(per_lang_path, ["repo","language","files","blank","comment","code"])
        
        # Aggregate languages across all repos.
        agg = {}
        for r in langs_raw:
            a = agg.setdefault(r["language"], {"files":0,"blank":0,"comment":0,"code":0,"repos":set()})
            a["files"] += r["files"]; a["blank"] += r["blank"]
            a["comment"] += r["comment"]; a["code"] += r["code"]
            a["repos"].add(r["repo"])
        
        totals = {
            "repos": len(repos),
            "files": sum(r["files"] for r in repos),
            "blank": sum(r["blank"] for r in repos),
            "comment": sum(r["comment"] for r in repos),
            "code": sum(r["code"] for r in repos),
        }
        totals["lines"] = totals["blank"] + totals["comment"] + totals["code"]
        
        if as_json:
            # Per-repo language breakdown for wiki card badges.
            repo_langs = []
            for r in langs_raw:
                repo_langs.append({
                    "repo": r["repo"],
                    "language": r["language"],
                    "files": r["files"],
                    "blank": r["blank"],
                    "comment": r["comment"],
                    "code": r["code"],
                })
            out = {
                "root": root,
                "totals": totals,
                "repos": sorted(repos, key=lambda x: -x["code"]),
                "languages": sorted(
                    [{"language":k, **{kk:vv for kk,vv in v.items() if kk!="repos"},
                      "repos": len(v["repos"])} for k,v in agg.items()],
                    key=lambda x: -x["code"],
                ),
                "repo_languages": repo_langs,
            }
            print(json.dumps(out, indent=2))
            sys.exit(0)
        
        def fmt(n): return f"{n:,}"
        
        BOLD = "\033[1m"; CYAN = "\033[0;36m"; GREEN = "\033[0;32m"
        DIM = "\033[2m"; NC = "\033[0m"
        if not sys.stdout.isatty():
            BOLD = CYAN = GREEN = DIM = NC = ""
        
        def hr(ch="="): print(ch * 78)
        
        # -- Summary --
        hr("=")
        print(f"{BOLD}CODE STATISTICS{NC}  root: {root}")
        hr("=")
        print(f"  Repositories scanned : {fmt(totals['repos'])}")
        print(f"  Files                : {fmt(totals['files'])}")
        print(f"  Code lines           : {GREEN}{fmt(totals['code'])}{NC}")
        print(f"  Comment lines        : {fmt(totals['comment'])}")
        print(f"  Blank lines          : {fmt(totals['blank'])}")
        print(f"  Total lines          : {BOLD}{fmt(totals['lines'])}{NC}")
        print()
        
        def print_repo_table():
            if not repos: return
            print(f"{BOLD}Per-repository (top {top_n} by code lines){NC}")
            rows = sorted(repos, key=lambda x: -x["code"])[:top_n]
            name_w = max(len(r["repo"]) for r in rows)
            name_w = min(max(name_w, 24), 60)
            print(f"  {'REPO':<{name_w}}  {'FILES':>7}  {'CODE':>12}  {'COMMENT':>10}  {'BLANK':>10}")
            print(f"  {'-'*name_w}  {'-'*7}  {'-'*12}  {'-'*10}  {'-'*10}")
            for r in rows:
                nm = r["repo"]
                if len(nm) > name_w: nm = "..." + nm[-(name_w-3):]
                print(f"  {nm:<{name_w}}  {fmt(r['files']):>7}  {fmt(r['code']):>12}  {fmt(r['comment']):>10}  {fmt(r['blank']):>10}")
            if len(repos) > top_n:
                print(f"  {DIM}... {len(repos)-top_n} more repo(s) omitted (use --top to show more){NC}")
            print()
        
        def print_lang_table():
            if not agg: return
            print(f"{BOLD}Per-language (top {top_n} by code lines){NC}")
            rows = sorted(agg.items(), key=lambda kv: -kv[1]["code"])[:top_n]
            name_w = max(len(k) for k,_ in rows)
            name_w = max(name_w, 16)
            print(f"  {'LANGUAGE':<{name_w}}  {'REPOS':>5}  {'FILES':>7}  {'CODE':>12}  {'COMMENT':>10}  {'BLANK':>10}")
            print(f"  {'-'*name_w}  {'-'*5}  {'-'*7}  {'-'*12}  {'-'*10}  {'-'*10}")
            for lang, v in rows:
                print(f"  {lang:<{name_w}}  {len(v['repos']):>5}  {fmt(v['files']):>7}  {fmt(v['code']):>12}  {fmt(v['comment']):>10}  {fmt(v['blank']):>10}")
            if len(agg) > top_n:
                print(f"  {DIM}... {len(agg)-top_n} more language(s) omitted{NC}")
            print()
        
        if mode in ("all","by-repo"):
            print_repo_table()
        if mode in ("all","by-language"):
            print_lang_table()
        PY
        

        Share feedback

        You voted thumbs down

        compliance-report

        Run a deep compliance audit of a project (or recursively across the workspace).

        Compliance
        Make target
        compliance

        compliance-report

        scripts/compliance-report

        compliance-report -- Run deep compliance audit. Usage: compliance-report [PROJECT_DIR] Audit a single project compliance-report --recursive [ROOT] Discover all .git roots under ROOT and audit each ROOT defaults to the workspace root (auto-detected).

        compliance-report [PROJECT_DIR]              Audit a single project
        compliance-report --recursive [ROOT]         Discover all .git roots under ROOT and audit each
        
        PROJECT_DIR
        Project to audit (default: current directory)
        --recursive
        Audit every nested .git repo under ROOT

        Output: Compliance score + violations on stdout. Exits non-zero on violations.

        #!/usr/bin/env bash
        # compliance-report -- Run deep compliance audit.
        #
        # Usage:
        #   compliance-report [PROJECT_DIR]     Audit a single project
        #   compliance-report --recursive [ROOT] Discover all .git roots under ROOT and audit each
        #
        # ROOT defaults to the workspace root (auto-detected).
        set -euo pipefail
        
        _SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
        # shellcheck source=../lib/checks.sh
        if ! source "$_SCRIPT_DIR/../lib/checks.sh"; then
            echo "ERROR: failed to source $_SCRIPT_DIR/../lib/checks.sh" >&2
            exit 2
        fi
        
        # Skip patterns for recursive discovery (mirrors audit-workspace)
        _SKIP_DIRS="tmp|node_modules|\.venv|__pycache__|research|python-ta-reference|\.boot-linux|\.boot-macos|dist|build|target|\.cache|\.local"
        
        if [[ "${1:-}" == "--recursive" ]]; then
            shift
            _root="${1:-$CI_WORKSPACE_ROOT}"
            _root="$(cd "$_root" && pwd)"
        
            # Discover all .git roots
            _repos=()
            _gitdirs=()
            ci_capture_pipe _gitdirs 'find "$1" -name ".git" -type d | sort' "$_root"
            for _gitdir in "${_gitdirs[@]}"; do
                _repo="$(dirname "$_gitdir")"
                echo "$_repo" | grep -qE "$_SKIP_DIRS" && continue
                _repos+=("$_repo")
            done
        
            if [[ ${#_repos[@]} -eq 0 ]]; then
                ci_warn "No git repos found under $_root"
                exit 0
            fi
        
            _total_repos=${#_repos[@]}
            _total_passed=0
            _total_checks=0
            _total_violations=0
            _full_compliance=0
            _results=()
        
            for _repo in "${_repos[@]}"; do
                _rel="${_repo#"$_root"/}"
                [[ "$_repo" == "$_root" ]] && _rel="(root)"
        
                # Run compliance, capture output and exit code
                local _rc=0
                _output="$(ci_compliance_score "$_repo" 2>&1)" || _rc=$?
                echo "$_output"
        
                # Parse score from output: "COMPLIANCE: XX% (P/T)"
                if [[ "$_output" =~ COMPLIANCE:\ ([0-9]+)%\ \(([0-9]+)/([0-9]+)\) ]]; then
                    _pct="${BASH_REMATCH[1]}"
                    _p="${BASH_REMATCH[2]}"
                    _t="${BASH_REMATCH[3]}"
                    _v=$((_t - _p))
                    _total_passed=$((_total_passed + _p))
                    _total_checks=$((_total_checks + _t))
                    _total_violations=$((_total_violations + _v))
                    [[ $_v -eq 0 ]] && _full_compliance=$((_full_compliance + 1))
                    _results+=("$(printf '%3d%%  %-40s (%d/%d)' "$_pct" "$_rel" "$_p" "$_t")")
                fi
            done
        
            # Summary
            _agg_pct=0
            [[ $_total_checks -gt 0 ]] && _agg_pct=$(( (_total_passed * 100) / _total_checks ))
        
            _tier="Tier F"
            [[ $_agg_pct -ge 40 ]] && _tier="Tier D"
            [[ $_agg_pct -ge 60 ]] && _tier="Tier C"
            [[ $_agg_pct -ge 80 ]] && _tier="Tier B"
            [[ $_agg_pct -eq 100 ]] && _tier="Tier A"
        
            echo ""
            echo ""
            ci_info "=============================================="
            ci_info "  WORKSPACE COMPLIANCE SUMMARY"
            ci_info "=============================================="
            echo ""
            for _r in "${_results[@]}"; do
                echo "  $_r"
            done
            echo ""
            echo "  -------------------------------------------"
            printf "  Repos: %d | Full compliance: %d/%d\n" "$_total_repos" "$_full_compliance" "$_total_repos"
            printf "  Checks: %d/%d | Violations: %d\n" "$_total_passed" "$_total_checks" "$_total_violations"
            echo ""
        
            if [[ $_total_violations -eq 0 ]]; then
                ci_pass "WORKSPACE: ${_agg_pct}% -- $_tier"
            else
                ci_fail "WORKSPACE: ${_agg_pct}% -- $_tier -- $_total_violations total violation(s)"
            fi
            echo "=============================================="
        
            [[ $_total_violations -eq 0 ]] && exit 0 || exit 1
        else
            ci_compliance_score "${1:-.}"
        fi
        

        Share feedback

        You voted thumbs down

        rewrite-history

        Strip blocked patterns from commit messages across git history (dry-run by default).

        History
        Make target
        rewrite-history

        rewrite-history

        scripts/rewrite-history

        rewrite-history -- Strip blocked patterns from commit messages. Reads patterns from config/blocked_commit_patterns.yaml (same as hooks). SAFE BY DEFAULT: dry-run unless --execute is passed. Always creates a backup ref before rewriting. Usage: rewrite-history # Dry-run: report offending commits rewrite-history --execute # Rewrite (prompts for confirmation) rewrite-history --execute --yes # Rewrite without confirmation rewrite-history --base SHA # Only check/rewrite SHA..HEAD rewrite-history --config PATH # Custom config file

        rewrite-history [--execute]
        --execute
        Apply the rewrite (default: dry-run). Always creates a backup ref first.

        Output: Planned/affected commits on stdout. Rewrites history only with --execute.

        #!/usr/bin/env bash
        # rewrite-history -- Strip blocked patterns from commit messages.
        # Reads patterns from config/blocked_commit_patterns.yaml (same as hooks).
        #
        # SAFE BY DEFAULT: dry-run unless --execute is passed.
        # Always creates a backup ref before rewriting.
        #
        # Usage:
        #   rewrite-history                      # Dry-run: report offending commits
        #   rewrite-history --execute            # Rewrite (prompts for confirmation)
        #   rewrite-history --execute --yes      # Rewrite without confirmation
        #   rewrite-history --base SHA           # Only check/rewrite SHA..HEAD
        #   rewrite-history --config PATH        # Custom config file
        set -euo pipefail
        
        _SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
        _CI_ROOT="$(cd "$_SCRIPT_DIR/.." && pwd)"
        if ! source "$_CI_ROOT/lib/ci.sh"; then
            echo "ERROR: failed to source $_CI_ROOT/lib/ci.sh" >&2
            exit 2
        fi
        
        # Bypass the git guard only when explicitly authorised. This script rewrites
        # history and must reach git.original; casual PATH tricks are not enough.
        if [[ "${WORKSPACE_GUARD_ADMIN:-0}" != "1" ]]; then
            ci_fail "rewrite-history requires WORKSPACE_GUARD_ADMIN=1 (admin-only history rewrite)"
            exit 1
        fi
        
        # Use system git directly: this script is an explicitly destructive tool
        # that the user invokes manually. The git-guard blocks --force which
        # filter-branch requires. Prepend system git dir to PATH so all git calls
        # (including filter-branch's internal subprocesses) bypass the guard.
        _REAL_GIT="${GIT_GUARD_REAL_GIT:-}"
        if [[ -z "$_REAL_GIT" || ! -x "$_REAL_GIT" ]]; then
            # Check for git.original first (system guard renames real git)
            for _candidate in /usr/bin/git.original /usr/local/bin/git.original /usr/bin/git /usr/local/bin/git /snap/bin/git; do
                if [[ -x "$_candidate" ]]; then
                    _REAL_GIT="$_candidate"
                    break
                fi
            done
        fi
        if [[ -z "$_REAL_GIT" ]]; then
            ci_fail "System git not found. Cannot rewrite history without real git."
            exit 1
        fi
        # Create temp dir with git symlink pointing to real binary, prepend to PATH.
        # This ensures all subprocesses (including filter-branch's msg-filter shell)
        # use the real git, not any guard wrappers.
        _GIT_TMPBIN="$(mktemp -d)"
        ln -sf "$_REAL_GIT" "$_GIT_TMPBIN/git"
        export PATH="$_GIT_TMPBIN:$PATH"
        hash -r
        trap 'rm -rf "$_GIT_TMPBIN"' EXIT
        
        # -- Defaults --
        _config="${CI_CONFIG_DIR}/blocked_commit_patterns.yaml"
        _base=""
        _execute=0
        _yes=0
        
        while [[ $# -gt 0 ]]; do
            case "$1" in
                --config)   _config="$2"; shift 2 ;;
                --base)     _base="$2"; shift 2 ;;
                --execute)  _execute=1; shift ;;
                --yes)      _yes=1; shift ;;
                -h|--help)
                    echo "Usage: rewrite-history [--execute] [--yes] [--base SHA] [--config PATH]"
                    echo ""
                    echo "Strip blocked patterns from git commit messages."
                    echo "Dry-run by default. Pass --execute to actually rewrite."
                    exit 0
                    ;;
                *) ci_fail "Unknown option: $1"; exit 1 ;;
            esac
        done
        
        [[ -f "$_config" ]] || { ci_fail "Config not found: $_config"; exit 1; }
        
        # -- Load patterns --
        _patterns=()
        while IFS= read -r _line; do
            if [[ "$_line" =~ pattern:[[:space:]]*[\"\']?(.+)[\"\']?$ ]]; then
                _pat="${BASH_REMATCH[1]}"
                _pat="${_pat%\"}" ; _pat="${_pat%\'}"
                _pat="${_pat#\"}" ; _pat="${_pat#\'}"
                _patterns+=("$_pat")
            fi
        done < "$_config"
        
        if [[ ${#_patterns[@]} -eq 0 ]]; then
            ci_warn "No patterns found in $_config"
            exit 0
        fi
        
        # Build combined regex
        _combined=""
        for _p in "${_patterns[@]}"; do
            [[ -n "$_combined" ]] && _combined="${_combined}|"
            _combined="${_combined}${_p}"
        done
        
        # -- Determine commit range --
        if [[ -n "$_base" ]]; then
            _range="${_base}..HEAD"
        else
            _range="HEAD"
            # All commits: use --all for log
        fi
        
        # Scan HEAD only (not --all, which would include backup refs from previous runs)
        _commits=""
        if [[ -n "$_base" ]]; then
            local _log_rc=0
            _commits="$(git log --format='%H' "$_range")" || _log_rc=$?
        else
            _log_rc=0
            _commits="$(git log --format='%H' HEAD)" || _log_rc=$?
        fi
        
        if [[ -z "$_commits" ]]; then
            ci_pass "No commits to check."
            exit 0
        fi
        
        # -- Scan for offending commits --
        _offending=()
        _offending_subjects=()
        while IFS= read -r _sha; do
            [[ -z "$_sha" ]] && continue
            _msg="$(git log -1 --format=%B "$_sha")"
            if echo "$_msg" | grep -qiE "$_combined"; then
                _short="$(git log -1 --format=%h "$_sha")"
                _subj="$(git log -1 --format=%s "$_sha")"
                _offending+=("$_sha")
                _offending_subjects+=("$_short $_subj")
            fi
        done <<< "$_commits"
        
        _total="$(echo "$_commits" | wc -l | tr -d ' ')"
        
        if [[ ${#_offending[@]} -eq 0 ]]; then
            ci_pass "Scanned $_total commits. No blocked patterns found."
            exit 0
        fi
        
        # -- Report --
        echo ""
        ci_info "Found ${#_offending[@]} commit(s) with blocked patterns (out of $_total):"
        echo ""
        for _s in "${_offending_subjects[@]}"; do
            echo "  $_s"
        done
        echo ""
        
        # -- Dry-run stops here --
        if [[ $_execute -eq 0 ]]; then
            ci_info "Dry-run mode. Pass --execute to rewrite."
            exit 1
        fi
        
        # -- Safety checks before rewrite --
        
        # Dirty worktree?
        if [[ -n "$(git diff --stat)" || -n "$(git diff --cached --stat)" ]]; then
            ci_fail "Working tree has uncommitted changes. Commit or stash first."
            exit 1
        fi
        
        # Confirmation
        if [[ $_yes -eq 0 ]]; then
            echo "This will rewrite ${#_offending[@]} commit message(s)."
            echo "A backup ref will be created before rewriting."
            printf "Proceed? [y/N] "
            read -r _answer
            if [[ "$_answer" != "y" && "$_answer" != "Y" ]]; then
                ci_info "Aborted."
                exit 1
            fi
        fi
        
        # -- Create backup --
        _timestamp="$(date +%Y%m%d-%H%M%S)"
        _backup_ref="refs/backup/pre-rewrite-${_timestamp}"
        git update-ref "$_backup_ref" HEAD || { ci_fail "Failed to create backup ref"; exit 1; }
        ci_pass "Backup created: $_backup_ref"
        
        # -- Rewrite --
        ci_info "Rewriting commit messages..."
        
        # FILTER_BRANCH_SQUELCH_WARNING suppresses the "this is dangerous" nag
        export FILTER_BRANCH_SQUELCH_WARNING=1
        
        # Rewrite only the current branch (HEAD), not --all.
        # --all would rewrite the backup ref too, defeating the purpose.
        _filter_range="HEAD"
        if [[ -n "$_base" ]]; then
            _filter_range="${_base}..HEAD"
        fi
        
        git filter-branch --msg-filter "
            local _filter_rc=0
            grep -viE '$_combined' || _filter_rc=$?
        " --force -- $_filter_range
        
        # Clean up filter-branch refs
        local _cleanup_rc=0
        git for-each-ref --format='delete %(refname)' refs/original/ | git update-ref --stdin || _cleanup_rc=$?
        
        # -- Verify (only HEAD, not --all which includes backup refs) --
        _remaining=0
        _verify_commits=""
        if [[ -n "$_base" ]]; then
            _verify_log_rc=0
            _verify_commits="$(git log --format='%H' "${_base}..HEAD")" || _verify_log_rc=$?
        else
            _verify_log_rc=0
            _verify_commits="$(git log --format='%H' HEAD)" || _verify_log_rc=$?
        fi
        
        while IFS= read -r _sha; do
            [[ -z "$_sha" ]] && continue
            _msg="$(git log -1 --format=%B "$_sha")"
            if echo "$_msg" | grep -qiE "$_combined"; then
                _remaining=$((_remaining + 1))
            fi
        done <<< "$_verify_commits"
        
        echo ""
        if [[ $_remaining -gt 0 ]]; then
            ci_warn "$_remaining commit(s) still contain blocked patterns after rewrite."
        else
            ci_pass "All blocked patterns removed. ${#_offending[@]} commit(s) rewritten."
        fi
        
        echo ""
        ci_info "Recovery: git reset --hard $_backup_ref"
        

        Share feedback

        You voted thumbs down

        check-boot-venv-layout

        Non-blocking audit of boot_layout.yaml + moon.yml + .pre-commit-config.yaml --project refs.

        Compliance

        check-boot-venv-layout

        ci/check_boot_venv_layout.py

        Non-blocking audit of the platform-aware boot-layout contract.

        python -m ci.check_boot_venv_layout [PROJECT_DIR]
        PROJECT_DIR
        Project to audit (default: current directory)

        Output: Score + findings on stdout. Always exits 0 (non-blocking, per FR-BL-7.7).

        #!/usr/bin/env python3
        """Non-blocking audit of the platform-aware boot-layout contract.
        
        Validates that moon.yml::project.inherited_boot_dirs entries resolve to
        existing project roots with accessible boot directories, and that
        .pre-commit-config.yaml --project refs resolve to valid venvs.
        Always exits 0 as an advisory check, with infrastructure errors
        returning 2.
        
        Checks performed:
        1. moon.yml exists (INFO + early-exit if absent).
        2. Parse + validate moon.yml::project.inherited_boot_dirs.
        3. Each inherited_boot_dirs entry resolves to a project root (OK/INFO/WARN).
        4. Existing inherited boot dirs checked for world-writable mode (WARN).
        5. moon.yml::dependsOn contains the moon project id for each
           inherited_boot_dirs entry (WARN).
        6. .pre-commit-config.yaml entry refs resolve to pyproject.toml + venv.
        7. Print summary line with ok/warn/info counts. Exit 0.
        """
        
        from __future__ import annotations
        
        import argparse
        import sys
        from pathlib import Path
        
        import yaml
        from pydantic import ValidationError
        
        from ci._boot_layout_helpers import (
            EXIT_OK,
            MoonYml,
        )
        from ci._boot_layout_helpers import (
            derive_moon_id_from_inherited as _derive_moon_id_from_inherited,
        )
        from ci._boot_layout_helpers import (
            emit as _emit,
        )
        from ci._boot_layout_helpers import (
            emit_summary as _emit_summary,
        )
        from ci._boot_layout_helpers import (
            is_world_writable as _is_world_writable,
        )
        from ci._boot_layout_helpers import (
            load_yaml as _load_yaml,
        )
        from ci._boot_layout_helpers import (
            resolve_rel as _resolve_rel,
        )
        from ci._boot_layout_helpers import (
            scan_precommit_project_refs as _scan_precommit_project_refs,
        )
        from ci._boot_layout_helpers import (
            scan_precommit_venv_python_refs as _scan_precommit_venv_python_refs,
        )
        
        # ---------------------------------------------------------------------------
        # Check functions
        # ---------------------------------------------------------------------------
        
        
        def _check_moon_exists(
            project_dir: Path,
        ) -> tuple[Path | None, MoonYml | None, list[tuple[str, str]]]:
            """Check 1+2: moon.yml exists and parses validly."""
            moon_path = project_dir / "moon.yml"
            if not moon_path.is_file():
                return (
                    None,
                    None,
                    [("INFO", "moon.yml not found: repo has no boot-layout declaration")],
                )
            try:
                raw = _load_yaml(moon_path)
            except yaml.YAMLError as e:
                return None, None, [("WARN", f"moon.yml malformed YAML: {e}")]
            if raw is None or not isinstance(raw, dict):
                return None, None, [("WARN", "moon.yml is empty or not a mapping")]
            try:
                moon = MoonYml.model_validate(raw)
            except ValidationError as e:
                return None, None, [("WARN", f"moon.yml schema violation: {e}")]
            return moon_path, moon, []
        
        
        def _check_inherited_boot_dirs(
            moon: MoonYml, project_dir: Path
        ) -> list[tuple[str, str]]:
            """Checks 3+4: inherited_boot_dirs resolution + world-writable."""
            findings: list[tuple[str, str]] = []
            proj = moon.project
            if proj is None:
                return [("INFO", "moon.yml has no project: block")]
            entries = proj.inherited_boot_dirs
            if not entries:
                return [
                    ("INFO", "inherited_boot_dirs is empty: repo has no inherited boot dirs")
                ]
            for entry in entries:
                e = entry.strip().rstrip("/")
                if not e:
                    findings.append(("WARN", "inherited_boot_dirs contains an empty entry"))
                    continue
                resolved_project = _resolve_rel(project_dir, e)
                if not resolved_project.exists():
                    findings.append(
                        (
                            "INFO",
                            f"inherited_boot_dirs entry {entry!r} does not exist"
                            " on disk (soft-optional)",
                        )
                    )
                    continue
                if not resolved_project.is_dir():
                    findings.append(
                        (
                            "WARN",
                            f"inherited_boot_dirs entry {entry!r} exists as a"
                            " file (not a directory)",
                        )
                    )
                    continue
                boot_bin = resolved_project / ".boot-linux" / "bin"
                # Accept both .boot-linux and .boot-macos as valid boot dir names
                if not boot_bin.is_dir():
                    boot_bin = resolved_project / ".boot-macos" / "bin"
                if not boot_bin.is_dir():
                    findings.append(
                        (
                            "INFO",
                            f"inherited_boot_dirs entry {entry!r}:"
                            " no .boot-*/bin at project root",
                        )
                    )
                    continue
                if _is_world_writable(boot_bin):
                    findings.append(
                        (
                            "WARN",
                            f"inherited_boot_dirs entry {entry!r}: boot bin dir"
                            " is world-writable (security risk per NFR-3.2)",
                        )
                    )
                    continue
                findings.append(
                    ("OK", f"inherited_boot_dirs entry {entry!r} resolves to {boot_bin}")
                )
            return findings
        
        
        def _check_dependson_alignment(
            moon: MoonYml | None,
        ) -> list[tuple[str, str]]:
            """Check 5: dependsOn has the moon id from each inherited_boot_dirs entry."""
            findings: list[tuple[str, str]] = []
            if moon is None:
                return findings
            proj = moon.project
            if proj is None:
                return findings
            depends = moon.dependsOn
            for entry in proj.inherited_boot_dirs:
                moon_id = _derive_moon_id_from_inherited(entry)
                if moon_id is None:
                    continue
                if moon_id in depends:
                    findings.append(
                        (
                            "OK",
                            f"inherited_boot_dirs entry {entry!r}: dependsOn"
                            f" includes {moon_id!r}",
                        )
                    )
                else:
                    findings.append(
                        (
                            "WARN",
                            f"inherited_boot_dirs entry {entry!r}: dependsOn"
                            f" MISSING {moon_id!r} (add {moon_id!r} to dependsOn"
                            " or remove the entry; per §8.2)",
                        )
                    )
            return findings
        
        
        def _check_precommit_venv_python_refs(project_dir: Path) -> list[tuple[str, str]]:
            """Check 6b: warn on deprecated .venv/bin/python -m ci.* hook entries."""
            findings: list[tuple[str, str]] = []
            pcc_path = project_dir / ".pre-commit-config.yaml"
            if not pcc_path.is_file():
                return findings
            findings.extend(
                (
                    "WARN",
                    f".pre-commit-config.yaml line {line_no}:"
                    " use uv run python or uv run --project <path> --no-sync"
                    " python -m ci.<check> (not .venv/bin/python)",
                )
                for line_no in _scan_precommit_venv_python_refs(pcc_path)
            )
            return findings
        
        
        def _check_precommit_project_refs(project_dir: Path) -> list[tuple[str, str]]:
            """Check 6: .pre-commit-config.yaml --project refs resolve."""
            findings: list[tuple[str, str]] = []
            pcc_path = project_dir / ".pre-commit-config.yaml"
            if not pcc_path.is_file():
                return findings
            refs = _scan_precommit_project_refs(pcc_path)
            seen: set[tuple[str, bool, bool]] = set()
            for line_no, ref in refs:
                target = _resolve_rel(project_dir, ref)
                ok_pyproject = (target / "pyproject.toml").is_file()
                ok_venv = (target / ".venv" / "bin" / "python").is_file()
                key = (str(target), ok_pyproject, ok_venv)
                if key in seen:
                    continue
                seen.add(key)
                if ok_pyproject and ok_venv:
                    findings.append(
                        (
                            "OK",
                            f".pre-commit-config.yaml --project {ref!r} →"
                            f" pyproject.toml + .venv/bin/python at {target}",
                        )
                    )
                elif not ok_pyproject:
                    findings.append(
                        (
                            "WARN",
                            f".pre-commit-config.yaml --project {ref!r}"
                            f" (line {line_no}) → {target} missing pyproject.toml",
                        )
                    )
                else:
                    findings.append(
                        (
                            "WARN",
                            f".pre-commit-config.yaml --project {ref!r}"
                            f" (line {line_no}) → {target} has pyproject.toml"
                            " but no .venv/bin/python (run `uv sync` there)",
                        )
                    )
            return findings
        
        
        # ---------------------------------------------------------------------------
        # Main
        # ---------------------------------------------------------------------------
        
        
        def main() -> int:
            parser = argparse.ArgumentParser(
                prog="check-boot-venv-layout",
                description=(
                    "Non-blocking audit of the boot-layout contract (SPEC-BOOT-LAYOUT)."
                ),
            )
            parser.add_argument(
                "project_dir",
                nargs="?",
                default=".",
                help="Project dir to audit (default: current dir).",
            )
            args = parser.parse_args()
            project_dir = Path(args.project_dir).resolve(strict=False)
        
            findings: list[tuple[str, str]] = []
        
            # Checks 1+2: moon.yml existence + parse
            moon_path, moon, found = _check_moon_exists(project_dir)
            findings.extend(found)
            if moon_path is None or moon is None:
                _emit_and_exit(findings)
                return EXIT_OK
        
            # Checks 3+4: inherited_boot_dirs resolution + world-writable
            findings.extend(_check_inherited_boot_dirs(moon, project_dir))
        
            # Check 5: dependsOn alignment
            findings.extend(_check_dependson_alignment(moon))
        
            # Check 6: .pre-commit-config.yaml --project refs
            findings.extend(_check_precommit_venv_python_refs(project_dir))
            findings.extend(_check_precommit_project_refs(project_dir))
        
            # Check 7: summary
            _emit_and_exit(findings)
            return EXIT_OK  # unreachable
        
        
        def _emit_and_exit(findings: list[tuple[str, str]]) -> None:
            """Print all findings + summary line, then exit 0."""
            n_ok = n_warn = n_info = 0
            for level, msg in findings:
                if level == "OK":
                    n_ok += 1
                elif level == "WARN":
                    n_warn += 1
                else:
                    n_info += 1
                _emit(level, msg)
            _emit_summary(n_ok, n_warn, n_info)
            sys.exit(EXIT_OK)
        
        
        if __name__ == "__main__":
            sys.exit(main())
        

        Share feedback

        You voted thumbs down

        scaffold-ci

        Generate CI integration files (.pre-commit-config.yaml, Makefile, config defaults) for a consumer project.

        Bootstrap
        Make target
        scaffold-ci

        scaffold-ci

        scripts/scaffold-ci

        scaffold-ci: Generate CI integration files for a consumer project. Takes a consumer directory + ci-profile.yaml and emits: .pre-commit-config.yaml, Makefile, config/*.yaml, quality_exceptions.yaml Usage: scaffold-ci --consumer PATH [--profile PATH] [--config-overrides PATH] [--dry-run] [--apply-precommit] [--apply-makefile] [--apply-configs] [--apply-all] [--append-makefile] [--analyze] [--diff] [--json] [--yes] [--no-backup] [--lax-applicable] scaffold-ci --emit-template Default (no flag): generate MISSING files only; print analyze table. --analyze: print state of every file, write nothing. --apply-* / --force-*: overwrite existing customized files (Makefile has a 5a guard refusing hand-edited files; --append-makefile adds missing targets without clobbering existing recipes).

        scaffold-ci --consumer DIR [--dry-run] [--force] [--emit-template]
        --consumer
        Target project directory containing ci-profile.yaml
        --dry-run
        Print what would be written without touching disk
        --force
        Overwrite existing .pre-commit-config.yaml and Makefile
        --emit-template
        Generate a reference ci-profile.template.yaml from required_hooks.yaml

        Output: Writes .pre-commit-config.yaml, Makefile, config/ defaults, quality_exceptions.yaml to consumer dir.

        #!/usr/bin/env bash
        # scaffold-ci: Generate CI integration files for a consumer project.
        #
        # Takes a consumer directory + ci-profile.yaml and emits:
        #   .pre-commit-config.yaml, Makefile, config/*.yaml, quality_exceptions.yaml
        #
        # Usage: scaffold-ci --consumer PATH [--profile PATH] [--config-overrides PATH] [--dry-run]
        #                   [--apply-precommit] [--apply-makefile] [--apply-configs]
        #                   [--apply-all] [--append-makefile] [--analyze] [--diff]
        #                   [--json] [--yes] [--no-backup] [--lax-applicable]
        #        scaffold-ci --emit-template
        # Default (no flag): generate MISSING files only; print analyze table.
        # --analyze: print state of every file, write nothing.
        # --apply-* / --force-*: overwrite existing customized files (Makefile has
        #   a 5a guard refusing hand-edited files; --append-makefile adds missing
        #   targets without clobbering existing recipes).
        set -euo pipefail
        
        _SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
        _CI_ROOT="$(cd "$_SCRIPT_DIR/.." && pwd)"
        
        if ! source "$_CI_ROOT/lib/ci.sh"; then
            echo "ERROR: failed to source $_CI_ROOT/lib/ci.sh" >&2
            exit 2
        fi
        if ! source "$_CI_ROOT/lib/scaffold_lib.sh"; then
            echo "ERROR: failed to source $_CI_ROOT/lib/scaffold_lib.sh" >&2
            exit 2
        fi
        
        _PARSER="$_CI_ROOT/lib/parse_hook_yaml.awk"
        _QE_TEMPLATE="$_CI_ROOT/templates/quality_exceptions.template.yaml"
        _config_overrides=""
        
        _consumer=""
        _profile=""
        _dry_run=0
        _force_pc=0
        _force_mf=0
        _force_cfg=0
        _force_all=0
        _make_backup=1
        _assume_yes=0
        _emit_template=0
        _check_template=0
        _analyze_only=0
        _diff_only=0
        _json_only=0
        _append_mf=0
        _strict_applicable=1
        
        while [[ $# -gt 0 ]]; do
            case "$1" in
                --consumer)        _consumer="$2"; shift 2 ;;
                --profile)         _profile="$2"; shift 2 ;;
                --config-overrides) _config_overrides="$2"; shift 2 ;;
                --dry-run)         _dry_run=1; shift ;;
                --force-precommit|--apply-precommit) _force_pc=1; shift ;;
                --force-makefile|--apply-makefile)   _force_mf=1; shift ;;
                --force-configs|--apply-configs)    _force_cfg=1; shift ;;
                --force-all|--apply-all)             _force_all=1; shift ;;
                --append-makefile) _append_mf=1; shift ;;
                --analyze)         _analyze_only=1; shift ;;
                --diff)           _diff_only=1; shift ;;
                --json)           _json_only=1; shift ;;
                --lax-applicable) _strict_applicable=0; shift ;;
                --yes)             _assume_yes=1; shift ;;
                --no-backup)       _make_backup=0; shift ;;
                --emit-template)   _emit_template=1; shift ;;
                --check-template)  _check_template=1; shift ;;
        --force)
                    _scl_force_error_msg
                    exit 1
                    ;;
        -h|--help)
                    _scl_help_msg
                    exit 0
                    ;;
                *) ci_fail "Unknown option: $1"; exit 1 ;;
            esac
        done
        
        if [[ -n "$_config_overrides" ]]; then
            export CI_CONFIG_OVERRIDES="$_config_overrides"
        fi
        _REGISTRY="$(ci_config_path required_hooks)"
        _CONFIG_DIR="${CI_CONFIG_DIR}"
        
        _generated=()
        _skipped=()
        
        # ── --emit-template mode ───────────────────────────────────────────────────
        if [[ $_check_template -eq 1 ]]; then _emit_template=1; fi
        
        if [[ $_emit_template -eq 1 ]]; then
            _emit_target="$_CI_ROOT/templates/ci-profile.template.yaml"
            [[ -f "$_REGISTRY" ]] || { ci_fail "required_hooks.yaml not found"; exit 1; }
            _reg_parsed="$(awk -v mode=registry -f "$_PARSER" "$_REGISTRY")" || {
                ci_fail "Failed to parse required_hooks.yaml"; exit 1
            }
            declare -a _tpl_pc=() _tpl_cm=() _tpl_pp=()
            _seq=0
            while IFS= read -r _rl; do
                if [[ -z "$_rl" ]]; then continue; fi
                IFS=$'\034' read -r _rid _rk _re _rs _rpf _ra _rm _rsaf _rapp _rf _rft <<< "$_rl"
                _sk="1"
                if [[ "$_rsaf" == "true" ]]; then _sk="0"; fi
                _mk="1"
                if [[ "$_rm" == "true" ]]; then _mk="0"; fi
                _seq=$((_seq + 1))
                _key="$(printf '%s%s%05d' "$_sk" "$_mk" "$_seq"):$_rid"
                case "$_rs" in
                    pre-commit)  _tpl_pc+=("$_key") ;;
                    commit-msg)  _tpl_cm+=("$_key") ;;
                    pre-push)    _tpl_pp+=("$_key") ;;
                esac
            done <<< "$_reg_parsed"
        
            IFS=$'\n' _tpl_pc_sorted=($(printf '%s\n' "${_tpl_pc[@]:-}" | sort)); unset IFS
            IFS=$'\n' _tpl_cm_sorted=($(printf '%s\n' "${_tpl_cm[@]:-}" | sort)); unset IFS
            IFS=$'\n' _tpl_pp_sorted=($(printf '%s\n' "${_tpl_pp[@]:-}" | sort)); unset IFS
        
            _emit_content="$(_scl_gen_template)"
            if [[ $_check_template -eq 1 ]]; then
                _tmp=$(mktemp)
                printf '%s\n' "$_emit_content" > "$_tmp"
                sed -i 's/^# Generated: .*/# Generated: NORMALIZED/' "$_tmp"
                if [[ -f "$_emit_target" ]]; then
                    _cur=$(mktemp)
                    sed 's/^# Generated: .*/# Generated: NORMALIZED/' "$_emit_target" > "$_cur"
                else
                    _cur=/dev/null
                fi
                if diff -u "$_cur" "$_tmp" > /dev/null 2>&1; then
                    rm -f "$_tmp"
                    ci_pass "Template is up to date: $_emit_target"
                    exit 0
                fi
                echo "ERROR: $_emit_target is stale; regenerate with: scripts/scaffold-ci --emit-template" >&2
                diff -u "$_cur" "$_tmp" | head -40 >&2 || true
                rm -f "$_tmp" ${_cur:+"$_cur"}
                exit 1
            fi
            if [[ $_dry_run -eq 1 ]]; then
                echo "================================================================================"
                echo "Would write: $_emit_target"
                echo "================================================================================"
                printf '%s\n' "$_emit_content"
            else
                _tmp=$(mktemp)
                printf '%s\n' "$_emit_content" > "$_tmp"
                mv -f "$_tmp" "$_emit_target"
                ci_pass "Generated $_emit_target"
            fi
            exit 0
        fi
        
        # ── Validate consumer dir ──────────────────────────────────────────────────
        if [[ -z "$_consumer" ]]; then
            ci_fail "--consumer PATH is required (or use --emit-template)"
            exit 1
        fi
        [[ -d "$_consumer" ]] || { ci_fail "Consumer directory not found: $_consumer"; exit 1; }
        _consumer="$(cd "$_consumer" && pwd)"
        
        if [[ -z "$_profile" ]]; then
            _profile="$_consumer/ci-profile.yaml"
        fi
        [[ -f "$_profile" ]] || { ci_fail "Profile not found: $_profile"; exit 1; }
        
        if ! _realpath_path="$(command -v realpath 2>&1)"; then
            ci_fail "realpath(1) not found, install coreutils >= 8.23"
            exit 2
        fi
        REL_CI="$(realpath --relative-to="$_consumer" "$_CI_ROOT")"
        
        # ── Parse profile ──────────────────────────────────────────────────────────
        _profile_parsed="$(awk -v mode=profile -f "$_PARSER" "$_profile")" || {
            ci_fail "Failed to parse profile: $_profile"; exit 1
        }
        
        _pf_version=""
        _pf_project=""
        _pf_tier=""
        _pf_languages=()
        _pf_hooks_pre_commit=()
        _pf_hooks_commit_msg=()
        _pf_hooks_pre_push=()
        _pf_override_ids=()
        _pf_override_fields=()
        _pf_override_values=()
        
        while IFS= read -r _line; do
            if [[ -z "$_line" ]]; then continue; fi
            _prefix="${_line%%$'\034'*}"
            _rest="${_line#*$'\034'}"
            case "$_prefix" in
                S)
                    _key="${_rest%%$'\034'*}"
                    _val="${_rest#*$'\034'}"
                    case "$_key" in
                        version) _pf_version="$_val" ;;
                        project) _pf_project="$_val" ;;
                        tier)    _pf_tier="$_val" ;;
                    esac
                    ;;
                L) _pf_languages+=("$_rest") ;;
                H)
                    _stage="${_rest%%$'\034'*}"
                    _hid="${_rest#*$'\034'}"
                    case "$_stage" in
                        pre-commit)  _pf_hooks_pre_commit+=("$_hid") ;;
                        commit-msg)  _pf_hooks_commit_msg+=("$_hid") ;;
                        pre-push)    _pf_hooks_pre_push+=("$_hid") ;;
                    esac
                    ;;
                O)
                    _oid="${_rest%%$'\034'*}"
                    _orest="${_rest#*$'\034'}"
                    _ofield="${_orest%%$'\034'*}"
                    _oval="${_orest#*$'\034'}"
                    _pf_override_ids+=("$_oid")
                    _pf_override_fields+=("$_ofield")
                    _pf_override_values+=("$_oval")
                    ;;
            esac
        done <<< "$_profile_parsed"
        
        # ── Phase A: Schema Parse ──────────────────────────────────────────────────
        if [[ -z "$_pf_version" ]]; then
            ci_fail "Profile missing 'version' field or version is empty"
            exit 1
        fi
        
        # ── Phase B: Required Fields ───────────────────────────────────────────────
        _missing=()
        if [[ -z "$_pf_version" ]]; then _missing+=("version"); fi
        if [[ -z "$_pf_project" ]]; then _missing+=("project"); fi
        if [[ "${#_pf_languages[@]}" -eq 0 ]]; then _missing+=("languages"); fi
        if [[ -z "$_pf_tier" ]]; then _missing+=("tier"); fi
        if [[ ${#_missing[@]} -gt 0 ]]; then
            ci_fail "Missing required fields: ${_missing[*]}"
            exit 1
        fi
        
        if [[ "$_pf_tier" == "vendored" ]]; then
            _has_hooks=0
            if [[ ${#_pf_hooks_pre_commit[@]} -gt 0 || ${#_pf_hooks_commit_msg[@]} -gt 0 || ${#_pf_hooks_pre_push[@]} -gt 0 ]]; then
                _has_hooks=1
            fi
            if [[ $_has_hooks -eq 1 ]]; then
                ci_fail "tier=vendored but hooks block is non-empty; use tier=strict or remove hooks"
                exit 1
            fi
            ci_info "tier=vendored: no CI integration generated."
            exit 0
        fi
        
        # ── Phase C: Field Value Validation ────────────────────────────────────────
        _c_errors=()
        [[ "$_pf_version" == "1" ]] || _c_errors+=("version must be 1, got '$_pf_version'")
        case "$_pf_tier" in strict|poc|vendored) ;; *) _c_errors+=("tier must be strict|poc|vendored, got '$_pf_tier'") ;; esac
        _has_any=0
        for _lang in "${_pf_languages[@]}"; do
            case "$_lang" in any) _has_any=1 ;; python|rust|node|shell|lua|go|ruby) ;; *) _c_errors+=("unknown language: $_lang") ;; esac
        done
        if [[ $_has_any -eq 1 && ${#_pf_languages[@]} -gt 1 ]]; then
            _c_errors+=("language 'any' cannot coexist with other languages")
        fi
        if ! [[ "$_pf_project" =~ ^[A-Za-z0-9][A-Za-z0-9_.-]*$ ]]; then
            _c_errors+=("project name '$_pf_project' does not match required pattern")
        fi
        if [[ ${#_c_errors[@]} -gt 0 ]]; then
            ci_fail "Validation errors:"
            for _e in "${_c_errors[@]}"; do echo "  - $_e" >&2; done
            exit 1
        fi
        
        # ── Parse registry ─────────────────────────────────────────────────────────
        [[ -f "$_REGISTRY" ]] || { ci_fail "required_hooks.yaml not found at $_REGISTRY"; exit 1; }
        _registry_parsed="$(awk -v mode=registry -f "$_PARSER" "$_REGISTRY")" || {
            ci_fail "Failed to parse required_hooks.yaml"; exit 1
        }
        
        declare -A _reg_id _reg_kind _reg_entry _reg_stage _reg_pass_fn _reg_always
        declare -A _reg_mandatory _reg_safety _reg_applicable _reg_files _reg_files_types
        
        while IFS= read -r _rline; do
            if [[ -z "$_rline" ]]; then continue; fi
            IFS=$'\034' read -r _rid _rkind _rentry _rstage _rpass _ralways _rmand _rsafety _rapp _rfiles _rftypes <<< "$_rline"
            _reg_id["$_rid"]=1
            _reg_kind["$_rid"]="$_rkind"
            _reg_entry["$_rid"]="$_rentry"
            _reg_stage["$_rid"]="$_rstage"
            _reg_pass_fn["$_rid"]="$_rpass"
            _reg_always["$_rid"]="$_ralways"
            _reg_mandatory["$_rid"]="$_rmand"
            _reg_safety["$_rid"]="$_rsafety"
            _reg_applicable["$_rid"]="$_rapp"
            _reg_files["$_rid"]="$_rfiles"
            _reg_files_types["$_rid"]="$_rftypes"
        done <<< "$_registry_parsed"
        
        # ── Phase D: Hook ID Resolution ────────────────────────────────────────────
        _d_errors=()
        _d_warnings=()
        
        _scl_validate_ids() {
            local stage="$1"; shift
            local -n _arr="_pf_hooks_$stage"
            local _id _app _found _w _lang
            for _id in "${_arr[@]:-}"; do
                if [[ -z "$_id" ]]; then continue; fi
                if [[ -z "${_reg_id[$_id]:-}" ]]; then
                    _d_errors+=("hook '$_id' in stage '$stage' is not registered in required_hooks.yaml")
                    continue
                fi
                _app="${_reg_applicable[$_id]}"
                _found=0
                for _w in $_app; do
                    if [[ "$_w" == "any" ]]; then _found=1; break; fi
                    for _lang in "${_pf_languages[@]}"; do
                        if [[ "$_w" == "$_lang" ]]; then _found=1; break; fi
                    done
                    if [[ $_found -eq 1 ]]; then break; fi
                done
                if [[ $_found -eq 0 ]]; then
                    if [[ $_strict_applicable -eq 1 ]]; then
                        _d_errors+=("hook '$_id': applicable_to=[$_app] does not intersect languages=[${_pf_languages[*]}] (wiring anyway would fail at commit time with no diagnostic; pass --lax-applicable to downgrade to warning)")
                    else
                        _d_warnings+=("hook '$_id': applicable_to=[$_app] does not intersect languages=[${_pf_languages[*]}] (--lax-applicable; hook may fail at commit time)")
                    fi
                fi
            done
            return 0
        }
        
        _scl_validate_ids pre_commit
        _scl_validate_ids commit_msg
        _scl_validate_ids pre_push
        
        if [[ ${#_d_errors[@]} -gt 0 ]]; then
            ci_fail "Hook ID resolution errors:"
            for _e in "${_d_errors[@]}"; do echo "  - $_e" >&2; done
            exit 1
        fi
        for _w in "${_d_warnings[@]:-}"; do
            if [[ -z "$_w" ]]; then continue; fi
            ci_warn "$_w"
        done
        
        # ── Phase E: Mandatory-Hook Completeness ───────────────────────────────────
        _auto_inserted=()
        declare -A _in_profile
        for _h in "${_pf_hooks_pre_commit[@]:-}" "${_pf_hooks_commit_msg[@]:-}" "${_pf_hooks_pre_push[@]:-}"; do
            if [[ -n "$_h" ]]; then _in_profile["$_h"]=1; fi
        done
        
        for _rid in "${!_reg_id[@]}"; do
            _mand="${_reg_mandatory[$_rid]}"
            _safety="${_reg_safety[$_rid]}"
            _app="${_reg_applicable[$_rid]}"
            if [[ "$_mand" != "true" ]]; then continue; fi
            if [[ "$_pf_tier" == "poc" && "$_safety" != "true" ]]; then continue; fi
            _app_ok=0
            for _w in $_app; do
                if [[ "$_w" == "any" ]]; then _app_ok=1; break; fi
                for _lang in "${_pf_languages[@]}"; do
                    if [[ "$_w" == "$_lang" ]]; then _app_ok=1; break; fi
                done
                if [[ $_app_ok -eq 1 ]]; then break; fi
            done
            if [[ $_app_ok -eq 0 ]]; then continue; fi
            if [[ -z "${_in_profile[$_rid]:-}" ]]; then
                _mstage="${_reg_stage[$_rid]}"
                case "$_mstage" in
                    pre-commit) _pf_hooks_pre_commit+=("$_rid") ;;
                    commit-msg) _pf_hooks_commit_msg+=("$_rid") ;;
                    pre-push)   _pf_hooks_pre_push+=("$_rid") ;;
                esac
                _auto_inserted+=("$_rid")
            fi
        done
        
        # ── Render generated content once (used by analyze/diff/apply/append) ──────
        _pc_target="$_consumer/.pre-commit-config.yaml"
        _mf_target="$_consumer/Makefile"
        _pc_content="$(_scl_gen_precommit)"
        _mf_content="$(_scl_gen_makefile)"
        
        # ── Inspection-only dispatch (no writes, no confirmation needed) ───────────
        if [[ $_json_only -eq 1 ]]; then
            _scl_analyze_json
            exit 0
        fi
        if [[ $_diff_only -eq 1 ]]; then
            _scl_diff_mode
            exit 0
        fi
        if [[ $_analyze_only -eq 1 ]]; then
            _scl_analyze_text
            exit 0
        fi
        
        # ── Force-flag confirmation ────────────────────────────────────────────────
        _any_force=$(( _force_pc + _force_mf + _force_cfg + _force_all ))
        _backups_written=()
        if [[ $_any_force -gt 0 && $_assume_yes -eq 0 ]]; then
            if [[ -t 1 ]]; then
                _to_overwrite=()
                for _f in "$_consumer/.pre-commit-config.yaml" "$_consumer/Makefile" \
                          "$_consumer/config/coverage_thresholds.yaml" \
                          "$_consumer/config/file_length_limits.yaml" \
                          "$_consumer/config/dead_code.yaml" \
                          "$_consumer/config/dependency_excludes.yaml" \
                          "$_consumer/config/duplicate_dependency_excludes.yaml" \
                          "$_consumer/config/markdown_docs.yaml"; do
                    if [[ -f "$_f" ]]; then _to_overwrite+=("$_f"); fi
                done
                if [[ ${#_to_overwrite[@]} -gt 0 ]]; then
                    echo "WARNING: the following existing files would be overwritten:" >&2
                    printf '  %s\n' "${_to_overwrite[@]}" >&2
                    echo "Backups (*.scaffold-bak.<epoch>) will be written unless --no-backup." >&2
                else
                    echo "WARNING: --force-* given but no existing files to overwrite (fresh scaffold)." >&2
                fi
                printf 'Proceed? [y/N] ' >&2
                IFS= read -r _answer || _answer=""
                case "$_answer" in
                    y|Y|yes|YES) ;;
                    *) echo "Aborted; no files changed."; exit 1 ;;
                esac
            else
                ci_fail "Force flags set but --yes not given and stdout is not a TTY; cannot confirm interactively. Re-run with --yes to proceed non-interactively."
                exit 1
            fi
        fi
        
        # ── Generation ─────────────────────────────────────────────────────────────
        ci_info "==> scaffolding CI integration for $_consumer (tier=$_pf_tier, languages=${_pf_languages[*]}, REL_CI=$REL_CI)"
        
        if [[ -f "$_pc_target" && $_force_pc -eq 0 && $_force_all -eq 0 ]]; then
            _pcs="$(_scl_state "$_pc_content" "$_pc_target")"
            _skipped+=("$_pc_target ($_pcs; refresh with --force-precommit, diff with --diff)")
        else
            if [[ $_dry_run -eq 1 ]]; then
                echo "================================================================================"
                echo "Would write: $_pc_target  (REL_CI=$REL_CI)"
                echo "================================================================================"
                printf '%s\n' "$_pc_content"
            else
                _scl_backup "$_pc_target" "$_make_backup" _backups_written
                printf '%s\n' "$_pc_content" > "$_pc_target"
                _generated+=("$_pc_target")
                ci_warn ".pre-commit-config.yaml updated; run 'make install-hooks' to propagate to .git/hooks/pre-commit"
            fi
        fi
        
        if [[ $_append_mf -eq 1 ]]; then
            _scl_append_makefile "$_mf_content"
        else
            if [[ -f "$_mf_target" && $_force_mf -eq 0 && $_force_all -eq 0 ]]; then
                _mfs="$(_scl_state "$_mf_content" "$_mf_target")"
                _skipped+=("$_mf_target ($_mfs; refresh with --force-makefile, append new targets with --append-makefile)")
            elif [[ -f "$_mf_target" ]]; then
                # 5a guard: refuse to overwrite a customised Makefile.
                _mf_rendered_cleaned="$(printf '%s\n' "$_mf_content" | _scl_strip_ts)"
                _mf_existing_cleaned="$(_scl_strip_ts < "$_mf_target")"
                if [[ "$_mf_rendered_cleaned" != "$_mf_existing_cleaned" ]]; then
                    ci_fail "Makefile is customised (differs from scaffold template modulo the auto-generated timestamp). scaffold-ci refuses to overwrite a hand-edited Makefile."
                    echo "  To inspect the template: scaffold-ci --consumer <path> --dry-run (look for the Makefile block)." >&2
                    echo "  To regenerate: delete the Makefile by hand (scaffold-ci offers no auto-override for customised Makefiles), then re-run --force-makefile." >&2
                    exit 1
                fi
                if [[ $_dry_run -eq 1 ]]; then
                    echo "================================================================================"
                    echo "Would refresh: $_mf_target (matches template modulo timestamp, no customisation lost)"
                    echo "================================================================================"
                    printf '%s\n' "$_mf_content"
                else
                    _scl_backup "$_mf_target" "$_make_backup" _backups_written
                    printf '%s\n' "$_mf_content" > "$_mf_target"
                    _generated+=("$_mf_target")
                fi
            else
                if [[ $_dry_run -eq 1 ]]; then
                    echo "================================================================================"
                    echo "Would write: $_mf_target"
                    echo "================================================================================"
                    printf '%s\n' "$_mf_content"
                else
                    printf '%s\n' "$_mf_content" > "$_mf_target"
                    _generated+=("$_mf_target")
                fi
            fi
        fi
        
        _force_cfg_or_all=0
        [[ $_force_cfg -eq 1 || $_force_all -eq 1 ]] && _force_cfg_or_all=1
        _scl_copy_config "$_CONFIG_DIR/coverage_thresholds.yaml" "$_consumer/config/coverage_thresholds.yaml" "coverage"         "$_force_cfg_or_all" "$_make_backup"
        _scl_copy_config "$_CONFIG_DIR/file_length_limits.yaml"   "$_consumer/config/file_length_limits.yaml"   ""                "$_force_cfg_or_all" "$_make_backup"
        _scl_copy_config "$_CONFIG_DIR/dead_code.yaml"           "$_consumer/config/dead_code.yaml"           "dead_code"       "$_force_cfg_or_all" "$_make_backup"
        _scl_copy_config "$_CONFIG_DIR/dependency_excludes.yaml" "$_consumer/config/dependency_excludes.yaml"  ""                "$_force_cfg_or_all" "$_make_backup"
        _scl_copy_config "$_CONFIG_DIR/duplicate_dependency_excludes.yaml" "$_consumer/config/duplicate_dependency_excludes.yaml" "" "$_force_cfg_or_all" "$_make_backup"
        _scl_copy_config "$_CONFIG_DIR/markdown_docs.yaml"       "$_consumer/config/markdown_docs.yaml"       ""                "$_force_cfg_or_all" "$_make_backup"
        # osv-scanner.toml is consumer-owned suppression config at repo root
        # (REQ-CVE-SCAN FR-4/FR-5): strict tier only, customized files are kept.
        if [[ "$_pf_tier" == "strict" ]]; then
            _scl_copy_config "$_CI_ROOT/templates/osv-scanner.toml" "$_consumer/osv-scanner.toml" "" "$_force_cfg_or_all" "$_make_backup"
        fi
        
        _scl_gen_qe
        
        # ── Create any missing exemption files (manifest-driven, never overwrites) ──
        if [[ $_dry_run -eq 0 ]]; then
            if ! ci_uv_run -m ci.exemption_files ensure "$_consumer"; then
                ci_warn "exemption-file ensure failed; run manually: ci_uv_run -m ci.exemption_files ensure $_consumer"
            fi
        fi
        
        # ── Summary ────────────────────────────────────────────────────────────────
        echo ""
        if [[ ${#_generated[@]} -gt 0 ]]; then
            ci_pass "Generated: ${_generated[*]}"
        fi
        if [[ ${#_skipped[@]} -gt 0 ]]; then
            ci_warn "Skipped: ${_skipped[*]}"
        fi
        if [[ ${#_auto_inserted[@]} -gt 0 ]]; then
            ci_warn "Auto-inserted mandatory hooks: ${_auto_inserted[*]}"
        fi
        if [[ ${#_backups_written[@]} -gt 0 ]]; then
            ci_warn "Backups written (restore with cp): ${_backups_written[*]}"
        fi
        
        exit 0
        

        Share feedback

        You voted thumbs down

        The Digital and AI Workspace Guardrails Platform2026 ◆ Independent AI Labs