#!/usr/bin/env bash
#MISE description="Phase 1 of 5: Validate all release prerequisites before version bump. Checks: clean working directory, GH_TOKEN presence and format, GH_ACCOUNT target, plugin validation via validate-plugins.mjs, and releasable conventional commits since last tag. Exits non-zero on any failure. Must pass before release:version can run."
set -euo pipefail

# Iter-73: Opt-in per-phase wall-clock timing instrumentation. Set
# PREFLIGHT_TIMING_PROFILE=1 in the environment to emit "phase elapsed:
# Nms" after each visible "→" phase header. Default behavior unchanged
# (no output, no measurable overhead in the common case). Uses bash 5+
# $EPOCHREALTIME for sub-second precision — preflight's shebang pins
# bash so this is portable to macOS (where the system /bin/bash is 3.2
# and lacks EPOCHREALTIME, but mise's bash is 5+). Iter-73 baseline
# measurement (2026-05-20, machine: el01 / terryli MacBook Pro M2 Max):
# preflight real time was 10.74s (4.34s user + 6.72s sys) — sys > user
# indicates heavy fork/exec, primarily from the four mise-run audit
# subprocess invocations (Checks 4d/4f/4g/4h/4i/4j). Per-phase data
# captured under this instrumentation steers iter-74+ targeted opt
# work (e.g. parallel execution candidates, cached-result reuse).
# Loose-coupled phase-label argument is descriptive only; never
# load-bearing for control flow.
preflight_timing_phase_start_seconds_for_iter73_instrumentation=""
# Iter-130 enhancement: accumulator for the top-N-slowest-checks-ranked-by-
# elapsed-milliseconds-descending bottleneck summary. Each per-phase timing
# call appends a TAB-separated "elapsed_ms\tphase_label" record; the
# end-of-script summary sort -rn -k1's this array to surface the top 5.
# Workflow: iter-124 → iter-129 perf-optimization campaign demonstrated that
# operators iterating on preflight perf must visually scan 25+ "⧗" lines to
# find the next bottleneck. This accumulator removes that manual scan.
declare -a iter130_per_phase_timing_record_array_for_top_n_slowest_bottleneck_ranking_summary=()

__preflight_timing_mark_phase_start_using_EPOCHREALTIME() {
    if [[ "${PREFLIGHT_TIMING_PROFILE:-0}" == "1" ]]; then
        preflight_timing_phase_start_seconds_for_iter73_instrumentation="$EPOCHREALTIME"
    fi
}
__preflight_timing_report_phase_elapsed_milliseconds() {
    if [[ "${PREFLIGHT_TIMING_PROFILE:-0}" == "1" ]] && [[ -n "$preflight_timing_phase_start_seconds_for_iter73_instrumentation" ]]; then
        local phase_label_for_per_phase_report="$1"
        # Iter-137: optional third arg `parallel_execution_bucket_label_for_wall_clock_attribution_awareness`
        # marks the phase as part of a concurrent execution batch (e.g.,
        # "iter134-audit-batch" for Checks 4f-4v which run in parallel via
        # iter-134's xargs -P pre-warm). Empty/unset = sequential phase
        # whose elapsed-ms directly adds to total preflight wall-clock.
        # Non-empty = parallel-batch member whose elapsed-ms is HIDDEN
        # behind the slowest sibling's elapsed-ms (wall-clock is bounded
        # by max, not sum). Iter-130 ranking output surfaces this distinction
        # so operators iterating on perf don't waste effort optimizing a
        # non-slowest parallel-batch member (saves CPU but NOT wall-clock).
        local parallel_execution_bucket_label_for_wall_clock_attribution_awareness="${2:-}"
        local end_seconds="$EPOCHREALTIME"
        # Portable sub-second math via awk (no `bc`, no `python` dep).
        local elapsed_milliseconds
        elapsed_milliseconds=$(awk -v s="$preflight_timing_phase_start_seconds_for_iter73_instrumentation" -v e="$end_seconds" 'BEGIN { printf "%.0f", (e - s) * 1000 }')
        # Iter-137: emit bucket label inline for the per-phase report too,
        # so operators reading the "⧗ phase elapsed" lines mid-stream see
        # the parallel-batch attribution without scrolling to end-of-script.
        if [[ -n "$parallel_execution_bucket_label_for_wall_clock_attribution_awareness" ]]; then
            echo "    ⧗ phase elapsed: ${elapsed_milliseconds}ms (${phase_label_for_per_phase_report})  [parallel: ${parallel_execution_bucket_label_for_wall_clock_attribution_awareness}]"
        else
            echo "    ⧗ phase elapsed: ${elapsed_milliseconds}ms (${phase_label_for_per_phase_report})"
        fi
        # Iter-130: append to accumulator for end-of-script top-N ranking.
        # TAB-separated so sort -rn -k1 works correctly even when phase labels
        # contain spaces (they always do — labels are human-readable strings).
        # Iter-137: third TAB-separated field is the parallel-bucket label
        # (empty for sequential phases). The end-of-script ranking awk
        # script displays "[parallel: BUCKET]" for non-empty third fields.
        iter130_per_phase_timing_record_array_for_top_n_slowest_bottleneck_ranking_summary+=("${elapsed_milliseconds}"$'\t'"${phase_label_for_per_phase_report}"$'\t'"${parallel_execution_bucket_label_for_wall_clock_attribution_awareness}")
    fi
}

# Iter-134: parallel fan-out of preflight Checks 4f-4v audit subprocesses.
# Iter-130 instrumentation revealed Checks 4f-4v collectively consumed
# ~2603ms wall-clock (sum), max single ~374ms (Check 4k iter-77 L3-stripped-
# path audit). All 17 audits are 100% independent: each scans the marketplace,
# writes to its own /tmp/<audit-key>.log path, and emits a one-line summary
# parsed via loose-coupled defensive grep. Zero cross-dependencies; zero
# shared mutable state. Same parallelization invariant the iter-75 marketplace
# regression suite exploited.
#
# Design (mirrors iter-75 marketplace-suite + iter-131 elapsed_ms sidecar):
#
#   Phase A (PRE-WARM, pre-Check-4f): xargs -P spawns all 17 audit-task
#     mise-runs concurrently. Each worker writes:
#       /tmp/<key>.log          ← captured stdout+stderr (existing path)
#       /tmp/<key>.exit         ← captured exit code (sidecar)
#       /tmp/<key>.elapsed_ms   ← per-audit wall-clock (sidecar, iter-131 pattern)
#     Phase A blocks until ALL audits complete.
#
#   Phase B (sequential, Checks 4f-4v inline): each existing check block runs
#     UNCHANGED post-processing (defensive-grep banner extracts), but replaces
#     the inline `if ! mise run X > /tmp/X.log 2>&1; then` with
#     `if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file X; then`
#     (reads /tmp/X.exit instead of re-running the audit). The per-check
#     iter-130 timing report is preserved bit-for-bit by seeding the phase
#     start time backwards from the externally-captured elapsed_ms sidecar.
#
# Adaptive lane count (operator-tunable via ITER134_PREFLIGHT_AUDIT_PARALLEL_LANES):
# default clamp(sysctl_hw_ncpu - 4, 4, 12), same heuristic as iter-128's
# marketplace-suite adaptive sizing. Floors at 4 for low-end laptops; ceilings
# at 12 to avoid the bun-cold-start contention plateau measured in iter-128.
# The 17 audits are non-bun-spawning shell scripts so the plateau may differ,
# but the same clamp is safe.
#
# Opt-out: ITER134_DISABLE_PREFLIGHT_AUDIT_PARALLELIZATION=1 forces -P 1 (serial
# through xargs), preserving the sidecar contract. Use when diagnosing
# audit-suite issues where parallelism could confuse output ordering.
#
# Per-audit metadata as PIPE-separated records keyed by the existing log path
# basename (without .log extension). Format: <log_sidecar_key>|<mise_task_name>|<extra_cli_args>
# The third field handles Check 4u's `--check` flag (only audit with extra args).
#
# IMPORTANT: PIPE delimiter `|` is REQUIRED (not TAB). BSD xargs (macOS) collapses
# internal whitespace — including TABs — into single SPACE characters at the
# `-I {}` substitution handoff. Empirically verified iter-134 forensic finding:
# TAB-separated records caused `cut -f1` in the xargs bash worker to return the
# FULL record (no TAB found post-collapse), triggering "File name too long"
# errors when the resulting `/tmp/<key> <task>.elapsed_ms` path exceeded 255
# bytes for the two longest audit task names (iter-103 NotebookEdit-applicability
# at 207 chars + iter-105 truncation-helper at 220 chars). PIPE `|` is non-
# whitespace and therefore preserved bit-for-bit by xargs across the BSD vs
# GNU xargs portability boundary. Safe because audit task names are pure
# kebab-case (lowercase letters, digits, hyphens) — `|` will NEVER appear.
iter134_parallelizable_preflight_audit_metadata_records_keyed_by_existing_log_path_basename=(
    "pretooluse-schema-audit|audit-pretooluse-hooks-for-deprecated-top-level-decision-schema-versus-modern-hookSpecificOutput-permissionDecision|"
    "pueue-wrap-guard-ordering-audit|audit-pretooluse-pueue-wrap-guard-is-last-pretooluse-entry-in-hooks-json-to-mitigate-github-15897-multi-hook-updatedInput-aggregation-last-writer-wins-bug|"
    "inverse-pretooluse-schema-audit|audit-non-pretooluse-hooks-for-accidental-use-of-pretooluse-only-hookSpecificOutput-permissionDecision-field-which-silently-fails-to-block-on-posttooluse-stop-userpromptsubmit-sessionstart-sessionend-events|"
    "wildcard-matcher-audit|audit-pretooluse-and-posttooluse-hooks-for-wildcard-matcher-star-or-null-which-cold-starts-bun-on-every-tool-call-causing-12-17ms-cpu-or-latency-waste-per-non-meaningful-invocation|"
    "stop-hook-additional-context-audit|audit-stop-hooks-for-additionalContext-emission-which-claude-code-silently-drops-per-official-anthropic-schema-only-decision-and-reason-fields-are-read-from-stop-hook-stdout-json|"
    "iter77-l3-stripped-path-audit|audit-hook-source-files-for-references-to-iter76-cache-populator-stripped-paths-which-silently-fail-at-layer3-runtime|"
    "iter82-conventional-commits-conformance|audit-recent-git-commit-messages-for-conventional-commits-conformance-to-prevent-silent-semantic-release-skip-of-non-standard-compound-type-scope-prefixes|"
    "iter86-orchestrator-subhook-contract-static-check|audit-pretooluse-orchestrator-subhook-contract-violations-static-check-no-stdin-stdout-exit-in-classifier-functions-and-import-meta-main-guard-on-standalone-main|"
    "iter99-posttooluse-silent-context-drop-audit|audit-no-raw-stdout-emission-in-posttooluse-typescript-hooks-because-anthropic-schema-routes-non-json-stdout-to-operator-transcript-only-and-silently-drops-it-from-claude-context|"
    "iter101-matcher-hygiene-audit|audit-pretooluse-and-posttooluse-hook-matchers-for-write-or-edit-without-multiedit-coverage-gap-surfaced-by-iter100-postooluse-orchestrator-matcher-broadening-scaled-to-marketplace-invariant|"
    "iter103-notebookedit-applicability-audit|audit-pretooluse-and-posttooluse-hooks-for-notebookedit-applicability-per-jupyter-notebook-cell-content-coverage-matrix-surfaced-by-iter102-web-research-into-2026-anthropic-canonical-file-edit-tool-quadruple|"
    "iter105-truncation-helper-audit|audit-pretooluse-and-posttooluse-hook-classifiers-for-unbounded-reason-emission-not-wrapped-in-canonical-truncation-helper-against-claude-file-spillover-threshold-iter105-marketplace-scale-of-iter104-single-hook-fix|"
    "iter106-canonical-home-audit|audit-truncation-helper-canonical-home-relocated-from-posttooluse-contract-lib-to-dedicated-cross-pretooluse-and-posttooluse-shared-lib-iter106-eliminates-iter105-cross-lib-import-awkwardness|"
    "iter110-escape-hatch-strict-audit|audit-marketplace-wide-escape-hatch-marker-detection-inventory-with-recommendation-to-migrate-hand-rolled-patterns-to-iter107-canonical-shared-helper|"
    "iter111-producer-marker-typo-audit|audit-marketplace-wide-producer-escape-hatch-marker-typo-detection-against-canonical-iter111-registry|"
    "iter113-doc-drift-detector|generate-marketplace-escape-hatch-marker-reference-documentation-from-iter111-canonical-registry|--check"
    "iter121-stale-description-audit|audit-iter121-canonical-registry-entry-description-references-discriminating-hyphen-segment-from-marker-or-consumer-basename-to-catch-stale-descriptions-after-hook-renames-spanning-iter111-and-iter114-registries|"
)

__iter134_compute_adaptive_preflight_audit_parallel_lanes_clamped_against_host_cpu_count_with_four_cpu_headroom_for_os_and_ide_mirroring_iter128_marketplace_suite_heuristic() {
    local detected_host_cpu_count
    detected_host_cpu_count=$(sysctl -n hw.ncpu 2>/dev/null || nproc 2>/dev/null || echo 8)
    local recommended_lane_count=$((detected_host_cpu_count - 4))
    # Clamp to [4, 12]. Same iter-128 empirical sweet-spot range.
    if [[ "$recommended_lane_count" -lt 4 ]]; then
        recommended_lane_count=4
    elif [[ "$recommended_lane_count" -gt 12 ]]; then
        recommended_lane_count=12
    fi
    # Opt-out for diagnostics: ITER134_DISABLE_PREFLIGHT_AUDIT_PARALLELIZATION=1
    # forces -P 1 (serial through xargs), preserving the sidecar contract.
    if [[ "${ITER134_DISABLE_PREFLIGHT_AUDIT_PARALLELIZATION:-0}" == "1" ]]; then
        recommended_lane_count=1
    fi
    echo "$recommended_lane_count"
}

__iter134_parallel_fan_out_all_preflight_audit_subprocesses_via_xargs_p_with_per_audit_log_exit_and_elapsed_ms_sidecar_capture() {
    local lane_count
    lane_count="${ITER134_PREFLIGHT_AUDIT_PARALLEL_LANES:-$(__iter134_compute_adaptive_preflight_audit_parallel_lanes_clamped_against_host_cpu_count_with_four_cpu_headroom_for_os_and_ide_mirroring_iter128_marketplace_suite_heuristic)}"
    # BSD-xargs hardening: -S 16384 to handle long mise task names (some
    # exceed 200 chars + the bash worker body). Same iter-90 hardening
    # pattern as the marketplace-suite runner.
    # shellcheck disable=SC2016
    # SC2016 false positive: $1 inside single-quoted bash -c body refers to
    # the positional arg passed to the NESTED bash, not the outer scope.
    printf '%s\n' "${iter134_parallelizable_preflight_audit_metadata_records_keyed_by_existing_log_path_basename[@]}" | \
        xargs -S 16384 -P "$lane_count" -I {} bash -c '
            pipe_separated_metadata_record="$1"
            # Use cut -d"|" (PIPE delimiter). See array-definition header comment
            # for the BSD-xargs-collapses-TAB-to-SPACE empirical forensic.
            audit_log_sidecar_key="$(echo "$pipe_separated_metadata_record" | cut -d"|" -f1)"
            audit_mise_task_name="$(echo "$pipe_separated_metadata_record" | cut -d"|" -f2)"
            audit_extra_cli_args="$(echo "$pipe_separated_metadata_record" | cut -d"|" -f3)"
            audit_wall_clock_start_seconds_for_elapsed_ms_sidecar_capture="$EPOCHREALTIME"
            if mise run "$audit_mise_task_name" $audit_extra_cli_args > "/tmp/$audit_log_sidecar_key.log" 2>&1; then
                echo 0 > "/tmp/$audit_log_sidecar_key.exit"
            else
                echo "$?" > "/tmp/$audit_log_sidecar_key.exit"
            fi
            audit_wall_clock_end_seconds_for_elapsed_ms_sidecar_capture="$EPOCHREALTIME"
            awk -v s="$audit_wall_clock_start_seconds_for_elapsed_ms_sidecar_capture" \
                -v e="$audit_wall_clock_end_seconds_for_elapsed_ms_sidecar_capture" \
                "BEGIN { printf \"%.0f\", (e - s) * 1000 }" \
                > "/tmp/$audit_log_sidecar_key.elapsed_ms"
        ' _ {}
}

__iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file() {
    local audit_log_sidecar_key="$1"
    local exit_code_sidecar_file="/tmp/$audit_log_sidecar_key.exit"
    if [[ ! -f "$exit_code_sidecar_file" ]]; then
        # Defensive: pre-warm couldn't produce sidecar (xargs aborted, disk
        # full, etc.). Treat as failure so the gate doesn't false-green on
        # missing evidence. Same iter-75 marketplace-suite defensive pattern.
        return 1
    fi
    local captured_exit_code
    captured_exit_code=$(cat "$exit_code_sidecar_file")
    [[ "$captured_exit_code" == "0" ]]
}

__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file() {
    # Preserves iter-130 bottleneck-ranking accuracy across parallel pre-warm:
    # seeds preflight_timing_phase_start_seconds backwards by the externally-
    # captured elapsed-ms so the subsequent
    # __preflight_timing_report_phase_elapsed_milliseconds call reports the
    # correct per-audit wall-clock (the time the audit actually took in Phase A),
    # NOT the trivial post-processing time after the parallel pre-warm.
    local audit_log_sidecar_key="$1"
    if [[ "${PREFLIGHT_TIMING_PROFILE:-0}" != "1" ]]; then
        return 0
    fi
    local elapsed_ms_sidecar_file="/tmp/$audit_log_sidecar_key.elapsed_ms"
    if [[ ! -f "$elapsed_ms_sidecar_file" ]]; then
        # Fall back to current EPOCHREALTIME so the timing helper reports ~0ms
        # rather than a wild stale value. Better-than-nothing graceful degrade.
        preflight_timing_phase_start_seconds_for_iter73_instrumentation="$EPOCHREALTIME"
        return 0
    fi
    local externally_captured_audit_elapsed_ms
    externally_captured_audit_elapsed_ms=$(cat "$elapsed_ms_sidecar_file")
    preflight_timing_phase_start_seconds_for_iter73_instrumentation=$(awk \
        -v e="$EPOCHREALTIME" \
        -v ms="$externally_captured_audit_elapsed_ms" \
        'BEGIN { printf "%.6f", e - (ms / 1000) }')
}

# Iter-130: top-N-slowest-checks bottleneck ranking summary. Invoked at
# end-of-script when PREFLIGHT_TIMING_PROFILE=1 is set. Sorts the
# per-phase accumulator by elapsed-ms descending and prints the top N
# (default: 5) so operators iterating on preflight perf see the next
# bottleneck WITHOUT manually scanning all "⧗" lines.
__iter130_emit_top_n_slowest_preflight_checks_ranked_by_elapsed_milliseconds_descending_bottleneck_summary() {
    if [[ "${PREFLIGHT_TIMING_PROFILE:-0}" != "1" ]]; then
        return 0
    fi
    if [[ "${#iter130_per_phase_timing_record_array_for_top_n_slowest_bottleneck_ranking_summary[@]}" -eq 0 ]]; then
        return 0
    fi
    local top_n_threshold_for_slowest_check_ranking_display="${ITER130_TOP_N_SLOWEST_CHECKS_TO_DISPLAY:-5}"
    echo ""
    echo "    ⧗ ─── Top ${top_n_threshold_for_slowest_check_ranking_display} slowest preflight checks (iter-130 bottleneck ranking, iter-137 parallelism-aware) ───"
    # Sort -rn -k1 (descending by first TAB-separated field, numeric).
    # printf '%s\n' joined with implicit "\n" gives one record per line.
    # Iter-137: third TAB-separated field is the parallel-bucket label
    # (empty for sequential phases). Render "[parallel: BUCKET]" suffix
    # when non-empty so operators see the parallelization context.
    printf '%s\n' "${iter130_per_phase_timing_record_array_for_top_n_slowest_bottleneck_ranking_summary[@]}" \
        | sort -rn -k1 \
        | head -n "${top_n_threshold_for_slowest_check_ranking_display}" \
        | awk -F'\t' '{
            if ($3 != "") {
                printf "      %2d. %6d ms  %s  [parallel: %s]\n", NR, $1, $2, $3
            } else {
                printf "      %2d. %6d ms  %s\n", NR, $1, $2
            }
        }'
    echo "    ⧗ (override count via ITER130_TOP_N_SLOWEST_CHECKS_TO_DISPLAY=N)"
    # Iter-137 wall-clock-attribution hint: enumerate distinct parallel
    # buckets and surface the SLOWEST member of each (= critical path).
    # Operators see "phases in [parallel: BUCKET] run concurrently —
    # wall-clock is bounded by the slowest member only" so they don't
    # waste effort optimizing a non-critical-path member.
    local -A iter137_max_elapsed_ms_per_parallel_execution_bucket=()
    local -A iter137_slowest_member_label_per_parallel_execution_bucket=()
    local timing_record current_elapsed_ms current_label current_bucket
    for timing_record in "${iter130_per_phase_timing_record_array_for_top_n_slowest_bottleneck_ranking_summary[@]}"; do
        current_bucket=$(echo "$timing_record" | cut -f3)
        if [[ -z "$current_bucket" ]]; then
            continue
        fi
        current_elapsed_ms=$(echo "$timing_record" | cut -f1)
        current_label=$(echo "$timing_record" | cut -f2)
        # Track the slowest (= critical-path) member per bucket.
        if [[ -z "${iter137_max_elapsed_ms_per_parallel_execution_bucket[$current_bucket]:-}" ]] || \
           [[ "$current_elapsed_ms" -gt "${iter137_max_elapsed_ms_per_parallel_execution_bucket[$current_bucket]}" ]]; then
            iter137_max_elapsed_ms_per_parallel_execution_bucket[$current_bucket]=$current_elapsed_ms
            iter137_slowest_member_label_per_parallel_execution_bucket[$current_bucket]=$current_label
        fi
    done
    if [[ "${#iter137_max_elapsed_ms_per_parallel_execution_bucket[@]}" -gt 0 ]]; then
        echo ""
        echo "    ⧗ NOTE (iter-137 wall-clock attribution): phases marked [parallel: BUCKET] run"
        echo "      concurrently — wall-clock is bounded by the SLOWEST member only (= critical path)."
        echo "      Optimizing a non-slowest member saves CPU but NOT wall-clock. Critical paths:"
        local current_bucket_for_critical_path_report
        for current_bucket_for_critical_path_report in "${!iter137_max_elapsed_ms_per_parallel_execution_bucket[@]}"; do
            echo "        - ${current_bucket_for_critical_path_report}: ${iter137_max_elapsed_ms_per_parallel_execution_bucket[$current_bucket_for_critical_path_report]}ms  ←  ${iter137_slowest_member_label_per_parallel_execution_bucket[$current_bucket_for_critical_path_report]}"
        done
    fi
}

# Whole-script timer: lets the operator confirm sum-of-phases ≈ wall-time
# (sanity check for the per-phase instrumentation itself).
preflight_timing_whole_script_start_seconds_for_iter73_instrumentation=""
if [[ "${PREFLIGHT_TIMING_PROFILE:-0}" == "1" ]]; then
    preflight_timing_whole_script_start_seconds_for_iter73_instrumentation="$EPOCHREALTIME"
    echo "    ⧗ PREFLIGHT_TIMING_PROFILE=1 — per-phase wall-clock instrumentation active"
fi

echo "═══════════════════════════════════════════════════════════"
echo "  Phase 1: PREFLIGHT"
echo "═══════════════════════════════════════════════════════════"

# Check 1: Working directory clean
__preflight_timing_mark_phase_start_using_EPOCHREALTIME
echo "→ Checking working directory..."
if [[ -n "$(git status --porcelain)" ]]; then
    echo "  ✗ Working directory not clean"
    git status --short
    exit 1
fi
echo "  ✓ Working directory clean"
__preflight_timing_report_phase_elapsed_milliseconds "Check 1: working directory clean"

# Check 2: GitHub authentication (token file check - no API calls to avoid process storms)
__preflight_timing_mark_phase_start_using_EPOCHREALTIME
echo "→ Checking GitHub authentication..."
if [[ -z "${GH_TOKEN:-}" ]]; then
    echo "  ✗ GH_TOKEN not set"
    echo "    Run: eval \"\$(mise env)\" or check .mise.toml"
    exit 1
fi
# Validate token is not empty/whitespace
if [[ -z "$(echo "$GH_TOKEN" | tr -d '[:space:]')" ]]; then
    echo "  ✗ GH_TOKEN is empty"
    exit 1
fi
# Check token format (should start with ghp_ or github_pat_)
if [[ ! "$GH_TOKEN" =~ ^(ghp_|github_pat_) ]]; then
    echo "  ⚠ GH_TOKEN format unusual (expected ghp_* or github_pat_*)"
fi
echo "  ✓ GH_TOKEN present (${#GH_TOKEN} chars)"

# Check 3: Expected account (from GH_ACCOUNT env, set by mise)
if [[ -n "${GH_ACCOUNT:-}" ]]; then
    echo "  ✓ Target account: $GH_ACCOUNT (from GH_ACCOUNT env)"
else
    echo "  ⚠ GH_ACCOUNT not set - releasing with token from mise.toml"
fi
__preflight_timing_report_phase_elapsed_milliseconds "Check 2-3: GH_TOKEN + GH_ACCOUNT env"

# Check 4: Plugin validation
__preflight_timing_mark_phase_start_using_EPOCHREALTIME
echo "→ Validating plugins..."
if ! bun scripts/validate-plugins.mjs 2>/dev/null; then
    echo "  ✗ Plugin validation failed"
    exit 1
fi
echo "  ✓ Plugins validated"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4: plugin manifest validation (bun)"

# Check 4b: Self-evolution sandwich (top reminder + bottom reflection on all skills).
#
# Iter-74 perf rewrite: replaces the iter-73-baseline 217-file ×
# ~8-fork-exec-per-file storm (`awk` + `head` + `grep` + `grep` + `tail`
# + `cut` + `wc` + `tr` per file = ~1736 forks total) with a single-pass
# awk scanner that processes all SKILL.md files in one process and emits
# TSV per-file audit records, then a single bash loop iterates the TSV
# with parameter-expansion-only ops (no fork/exec) to compute diagnostics
# and increment the violation counter. Iter-73 baseline: 2032ms / 20.6%
# of preflight wall time. Iter-74 target: ~500ms (~75% reduction). The
# scanner and its parity regression test:
#   scripts/skill-md-self-evolution-sandwich-single-pass-awk-scanner.awk
#   .mise/tasks/tests/test-skill-md-self-evolution-sandwich-single-pass-awk-scanner-parity-against-iter73-fork-storm-bash-loop-baseline.sh
__preflight_timing_mark_phase_start_using_EPOCHREALTIME
echo "→ Checking self-evolution sandwich..."
SANDWICH_ERRORS=0
SANDWICH_SCANNER_AWK_SCRIPT_PATH="$(dirname "$0")/../../../scripts/skill-md-self-evolution-sandwich-single-pass-awk-scanner.awk"
# Single awk invocation emits TSV: filename\thas_top_marker\tlast_post_exec_line\ttotal_lines
while IFS=$'\t' read -r skill_md_filename has_self_evolving_marker last_post_execution_reflection_line total_line_count_for_file; do
    # Convert "plugins/X/skills/Y/SKILL.md" → "X:Y" via parameter expansion
    # only — no subshells, no fork/exec (preserves iter-71 SC2001 fix).
    SKILL_PATH_BUFFER="${skill_md_filename#plugins/}"
    SKILL_PATH_BUFFER="${SKILL_PATH_BUFFER%/SKILL.md}"
    SKILL_NAME="${SKILL_PATH_BUFFER/\/skills\//:}"
    # Top check: self-evolving marker must be present in first 25 body lines.
    if [[ "$has_self_evolving_marker" -eq 0 ]]; then
        echo "  ✗ $SKILL_NAME: missing Self-Evolving reminder at top"
        SANDWICH_ERRORS=$((SANDWICH_ERRORS + 1))
    fi
    # Bottom check: Post-Execution Reflection must exist AND be within last 15 lines.
    if [[ "$last_post_execution_reflection_line" -eq 0 ]]; then
        echo "  ✗ $SKILL_NAME: missing Post-Execution Reflection"
        SANDWICH_ERRORS=$((SANDWICH_ERRORS + 1))
    elif [[ "$((total_line_count_for_file - last_post_execution_reflection_line))" -gt 15 ]]; then
        echo "  ✗ $SKILL_NAME: Post-Execution Reflection not at bottom"
        SANDWICH_ERRORS=$((SANDWICH_ERRORS + 1))
    fi
done < <(awk -f "$SANDWICH_SCANNER_AWK_SCRIPT_PATH" plugins/*/skills/*/SKILL.md)
if [[ "$SANDWICH_ERRORS" -gt 0 ]]; then
    echo "  ✗ Self-evolution sandwich check failed ($SANDWICH_ERRORS issue(s))"
    exit 1
fi
echo "  ✓ All skills have self-evolution sandwich (top + bottom)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4b: self-evolution sandwich (top+bottom) across all SKILL.md"

# Check 4c: Hook registration sanity (post-incident regression catcher).
# Catches: stale paths in settings.json, duplicate commands, SKIP_HOOK_SYNC
# typos, plugin/skip-list/settings.json drift. See:
# scripts/validate-hook-registration.sh for details.
__preflight_timing_mark_phase_start_using_EPOCHREALTIME
if ! bash "$(dirname "$0")/../../../scripts/validate-hook-registration.sh"; then
    exit 1
fi
__preflight_timing_report_phase_elapsed_milliseconds "Check 4c: hook registration sanity"

# Check 4d: ABSORBED into Check 4e by iter-138.
# The chronicle-slicing 37-assertion regression test was relocated from
# .mise/tasks/release/test-chronicle-slicing to .mise/tasks/tests/test-
# chronicle-slicing-*.sh so the iter-50/iter-75 marketplace-hook-regression-
# suite auto-discovers it. Result: chronicle-slicing now runs INSIDE Check 4e's
# xargs -P parallel batch (concurrent with the ~1135ms longest test rather
# than after it, so no wall-clock increase to Check 4e), and the previous
# Check 4d sequential 670ms is fully eliminated from preflight (~14% reduction
# in total preflight wall-clock from ~4958ms to ~4288ms). The chronicle test's
# 37 assertions are still verified pre-tag-publish (Check 4e fails on any
# member-test failure) — the iter-50 marketplace runner aggregates and reports
# any failure with full per-test stdout.
#
# Operators previously running `mise run release:test-chronicle-slicing`
# can now invoke `bash .mise/tasks/tests/test-chronicle-slicing-*.sh` (the
# file is auto-executable; same script content).

# Check 4e: Marketplace-wide hook regression suite. Iter-51 wire-up of
# the iter-50 mise task into the release gate. Auto-discovers every
# plugins/*/hooks/tests/test-*.sh and runs it. Catches behavioral
# regressions in hooks BEFORE the release publishes a tag that would
# deploy the broken behavior to operator Layer 3 caches (see iter-42
# docs/HOOKS.md for the 3-layer cache lifecycle).
__preflight_timing_mark_phase_start_using_EPOCHREALTIME
echo "→ Running marketplace-wide hook regression suite..."
if ! mise run test-marketplace-hook-regression-suite >/tmp/hook-regression-test.log 2>&1; then
    echo "  ✗ Hook regression suite FAILED — see /tmp/hook-regression-test.log"
    tail -20 /tmp/hook-regression-test.log
    exit 1
fi
# Loose-coupled defensive grep — see iter-70 hardening note above.
HOOK_TESTS_PASSED=$( { grep -oE 'Test files PASSED:[[:space:]]+[0-9]+' /tmp/hook-regression-test.log || true; } | head -1 | awk '{print $NF}' || echo 0)
HOOK_TESTS_FAILED=$( { grep -oE 'Test files FAILED:[[:space:]]+[0-9]+' /tmp/hook-regression-test.log || true; } | head -1 | awk '{print $NF}' || echo 0)
echo "  ✓ Hook regression: ${HOOK_TESTS_PASSED:-0} test files passed (${HOOK_TESTS_FAILED:-0} failed)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4e: marketplace-wide hook regression suite"

# Iter-134: Phase A — parallel fan-out of all 17 marketplace audits (Checks
# 4f-4v). Each audit's mise-run subprocess writes its existing /tmp/<key>.log
# path plus iter-134 sidecars (.exit, .elapsed_ms). The subsequent Check 4f-4v
# inline blocks become non-blocking exit-code checks that read sidecars instead
# of re-running the audit. Compresses ~2.6s of sequential audit work into
# ~370ms (longest single audit caps wall-clock; iter-128 lane-clamp heuristic
# avoids contention plateau). Saves ~2.2s of preflight wall-clock (~22%
# reduction in total preflight time).
__iter134_parallel_fan_out_all_preflight_audit_subprocesses_via_xargs_p_with_per_audit_log_exit_and_elapsed_ms_sidecar_capture

# Check 4f: PreToolUse schema-correctness audit (iter-60 gate). Per Claude
# Code v2.0.10+ spec, PreToolUse top-level `decision: "block"|"deny"`
# is DEPRECATED — hooks using it silently FAIL TO BLOCK. The audit
# scans every plugins/*/hooks/pretooluse-* source and exits non-zero
# if any deprecated-schema hook is found. Blocks tag publish so a
# deprecated-schema PreToolUse regression cannot escape to Layer 3
# operator caches (see iter-42 docs/HOOKS.md for cache lifecycle).
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file pretooluse-schema-audit
echo "→ Running PreToolUse schema-correctness audit..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file pretooluse-schema-audit; then
    echo "  ✗ PreToolUse schema audit FAILED — see /tmp/pretooluse-schema-audit.log"
    tail -20 /tmp/pretooluse-schema-audit.log
    exit 1
fi
# Loose-coupled defensive grep — see iter-70 hardening note above.
SCHEMA_MODERN=$( { grep -oE 'MODERN-CORRECT[^:]*:[[:space:]]+[0-9]+' /tmp/pretooluse-schema-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
SCHEMA_HELPER=$( { grep -oE 'HELPER-WRAPPED[^:]*:[[:space:]]+[0-9]+' /tmp/pretooluse-schema-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
SCHEMA_DEPRECATED=$( { grep -oE 'DEPRECATED-WARNING[^:]*:[[:space:]]+[0-9]+' /tmp/pretooluse-schema-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
echo "  ✓ PreToolUse schema: ${SCHEMA_MODERN:-0} modern + ${SCHEMA_HELPER:-0} helper-wrapped (${SCHEMA_DEPRECATED:-0} deprecated)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4f: PreToolUse schema-correctness audit (iter-60 gate)" "iter134-audit-batch"

# Check 4g: pueue-wrap-guard last-PreToolUse-entry ordering audit (iter-61
# gate). Per GitHub #15897, when multiple PreToolUse hooks fire on the
# same tool invocation, the LAST hook's hookSpecificOutput response
# replaces earlier ones — including resetting updatedInput to undefined
# when the last hook doesn't emit it. pretooluse-pueue-wrap-guard.ts
# carries TWO load-bearing mutations: OP_SERVICE_ACCOUNT_TOKEN injection
# and pueue command-wrapping. Both live in updatedInput.command. If
# any later PreToolUse hook runs after pueue-wrap-guard, both mutations
# get silently clobbered. The audit walks every hooks.json that
# registers pueue-wrap-guard and asserts it's the LAST PreToolUse
# entry. Blocks tag publish so a regression cannot escape to Layer 3
# operator caches (see iter-42 docs/HOOKS.md for cache lifecycle).
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file pueue-wrap-guard-ordering-audit
echo "→ Running pueue-wrap-guard last-PreToolUse-entry ordering audit..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file pueue-wrap-guard-ordering-audit; then
    echo "  ✗ Pueue-wrap-guard ordering audit FAILED — see /tmp/pueue-wrap-guard-ordering-audit.log"
    tail -20 /tmp/pueue-wrap-guard-ordering-audit.log
    exit 1
fi
# Loose-coupled defensive grep — see iter-70 hardening note above.
ORDERING_OK=$( { grep -oE 'ORDERING-OK[^:]*:[[:space:]]+[0-9]+' /tmp/pueue-wrap-guard-ordering-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
ORDERING_VIOLATION=$( { grep -oE 'ORDERING-VIOLATION[^:]*:[[:space:]]+[0-9]+' /tmp/pueue-wrap-guard-ordering-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
echo "  ✓ Pueue-wrap-guard ordering: ${ORDERING_OK:-0} ok (${ORDERING_VIOLATION:-0} violations)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4g: pueue-wrap-guard last-entry ordering audit (iter-61 gate)" "iter134-audit-batch"

# Check 4h: INVERSE PreToolUse schema audit (iter-62 gate). Symmetric
# companion to iter-60 Check 4f. Where Check 4f catches PreToolUse
# hooks using the DEPRECATED top-level decision:"block" schema (silent
# fail on Claude Code v2.0.10+), Check 4h catches the inverse: non-
# PreToolUse hooks (PostToolUse, Stop, UserPromptSubmit, SessionStart,
# SessionEnd) accidentally using the PreToolUse-only
# hookSpecificOutput.permissionDecision field. Per the official spec,
# only PreToolUse consumes permissionDecision; non-PreToolUse events
# expect top-level decision:"block" + reason. A non-PreToolUse hook
# emitting permissionDecision goes to no consumer — silent fail. At
# iter-62 build time the marketplace has ZERO instances. This gate
# is preventive: blocks tag publish so a future regression cannot
# escape to Layer 3 operator caches (see iter-42 docs/HOOKS.md for
# cache lifecycle).
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file inverse-pretooluse-schema-audit
echo "→ Running INVERSE PreToolUse schema-correctness audit (non-PreToolUse hooks)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file inverse-pretooluse-schema-audit; then
    echo "  ✗ Inverse PreToolUse schema audit FAILED — see /tmp/inverse-pretooluse-schema-audit.log"
    tail -20 /tmp/inverse-pretooluse-schema-audit.log
    exit 1
fi
# Loose-coupled defensive grep — see iter-70 hardening note above.
INV_CORRECT=$( { grep -oE 'SCHEMA-CORRECT-FOR-EVENT:[[:space:]]+[0-9]+' /tmp/inverse-pretooluse-schema-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
INV_NO_BLOCK=$( { grep -oE 'NO-BLOCKING-EMITTED[^:]*:[[:space:]]+[0-9]+' /tmp/inverse-pretooluse-schema-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
INV_WRONG=$( { grep -oE 'WRONG-FIELD-SILENT-FAIL[^:]*:[[:space:]]+[0-9]+' /tmp/inverse-pretooluse-schema-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
echo "  ✓ Inverse schema: ${INV_CORRECT:-0} correct + ${INV_NO_BLOCK:-0} no-block (${INV_WRONG:-0} wrong-field silent-fails)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4h: INVERSE PreToolUse schema audit (iter-62 gate)" "iter134-audit-batch"

# Check 4i: Wildcard-matcher audit (iter-65 gate). Scales iter-63 +
# iter-64 perf forensic findings into preventive infrastructure.
# PreToolUse and PostToolUse hooks registered with matcher "*" or
# null/missing cause Claude Code to cold-start bun on EVERY tool call
# (~12-17ms each). iter-63 measured the cost (~1360ms wasted per
# session for a single 100-tool session at 80% non-meaningful calls).
# iter-63 narrowed pretooluse-subprocess-stdin-inlet-guard from "*"
# to "Bash"; iter-64 did the same for posttooluse-subprocess-orphan-
# cleanup. iter-65 audit walks every plugins/*/hooks/hooks.json and
# blocks tag publish if any new wildcard matcher appears without an
# explicit WILDCARD-MATCHER-OK source-comment escape hatch (with a
# justification reason ≥ 10 chars). Prevents perf regressions from
# escaping to Layer 3 operator caches (see iter-42 docs/HOOKS.md for
# cache lifecycle).
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file wildcard-matcher-audit
echo "→ Running wildcard-matcher audit (PreToolUse + PostToolUse hooks)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file wildcard-matcher-audit; then
    echo "  ✗ Wildcard-matcher audit FAILED — see /tmp/wildcard-matcher-audit.log"
    tail -20 /tmp/wildcard-matcher-audit.log
    exit 1
fi
# Loose-coupled defensive grep — see iter-70 hardening note above.
WM_SCOPED=$( { grep -oE 'SCOPED-MATCHER[^:]*:[[:space:]]+[0-9]+' /tmp/wildcard-matcher-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
WM_WITH_OK=$( { grep -oE 'WILDCARD-WITH-OK-MARKER[^:]*:[[:space:]]+[0-9]+' /tmp/wildcard-matcher-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
WM_VIOL=$( { grep -oE 'WILDCARD-VIOLATION[^:]*:[[:space:]]+[0-9]+' /tmp/wildcard-matcher-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
echo "  ✓ Wildcard-matcher: ${WM_SCOPED:-0} scoped + ${WM_WITH_OK:-0} with-ok-marker (${WM_VIOL:-0} violations)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4i: wildcard-matcher audit (iter-65 gate)" "iter134-audit-batch"

# Check 4j: additionalContext-Silently-Dropped Pentad audit (iter-67 gate +
# iter-68 trinity expansion + iter-69 pentad completion). Scales iter-66
# single-hook fix into preventive infrastructure across the full pentad of
# event types where additionalContext is silently dropped:
#
#   - Stop hooks: per official Anthropic schema (GitHub #19115, also
#     code.claude.com/docs/en/hooks), read ONLY {decision:'block', reason}
#     — any additionalContext (top-level OR nested) silently dropped.
#   - SubagentStop hooks (iter-68): same schema as Stop per
#     code.claude.com/docs/en/hooks ("SubagentStop hooks use the same
#     decision control format as Stop hooks"). Marketplace 0; preventive.
#   - SessionEnd hooks (iter-68): per Go type definitions in
#     CorridorSecurity/hookshot (pkg.go.dev/github.com/CorridorSecurity/
#     hookshot/claude), SessionEndOK returns EMPTY output — SessionEnd
#     cannot inject ANY context (session terminating). Marketplace 0.
#   - PreCompact hooks (iter-69): same {decision:'block', reason} schema
#     family as Stop. Common use: pre-compaction transcript backup via
#     async:true (Jan 2026 feature). Marketplace 0.
#   - Notification hooks (iter-69): purely informational, NO decision
#     capability ("Exit Code 2 Behavior: N/A — stderr to user only").
#     Subtypes: permission_prompt, idle_prompt, auth_success. Marketplace 0.
#
# iter-66 forensic: itp-hooks stop-orchestrator was pre-iter-66 emitting
# {additionalContext: <aggregated subhook summary>} to stdout JSON.
# Claude Code parsed the JSON, found no decision field, treated the Stop
# as "don't block", and silently ignored the additionalContext field
# entirely. Subhook summaries from stop-markdown-lint, stop-ty-project-
# check, and stop-hook-error-summary reached no one — operators got no
# transcript visibility, Claude got no context. The fix routed the
# summary to STDERR (transcript-visible via Ctrl-R) instead of
# pretending stdout JSON would reach Claude.
#
# Audit walks every plugins/*/hooks/hooks.json that registers a Stop,
# SubagentStop, or SessionEnd hook, resolves the source file, strips
# JSDoc + line comments, and blocks tag publish if any source references
# additionalContext in non-comment code without an explicit
# STOP-HOOK-ADDITIONAL-CONTEXT-OK source-comment escape hatch (≥ 10-char
# justification reason). Per-event-type breakdown shows which hook type
# each violation belongs to. Prevents silent-drop regressions from
# escaping to Layer 3 operator caches (see iter-42 docs/HOOKS.md for
# cache lifecycle).
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file stop-hook-additional-context-audit
echo "→ Running additionalContext-silently-dropped pentad audit (Stop/SubagentStop/SessionEnd/PreCompact/Notification)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file stop-hook-additional-context-audit; then
    echo "  ✗ Stop-hook additionalContext-emission audit FAILED — see /tmp/stop-hook-additional-context-audit.log"
    tail -30 /tmp/stop-hook-additional-context-audit.log
    exit 1
fi
# Loose-coupled summary grep — insulates preflight from audit-banner
# phrasing evolution (iter-67 "Stop hooks", iter-68 same, iter-69 renamed
# to "pentad-member hooks"). Iter-69 lesson: assertion greps should target
# count semantics, not banner phrasing. Same fix applied to the regression
# test in iter-69. The `|| true` and `|| echo 0` defenses ensure pipefail
# can't abort preflight on empty grep results (e.g. when a future audit
# rename breaks the regex — gate should report 0/?/? not crash).
SHAC_SCANNED=$( { grep -oE 'Total registered [a-zA-Z -]+ scanned:[[:space:]]+[0-9]+' /tmp/stop-hook-additional-context-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
SHAC_CLEAN=$( { grep -oE 'CLEAN \(no additionalContext in code\):[[:space:]]+[0-9]+' /tmp/stop-hook-additional-context-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
SHAC_OK=$( { grep -oE 'WITH-OK-MARKER \(justified internal usage\):[[:space:]]+[0-9]+' /tmp/stop-hook-additional-context-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
SHAC_VIOL=$( { grep -oE 'EMISSION-VIOLATION \(silent-drop risk\):[[:space:]]+[0-9]+' /tmp/stop-hook-additional-context-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
echo "  ✓ Pentad-member additionalContext: ${SHAC_SCANNED:-0} scanned (${SHAC_CLEAN:-0} clean + ${SHAC_OK:-0} with-ok-marker, ${SHAC_VIOL:-0} violations)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4j: additionalContext-silently-dropped pentad audit (iter-67/68/69 gate)" "iter134-audit-batch"

# Check 4k: Iter-77 hook-source L3-stripped-path audit. Acts on the
# iter-76 cache-populator-filter forensic discovery (docs/HOOKS.md): the
# Claude Code plugin cache populator strips any plugin-root-level
# subtree NOT in {hooks, skills, commands, agents}. Hook source code
# referencing ${CLAUDE_PLUGIN_ROOT}/<non-allowlisted-segment>/ resolves
# to a missing file at L3 runtime and fails SILENTLY. Iter-77 found one
# real instance (link-tools/hooks/stop-link-check.py's lychee.toml
# fallback) and ships this gate to prevent recurrence. Blocks tag
# publish so a regression cannot escape to Layer 3 operator caches
# (see iter-42 docs/HOOKS.md for cache lifecycle).
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter77-l3-stripped-path-audit
echo "→ Running iter-77 L3-stripped-path audit (hook source code)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter77-l3-stripped-path-audit; then
    echo "  ✗ L3-stripped-path audit FAILED — see /tmp/iter77-l3-stripped-path-audit.log"
    tail -25 /tmp/iter77-l3-stripped-path-audit.log
    exit 1
fi
# Loose-coupled defensive grep (per iter-70 brittle-banner hardening).
L3SP_SCANNED=$( { grep -oE 'Hook source files scanned:[[:space:]]+[0-9]+' /tmp/iter77-l3-stripped-path-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
L3SP_VIOL_FOUND=$( { grep -oE 'L3-stripped-path references found:[[:space:]]+[0-9]+' /tmp/iter77-l3-stripped-path-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
L3SP_WITH_OK=$( { grep -oE 'With LAYER3-STRIPPED-PATH-OK escape hatch:[[:space:]]+[0-9]+' /tmp/iter77-l3-stripped-path-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
L3SP_UNJUSTIFIED=$( { grep -oE 'Unjustified violations \(silent-fail risk\):[[:space:]]+[0-9]+' /tmp/iter77-l3-stripped-path-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
echo "  ✓ L3-stripped-path: ${L3SP_SCANNED:-0} files scanned (${L3SP_VIOL_FOUND:-0} refs found, ${L3SP_WITH_OK:-0} with-ok-marker, ${L3SP_UNJUSTIFIED:-0} unjustified)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4k: L3-stripped-path audit (iter-77 gate)" "iter134-audit-batch"

# Check 4l: Iter-82 conventional-commits-conformance validator. Acts on
# the iter-77/80/81 silent-release-skip forensic finding: compound
# prefixes like "feat(scope)+docs:" land on main but produce NO
# version-bump tag because @semantic-release/commit-analyzer's regex
# does not match them. INFORMATIONAL only (does not block) because
# legacy violations exist on main and gating would require destructive
# rebase. Operators see compound-prefix violations BEFORE the next
# release rather than after a stranded commit.
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter82-conventional-commits-conformance
echo "→ Running iter-82 conventional-commits-conformance validator (informational)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter82-conventional-commits-conformance; then
    echo "  ⚠ Validator exited non-zero (informational only — not blocking release)"
fi
# Loose-coupled defensive grep (per iter-70 brittle-banner hardening).
CCC_SCANNED=$( { grep -oE 'Total commits scanned:[[:space:]]+[0-9]+' /tmp/iter82-conventional-commits-conformance.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
CCC_CONFORMANT=$( { grep -oE 'Standard-conformant:[[:space:]]+[0-9]+' /tmp/iter82-conventional-commits-conformance.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
CCC_COMPOUND=$( { grep -oE 'Compound-prefix violations \(silent-fail\):[[:space:]]+[0-9]+' /tmp/iter82-conventional-commits-conformance.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
CCC_MISSING_TYPE=$( { grep -oE 'Missing-type / unrecognized-type violations:[[:space:]]+[0-9]+' /tmp/iter82-conventional-commits-conformance.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
if [[ "${CCC_COMPOUND:-0}" -gt 0 ]] || [[ "${CCC_MISSING_TYPE:-0}" -gt 0 ]]; then
    echo "  ⚠ Conventional-commits: ${CCC_SCANNED:-0} scanned, ${CCC_CONFORMANT:-0} conformant, ${CCC_COMPOUND:-0} compound-prefix violation(s), ${CCC_MISSING_TYPE:-0} missing-type violation(s)"
    echo "    (each compound-prefix commit is silently skipped by semantic-release — use clean type(scope): prefixes going forward)"
else
    echo "  ✓ Conventional-commits: ${CCC_SCANNED:-0} scanned, all conformant"
fi
__preflight_timing_report_phase_elapsed_milliseconds "Check 4l: conventional-commits-conformance validator (iter-82 gate; informational)" "iter134-audit-batch"

# Check 4m: Iter-86 PreToolUse-orchestrator subhook-contract static checker.
# Statically verifies every file in plugins/itp-hooks/hooks/ that exports a
# classify*ForOrchestrator function: (a) the classifier function body MUST
# NOT contain process.exit/process.stdout.write/process.stdin/console.log
# calls (pure-function discipline — orchestrator owns I/O), AND (b) the
# file MUST gate its standalone main() under `if (import.meta.main)` so
# importing the classifier from the orchestrator does NOT double-execute
# main(). Addresses the iter-85 adversarial-audit's HIGH FOOTGUNs #1+#2.
# Informational by default; future iters may flip to --strict once all
# inlined subhooks have stable contracts.
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter86-orchestrator-subhook-contract-static-check
echo "→ Running iter-86 PreToolUse-orchestrator subhook-contract static checker (informational)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter86-orchestrator-subhook-contract-static-check; then
    echo "  ⚠ Subhook-contract static checker exited non-zero (informational only — not blocking release)"
fi
# Loose-coupled defensive grep extraction (iter-70 brittle-banner hardening pattern).
SUBHOOK_CONTRACT_FILES_SCANNED=$( { grep -oE 'Total subhook files scanned:[[:space:]]+[0-9]+' /tmp/iter86-orchestrator-subhook-contract-static-check.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
SUBHOOK_CONTRACT_MISSING_GUARD_VIOLATIONS=$( { grep -oE 'Files missing import\.meta\.main guard:[[:space:]]+[0-9]+' /tmp/iter86-orchestrator-subhook-contract-static-check.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
SUBHOOK_CONTRACT_FORBIDDEN_IO_VIOLATIONS=$( { grep -oE 'Files with forbidden I/O in classifier body:[[:space:]]+[0-9]+' /tmp/iter86-orchestrator-subhook-contract-static-check.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
if [[ "${SUBHOOK_CONTRACT_MISSING_GUARD_VIOLATIONS:-0}" -gt 0 ]] || [[ "${SUBHOOK_CONTRACT_FORBIDDEN_IO_VIOLATIONS:-0}" -gt 0 ]]; then
    echo "  ⚠ Subhook contract: ${SUBHOOK_CONTRACT_FILES_SCANNED:-0} scanned, ${SUBHOOK_CONTRACT_MISSING_GUARD_VIOLATIONS:-0} missing-guard violation(s), ${SUBHOOK_CONTRACT_FORBIDDEN_IO_VIOLATIONS:-0} forbidden-I/O violation(s)"
    echo "    (each violation can silently break the orchestrator dual-mode contract — see /tmp/iter86-orchestrator-subhook-contract-static-check.log)"
else
    echo "  ✓ Subhook contract: ${SUBHOOK_CONTRACT_FILES_SCANNED:-0} scanned, all conform to PreToolUseSubhookContract"
fi
__preflight_timing_report_phase_elapsed_milliseconds "Check 4m: subhook-contract static checker (iter-86 gate; informational)" "iter134-audit-batch"

# Check 4n: Iter-99 marketplace-wide silent-context-drop audit. Scales the
# iter-98 single-hook fix to a marketplace invariant. Per the iter-66/93
# forensic finding + Anthropic PostToolUse schema docs, plain-text stdout
# from PostToolUse hooks is rendered into the operator transcript (Ctrl-R
# visible) but NEVER delivered to Claude's next-turn context. The only two
# Claude-visible PostToolUse stdout schemas are:
#   (1) {decision:"block", reason:"..."} JSON
#   (2) {hookSpecificOutput:{hookEventName:"PostToolUse", additionalContext:"..."}} JSON
# This audit catches the silent-drop pattern preventively in TypeScript
# PostToolUse hooks (console.log of template-literal / string-literal —
# bypasses BOTH valid schemas). Escape hatch: `// POSTTOOLUSE-RAW-STDOUT-OK:
# <reason ≥ 10 chars>` on same-line or within 3 preceding lines for
# explicitly operator-only intent.
# Informational by default — future iters may flip to --strict.
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter99-posttooluse-silent-context-drop-audit
echo "→ Running iter-99 PostToolUse silent-context-drop marketplace audit (informational)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter99-posttooluse-silent-context-drop-audit; then
    echo "  ⚠ Silent-context-drop audit exited non-zero (informational only — not blocking release)"
    echo "    (each violation indicates a PostToolUse hook whose reminder Claude never sees — see /tmp/iter99-posttooluse-silent-context-drop-audit.log)"
fi
# Loose-coupled defensive grep extraction (iter-70 brittle-banner hardening pattern).
POSTTOOLUSE_SILENT_DROP_HOOKS_DISCOVERED=$( { grep -oE 'PostToolUse TypeScript hooks discovered across marketplace:[[:space:]]+[0-9]+' /tmp/iter99-posttooluse-silent-context-drop-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
POSTTOOLUSE_SILENT_DROP_VIOLATIONS=$( { grep -oE 'AUDIT FAILED — [0-9]+ silent-context-drop' /tmp/iter99-posttooluse-silent-context-drop-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
if [[ "${POSTTOOLUSE_SILENT_DROP_VIOLATIONS:-0}" -gt 0 ]]; then
    echo "  ⚠ Silent-context-drop audit: ${POSTTOOLUSE_SILENT_DROP_HOOKS_DISCOVERED:-0} hooks scanned, ${POSTTOOLUSE_SILENT_DROP_VIOLATIONS:-0} violation(s)"
else
    echo "  ✓ Silent-context-drop audit: ${POSTTOOLUSE_SILENT_DROP_HOOKS_DISCOVERED:-0} hooks scanned, 0 violations"
fi
__preflight_timing_report_phase_elapsed_milliseconds "Check 4n: PostToolUse silent-context-drop audit (iter-99 gate; informational)" "iter134-audit-batch"

# Check 4o: Iter-101 marketplace-wide matcher-hygiene audit. Scales the
# iter-100 single-orchestrator MultiEdit-matcher-broadening fix to a
# marketplace invariant. Per 2026 Anthropic + community best-practice web
# research surfaced during iter-100 adversarial audit, Claude's MultiEdit
# tool call (tool_input.edits[] shape) is DISTINCT from Write/Edit. Any
# PreToolUse/PostToolUse matcher of the form `Write|Edit` (or any subset
# containing Write or Edit but NOT MultiEdit) silently bypasses MultiEdit
# tool calls — the hook never fires for that input class. Iter-101
# discovered 8 such gaps across 3 plugins (itp-hooks: PreToolUse
# orchestrator + process-storm-guard + 2 PostToolUse multi-hook entries;
# dotfiles-tools: chezmoi-sync-reminder; rust-tools: rust-sota-reminder)
# and fixed all of them. The audit now stands guard preventively.
# Escape hatch: `MATCHER-NO-MULTIEDIT-OK: <reason ≥ 10 chars>` in the
# hook's description field for explicitly-justified MultiEdit exclusions.
# Informational by default — future iters may flip to --strict.
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter101-matcher-hygiene-audit
echo "→ Running iter-101 PreToolUse/PostToolUse matcher-hygiene marketplace audit (informational)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter101-matcher-hygiene-audit; then
    echo "  ⚠ Matcher-hygiene audit exited non-zero (informational only — not blocking release)"
    echo "    (each violation indicates a hook whose matcher silently bypasses Claude's MultiEdit tool calls — see /tmp/iter101-matcher-hygiene-audit.log)"
fi
# Loose-coupled defensive grep extraction (iter-70 brittle-banner hardening pattern).
MATCHER_HYGIENE_HOOKS_DISCOVERED=$( { grep -oE 'hooks.json files discovered across marketplace:[[:space:]]+[0-9]+' /tmp/iter101-matcher-hygiene-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
MATCHER_HYGIENE_VIOLATIONS=$( { grep -oE 'AUDIT FAILED — [0-9]+ matcher coverage gap' /tmp/iter101-matcher-hygiene-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
if [[ "${MATCHER_HYGIENE_VIOLATIONS:-0}" -gt 0 ]]; then
    echo "  ⚠ Matcher-hygiene audit: ${MATCHER_HYGIENE_HOOKS_DISCOVERED:-0} hooks.json files scanned, ${MATCHER_HYGIENE_VIOLATIONS:-0} violation(s)"
else
    echo "  ✓ Matcher-hygiene audit: ${MATCHER_HYGIENE_HOOKS_DISCOVERED:-0} hooks.json files scanned, 0 violations"
fi
__preflight_timing_report_phase_elapsed_milliseconds "Check 4o: PreToolUse/PostToolUse matcher-hygiene audit (iter-101 gate; informational)" "iter134-audit-batch"

# Check 4p: Iter-103 marketplace-wide NotebookEdit applicability audit.
# Per 2026 Anthropic canonical recommendation, the file-edit tool quadruple
# is `Edit|MultiEdit|Write|NotebookEdit`. NotebookEdit has a DIFFERENT
# payload shape (notebook_path + cell_id + new_source + edit_mode)
# operating on Jupyter .ipynb cells, NOT file content. This audit produces
# a per-classifier applicability matrix surfacing hooks that SHOULD honor
# NotebookEdit because their content patterns apply to notebook cell source
# (e.g., hardcoded versions in version-guard, PyTorch GPU patterns in gpu-
# optimization-guard). PURE INFORMATIONAL — community-validated 2026
# NotebookEdit bugs (insert-positioning, git diff noise, Jupyter MCP server
# recommendation) mean per-hook broadening is conditional, NOT universal.
# Iter-104+ scope: per-classifier NotebookEdit payload-shape adaptation
# for the APPLICABLE cohort (version-guard, gpu-optimization-guard, ssot-
# principles, memory-efficiency-reminder).
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter103-notebookedit-applicability-audit
echo "→ Running iter-103 NotebookEdit applicability marketplace audit (informational)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter103-notebookedit-applicability-audit; then
    echo "  ⚠ NotebookEdit applicability audit exited non-zero (informational only — never blocks release)"
fi
# Loose-coupled defensive grep extraction (iter-70 brittle-banner hardening pattern).
NOTEBOOKEDIT_APPLICABLE_CLASSIFIER_COUNT=$( { grep -oE 'APPLICABLE \(high-value coverage gap\):[[:space:]]+[0-9]+' /tmp/iter103-notebookedit-applicability-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
NOTEBOOKEDIT_POTENTIALLY_APPLICABLE_CLASSIFIER_COUNT=$( { grep -oE 'POTENTIALLY-APPLICABLE \(conditional value\):[[:space:]]+[0-9]+' /tmp/iter103-notebookedit-applicability-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
NOTEBOOKEDIT_HONORING_MATCHER_COUNT=$( { grep -oE '[0-9]+ matchers currently include NotebookEdit' /tmp/iter103-notebookedit-applicability-audit.log || true; } | grep -oE '^[0-9]+' | head -1 || echo 0)
echo "  ✓ NotebookEdit applicability audit: ${NOTEBOOKEDIT_APPLICABLE_CLASSIFIER_COUNT:-0} APPLICABLE + ${NOTEBOOKEDIT_POTENTIALLY_APPLICABLE_CLASSIFIER_COUNT:-0} POTENTIALLY-APPLICABLE classifiers surfaced (current marketplace coverage: ${NOTEBOOKEDIT_HONORING_MATCHER_COUNT:-0} matchers honor NotebookEdit)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4p: NotebookEdit applicability audit (iter-103 gate; informational)" "iter134-audit-batch"

# Check 4q: Iter-105 marketplace-wide truncation-helper invariant audit.
# Scales the iter-104 single-hook fix (vale-claude-md.ts wraps emissions
# via truncateHookOutputToStayBelowClaudeFileSpilloverThreshold against
# Claude's 10K-character hook-output file-spillover threshold) to a
# marketplace invariant covering all 8 classifier-with-emission hooks
# (vale-claude-md + ty + tsgo + oxlint + biome + ssot-principles +
# pretooluse-vale-claude-md-guard + PostToolUse orchestrator aggregation).
# Informational by default — future iters may flip to --strict once the
# helper is hoisted to a dedicated shared-lib file (iter-106+ candidate).
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter105-truncation-helper-audit
echo "→ Running iter-105 truncation-helper marketplace invariant audit (informational)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter105-truncation-helper-audit; then
    echo "  ⚠ Truncation-helper audit exited non-zero (informational only — not blocking release)"
fi
TRUNCATION_HELPER_COHORT_COUNT=$( { grep -oE 'Cohort discovered:[[:space:]]+[0-9]+' /tmp/iter105-truncation-helper-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
TRUNCATION_HELPER_PASSING_COUNT=$( { grep -oE 'AUDIT PASSED — all [0-9]+ cohort hooks' /tmp/iter105-truncation-helper-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
if [[ "${TRUNCATION_HELPER_PASSING_COUNT:-0}" == "${TRUNCATION_HELPER_COHORT_COUNT:-0}" ]] && [[ "${TRUNCATION_HELPER_COHORT_COUNT:-0}" -gt 0 ]]; then
    echo "  ✓ Truncation-helper audit: ${TRUNCATION_HELPER_PASSING_COUNT}/${TRUNCATION_HELPER_COHORT_COUNT} cohort hooks wrap via canonical helper"
else
    TRUNCATION_HELPER_MISSING_COUNT=$( { grep -oE 'AUDIT FAILED — [0-9]+ of [0-9]+ cohort hooks missing' /tmp/iter105-truncation-helper-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
    echo "  ⚠ Truncation-helper audit: ${TRUNCATION_HELPER_MISSING_COUNT}/${TRUNCATION_HELPER_COHORT_COUNT} cohort hooks missing canonical wrap (see /tmp/iter105-truncation-helper-audit.log)"
fi
__preflight_timing_report_phase_elapsed_milliseconds "Check 4q: truncation-helper invariant audit (iter-105 gate; informational)" "iter134-audit-batch"

# Check 4r: Iter-106 truncation-helper canonical-home invariant audit.
# Verifies the iter-104/iter-105 truncation helper has been relocated to its
# iter-106 canonical home (a dedicated cross-Pre/PostToolUse shared lib that
# eliminates the iter-105 cross-lib import awkwardness where pretooluse-vale-
# claude-md-guard imported from the PostToolUse contract lib). Confirms (1)
# the shared-lib file exists and holds literal exports, (2) PostToolUse
# contract lib re-exports for backward compat (no duplicate definitions),
# (3) all 8 iter-105 cohort hooks import the helper from the shared-lib
# canonical home. Informational — parallel to Check 4n/4o/4p/4q. Future iters
# may promote to --strict once the iter-105 + iter-106 invariants land as
# universally true across a marketplace-wide refactor pass.
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter106-canonical-home-audit
echo "→ Running iter-106 truncation-helper canonical-home audit (informational)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter106-canonical-home-audit; then
    echo "  ⚠ Canonical-home audit exited non-zero (informational only — not blocking release)"
fi
if grep -q 'AUDIT PASSED' /tmp/iter106-canonical-home-audit.log 2>/dev/null; then
    echo "  ✓ Iter-106 canonical-home audit: PASSED (helper at iter-106 shared-lib canonical home; PostToolUse contract lib re-exports for backward compat)"
else
    echo "  ⚠ Iter-106 canonical-home audit: FAILED (see /tmp/iter106-canonical-home-audit.log)"
fi
__preflight_timing_report_phase_elapsed_milliseconds "Check 4r: truncation-helper canonical-home audit (iter-106 gate; informational)" "iter134-audit-batch"

# Check 4s: Iter-107 escape-hatch-marker detection inventory audit.
# Iter-110 promoted to STRICT-BLOCK mode: closes the iter-107 → iter-109
# migration arc by enforcing two release-blocking invariants:
#   1. NO hand-rolled escape-hatch-marker regex detection in any hook
#      (detected via regex-pattern heuristic — catches new hook authors
#      bypassing the canonical shared helper)
#   2. ALL 8 canonical cohort members (curated list in the audit task)
#      MUST import the iter-107 shared helper (catches silent removal
#      of a previously-migrated helper consumption)
# A non-zero exit from this audit BLOCKS the release.
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter110-escape-hatch-strict-audit
echo "→ Running iter-107/iter-110 escape-hatch-marker detection invariant audit (STRICT-BLOCK)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter110-escape-hatch-strict-audit; then
    echo "  ✗ ESCAPE-HATCH AUDIT FAILED (iter-110 STRICT-BLOCK) — see /tmp/iter110-escape-hatch-strict-audit.log"
    exit 1
fi
ITER110_MIGRATED_COUNT=$( { grep -oE 'Migrated to shared helper:[[:space:]]+[0-9]+' /tmp/iter110-escape-hatch-strict-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
ITER110_COHORT_SIZE=$( { grep -oE 'Canonical cohort size:[[:space:]]+[0-9]+' /tmp/iter110-escape-hatch-strict-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
echo "  ✓ Escape-hatch invariant: ${ITER110_MIGRATED_COUNT:-0} hooks migrated / ${ITER110_COHORT_SIZE:-0} canonical cohort (iter-110 STRICT)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4s: escape-hatch-marker detection invariant audit (iter-110 STRICT-BLOCK)" "iter134-audit-batch"

# Check 4t: Iter-111 producer-side escape-hatch-marker typo-detection audit.
#
# Complementary to iter-110's CONSUMER-side invariant: while iter-110 enforces
# that every consumer hook routes through the iter-107 canonical helper,
# iter-111 enforces that every PRODUCER-side marker token (the `# FOO-OK`
# comments operators write into their source files) is recognized by some
# consumer hook — i.e., is registered in the iter-111 canonical registry.
#
# Catches the silent-fail typo class: `# PROCSS-STORM-OK` (missing first E)
# would otherwise be ignored by every consumer hook, and the operator would
# wonder why their "escape hatch" doesn't actually escape.
#
# Iter-111: introduced as informational (never blocked).
# Iter-114: extended the producer-marker layer with a parallel AUDIT-TASK
# marker registry (8 entries) covering the second lifecycle layer, so the
# marker-coverage gap that previously prevented strict-promotion is closed.
# Iter-115: PROMOTED TO STRICT-BLOCK. The audit reaches a stable 0-unregistered
# state at HEAD; any new unregistered token (a typo OR an intentional new
# marker that hasn't been registered in iter-111 OR iter-114) now fails
# release until either the token is fixed (typo path) or registered
# (legitimate-new-marker path).
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter111-producer-marker-typo-audit
echo "→ Running iter-111 producer-side escape-hatch-marker typo audit (iter-115 STRICT-BLOCK)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter111-producer-marker-typo-audit; then
    echo "  ✗ ITER-111 PRODUCER-MARKER TYPO AUDIT FAILED (iter-115 STRICT-BLOCK) — see /tmp/iter111-producer-marker-typo-audit.log"
    echo "    Fix paths:"
    echo "      A. If the token is a typo: correct it in the producer file"
    echo "      B. If the token is a legitimate new marker: register it in the"
    echo "         appropriate canonical registry (iter-111 for runtime-hook"
    echo "         markers, iter-114 for audit-task markers) and re-run"
    echo "         mise run generate-marketplace-escape-hatch-marker-reference-documentation-from-iter111-canonical-registry"
    exit 1
fi
ITER111_UNREGISTERED_COUNT=$( { grep -oE 'AUDIT FOUND [0-9]+' /tmp/iter111-producer-marker-typo-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
ITER111_REGISTERED_COUNT=$( { grep -oE 'parsed [0-9]+ registered markers' /tmp/iter111-producer-marker-typo-audit.log || true; } | grep -oE '[0-9]+' | head -1 || echo 0)
if [[ "${ITER111_UNREGISTERED_COUNT:-0}" -gt 0 ]]; then
    # Defensive: the audit task itself exits 0 even when unregistered tokens
    # are found (it reports informationally regardless), so re-check the
    # parsed count and fail explicitly if any unregistered marker exists.
    # This keeps strict-block semantics intact even if the audit task's
    # exit-code policy changes in the future.
    echo "  ✗ ITER-111 PRODUCER-MARKER TYPO AUDIT FAILED (iter-115 STRICT-BLOCK) — ${ITER111_UNREGISTERED_COUNT} unregistered token(s)"
    exit 1
fi
echo "  ✓ Iter-111 producer-marker registry: 0 unregistered markers across ${ITER111_REGISTERED_COUNT:-0} known tokens (iter-115 STRICT)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4t: producer-side escape-hatch-marker typo audit (iter-115 STRICT-BLOCK)" "iter134-audit-batch"

# Check 4u: Iter-113 registry-to-docs drift detector.
#
# Verifies that the on-disk operator-facing reference doc
#   docs/marketplace-escape-hatch-marker-reference.md
# is in sync with the iter-111 canonical registry source. Drift here means
# either (a) someone edited the registry without regenerating the doc, or
# (b) someone hand-edited the doc without updating the registry. Either way
# the SSoT is broken and operators consulting the doc would see stale
# information.
#
# Iter-113: introduced as informational.
# Iter-114: extended doc generator to render TWO catalogs (runtime + audit).
# Iter-115: PROMOTED TO STRICT-BLOCK alongside Check 4t. Drift is now a
# release blocker — operators reading the auto-generated reference doc must
# never see stale information that conflicts with the canonical registry SSoT.
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter113-doc-drift-detector
echo "→ Running iter-113 registry-to-docs drift detector (iter-115 STRICT-BLOCK)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter113-doc-drift-detector; then
    echo "  ✗ ITER-113 REGISTRY-TO-DOCS DRIFT DETECTOR FAILED (iter-115 STRICT-BLOCK) — see /tmp/iter113-doc-drift-detector.log"
    echo "    Fix: mise run generate-marketplace-escape-hatch-marker-reference-documentation-from-iter111-canonical-registry"
    echo "    (then commit the regenerated docs/marketplace-escape-hatch-marker-reference.md alongside the registry change)"
    exit 1
fi
echo "  ✓ Iter-113 operator-facing escape-hatch-marker reference doc is in sync with iter-111+iter-114 canonical registries (iter-115 STRICT)"
__preflight_timing_report_phase_elapsed_milliseconds "Check 4u: registry-to-docs drift detector (iter-115 STRICT-BLOCK)" "iter134-audit-batch"

# Check 4v: Iter-121 canonical-registry stale-description audit (INFORMATIONAL).
#
# Catches the operator-doc-drift class where a hook or audit-task is renamed
# (consumer-path field updated in the registry) but the human-readable
# description still references the OLD name. Pre-iter-121 no audit caught
# this: Check 4t (iter-111 producer-typo) only verifies marker spelling;
# Check 4u (iter-113 doc-drift) only verifies byte-identical regeneration.
# Neither cross-checks description ↔ consumer-path consistency.
#
# Algorithm: for each entry in the iter-111 RUNTIME-HOOK + iter-114 AUDIT-TASK
# registries, extract discriminating hyphen-segments from the marker name
# AND consumer basename, drop a stoplist of non-discriminating segments
# (OK/SKIP/WRAP suffix tokens; pretooluse/posttooluse/audit/guard/marketplace
# generic prefixes; iter-NNN iteration-suffix tokens), and verify the
# description contains AT LEAST ONE discriminating-segment substring
# (raw segment OR adjacent-pair kebab-case join, case-insensitive).
#
# Iter-121: INFORMATIONAL only — never blocks release. Reports findings so
# operators can address them before iter-122+ promotes the audit to
# STRICT-BLOCK once baseline coverage is verified across a few releases.
__iter134_seed_phase_timing_start_from_externally_captured_audit_wall_clock_elapsed_ms_sidecar_file iter121-stale-description-audit
echo "→ Running iter-121 canonical-registry stale-description audit (informational)..."
if ! __iter134_audit_subprocess_completed_successfully_per_sidecar_exit_code_file iter121-stale-description-audit; then
    echo "  ⚠ Iter-121 stale-description audit infrastructure failure — see /tmp/iter121-stale-description-audit.log"
    # Infrastructure failure (bun crash, missing registry, etc.) is non-blocking
    # in iter-121's informational mode. Iter-122+ will tighten this.
fi
ITER121_TOTAL_ENTRIES_AUDITED=$( { awk '/audited [0-9]+ entries/ { for (i=1; i<=NF; i++) if ($i == "audited") { print $(i+1); exit } }' /tmp/iter121-stale-description-audit.log || true; } | head -1)
ITER121_STALE_HITS=$( { grep -oE 'ITER-121 INFORMATIONAL FINDING: [0-9]+' /tmp/iter121-stale-description-audit.log || true; } | grep -oE '[0-9]+$' | head -1 || echo 0)
if [[ "${ITER121_STALE_HITS:-0}" -gt 0 ]]; then
    echo "  ⚠ Iter-121 stale-description audit: ${ITER121_STALE_HITS} entry/entries with unmoored descriptions across ${ITER121_TOTAL_ENTRIES_AUDITED:-?} audited (informational; never blocks release)"
else
    echo "  ✓ Iter-121 stale-description audit: 0 unmoored descriptions across ${ITER121_TOTAL_ENTRIES_AUDITED:-?} audited entries (informational)"
fi
__preflight_timing_report_phase_elapsed_milliseconds "Check 4v: stale-description audit (iter-121 informational)" "iter134-audit-batch"

# Check 5: Releasable commits exist
__preflight_timing_mark_phase_start_using_EPOCHREALTIME
echo "→ Checking for releasable commits..."
LATEST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [[ -n "$LATEST_TAG" ]]; then
    COMMITS=$(git log "$LATEST_TAG"..HEAD --oneline 2>/dev/null | wc -l | tr -d ' ')
    if [[ "$COMMITS" -eq 0 ]]; then
        echo "  ✗ No commits since $LATEST_TAG"
        exit 1
    fi
    echo "  ✓ Found $COMMITS commits since $LATEST_TAG"
fi
__preflight_timing_report_phase_elapsed_milliseconds "Check 5: releasable commits since last tag"

# Iter-73: emit whole-script wall-clock total to let operator sanity-check
# sum-of-phases ≈ whole-script (the gap = per-call awk + bash function
# overhead, which should be a few ms even at 12 phases).
if [[ "${PREFLIGHT_TIMING_PROFILE:-0}" == "1" ]] && [[ -n "$preflight_timing_whole_script_start_seconds_for_iter73_instrumentation" ]]; then
    preflight_timing_whole_script_end_seconds_for_iter73_instrumentation="$EPOCHREALTIME"
    preflight_timing_whole_script_elapsed_milliseconds_for_iter73_instrumentation=$(awk \
        -v s="$preflight_timing_whole_script_start_seconds_for_iter73_instrumentation" \
        -v e="$preflight_timing_whole_script_end_seconds_for_iter73_instrumentation" \
        'BEGIN { printf "%.0f", (e - s) * 1000 }')
    echo "    ⧗ whole-script elapsed: ${preflight_timing_whole_script_elapsed_milliseconds_for_iter73_instrumentation}ms (preflight total)"
fi

# Iter-130: emit top-N-slowest-checks ranking summary so operators see
# the next perf-optimization target without manually scanning all "⧗" lines.
__iter130_emit_top_n_slowest_preflight_checks_ranked_by_elapsed_milliseconds_descending_bottleneck_summary

echo ""
echo "✓ All preflight checks passed"
echo ""
