#!/usr/bin/env bash
#MISE description="Execute complete release pipeline: preflight validation → pre-sync (mirror HEAD to ~/.claude so live env reflects pending changes) → semantic-release version bump + changelog + git tag + GitHub release → marketplace sync + hook installation + cache population → artifact verification → session-chronicle bundle (private repos only) → postflight git state validation. Primary entry point for releasing cc-skills. Requires GH_TOKEN and clean working directory."
set -euo pipefail

# Iter-139: RELEASE_TIMING_PROFILE opt-in pipeline-level wall-clock instrumentation.
# Mirrors the iter-73 PREFLIGHT_TIMING_PROFILE pattern at one structural level up:
# where iter-73 measures per-check timing INSIDE the preflight script, iter-139
# measures per-phase timing ACROSS the seven-phase release orchestrator that
# wraps preflight + presync + version + sync + verify + chronicle + postflight.
#
# Operators set RELEASE_TIMING_PROFILE=1 to surface where the ~45-55s release
# wall-clock actually goes. Without this instrumentation the pipeline is
# opaque — operators iterating on release perf have no data to guide them
# (the preflight is heavily instrumented, but the OTHER ~90% of release time
# was previously invisible). Same iter-73 "instrument first, then optimize"
# discipline that unlocked iter-74 through iter-138's preflight wall-clock
# reduction from ~10.74s to ~4.5s (~58% cumulative).
#
# Output shape:
#   - Per-phase: "    ⧗ release-phase elapsed: Nms (phase-label)" emitted
#     after each phase completes, inline with phase boundary banners.
#   - End-of-script: top-N ranking sorted descending by elapsed-ms, mirroring
#     iter-130's preflight ranking. Default N=5; operator-tunable via
#     ITER139_TOP_N_SLOWEST_RELEASE_PHASES_TO_DISPLAY.
#
# Removed the previous `#MISE depends=["release:preflight"]` declaration so
# preflight runs INSIDE the orchestrator script body where it can be wrapped
# by the timing capture. Functionally identical to the depends-based invocation
# (mise wires both up the same way) — the explicit-call form just lets the
# iter-139 instrumentation see the preflight wall-clock too.
__iter139_release_phase_timing_record_array_for_top_n_slowest_bottleneck_ranking_summary=()

__iter139_wrap_release_phase_invocation_with_epochrealtime_wall_clock_capture_for_release_timing_profile_top_n_bottleneck_ranking() {
    local human_readable_release_phase_label_for_per_phase_report="$1"
    shift
    local release_phase_invocation_argv=("$@")
    if [[ "${RELEASE_TIMING_PROFILE:-0}" != "1" ]]; then
        "${release_phase_invocation_argv[@]}"
        return $?
    fi
    local release_phase_start_seconds_using_epochrealtime="$EPOCHREALTIME"
    local release_phase_invocation_exit_code=0
    "${release_phase_invocation_argv[@]}" || release_phase_invocation_exit_code=$?
    local release_phase_end_seconds_using_epochrealtime="$EPOCHREALTIME"
    local release_phase_elapsed_milliseconds
    release_phase_elapsed_milliseconds=$(awk \
        -v s="$release_phase_start_seconds_using_epochrealtime" \
        -v e="$release_phase_end_seconds_using_epochrealtime" \
        'BEGIN { printf "%.0f", (e - s) * 1000 }')
    echo "    ⧗ release-phase elapsed: ${release_phase_elapsed_milliseconds}ms (${human_readable_release_phase_label_for_per_phase_report})"
    __iter139_release_phase_timing_record_array_for_top_n_slowest_bottleneck_ranking_summary+=(
        "${release_phase_elapsed_milliseconds}"$'\t'"${human_readable_release_phase_label_for_per_phase_report}"
    )
    return $release_phase_invocation_exit_code
}

__iter139_emit_top_n_slowest_release_phases_ranked_by_elapsed_milliseconds_descending_bottleneck_summary() {
    if [[ "${RELEASE_TIMING_PROFILE:-0}" != "1" ]]; then
        return 0
    fi
    if [[ "${#__iter139_release_phase_timing_record_array_for_top_n_slowest_bottleneck_ranking_summary[@]}" -eq 0 ]]; then
        return 0
    fi
    local top_n_threshold_for_slowest_release_phase_ranking_display="${ITER139_TOP_N_SLOWEST_RELEASE_PHASES_TO_DISPLAY:-5}"
    echo ""
    echo "    ⧗ ─── Top ${top_n_threshold_for_slowest_release_phase_ranking_display} slowest release phases (iter-139 pipeline-level bottleneck ranking) ───"
    printf '%s\n' "${__iter139_release_phase_timing_record_array_for_top_n_slowest_bottleneck_ranking_summary[@]}" \
        | sort -rn -k1 \
        | head -n "${top_n_threshold_for_slowest_release_phase_ranking_display}" \
        | awk -F'\t' '{ printf "      %2d. %6d ms  %s\n", NR, $1, $2 }'
    echo "    ⧗ (override count via ITER139_TOP_N_SLOWEST_RELEASE_PHASES_TO_DISPLAY=N)"
    echo "    ⧗ (set PREFLIGHT_TIMING_PROFILE=1 too for the iter-130 per-check sub-ranking inside Phase 1)"
}

# Whole-pipeline timer. Mirrors the iter-73 whole-script timer in preflight.
release_timing_profile_whole_pipeline_start_seconds_using_epochrealtime=""
if [[ "${RELEASE_TIMING_PROFILE:-0}" == "1" ]]; then
    release_timing_profile_whole_pipeline_start_seconds_using_epochrealtime="$EPOCHREALTIME"
    echo "    ⧗ RELEASE_TIMING_PROFILE=1 — per-phase wall-clock instrumentation active (iter-139)"
fi

# ─── ITER-147: env-var-scoped SSH ControlMaster opt-in for this release run ─────
# Complementary to iter-146's ~/.ssh/config-modifying setup script. Iter-146
# refuses to auto-modify ~/.ssh/config when a conflicting Host github.com block
# already exists (e.g., when an operator has IdentityFile pins for anti-key-leak
# defense). On THIS operator's machine the iter-146 setup script correctly
# refused to modify the existing block with `IdentityFile ~/.ssh/id_ed25519_terrylica`
# + `IdentitiesOnly yes` (anti-tainora-leak invariant from 2026-05-19).
#
# Iter-147 ships a complementary, non-invasive lever:
#
#   RELEASE_SSH_MULTIPLEXING_ENABLED=1 — exports GIT_SSH_COMMAND with
#   `-o ControlMaster=auto -o ControlPath=~/.ssh/controlmasters/%r@%h:%p
#    -o ControlPersist=10m` for the duration of THIS release pipeline only.
#
# Differences from iter-146:
#
#   - Zero modification of ~/.ssh/config. The operator's IdentityFile pin
#     + IdentitiesOnly directives are preserved untouched.
#
#   - Process-tree-scoped: GIT_SSH_COMMAND is only set inside `mise run release:full`.
#     Spawned bash subprocesses inherit it; bash exit unsets it. Other
#     terminal sessions, cron jobs, IDE git operations, etc. are unaffected.
#
#   - Self-cleaning: ControlMaster sockets auto-expire after the 10-minute
#     ControlPersist TTL (or sooner if the parent ssh process exits and no
#     other ssh references the socket). The ~/.ssh/controlmasters/ directory
#     stays put as a mode-0700 host for future sessions.
#
#   - Same target as iter-146: the semantic-release `get-git-auth-url` step
#     calls `verifyAuth` which runs `git push --dry-run --no-verify <repo>
#     HEAD:<branch>` — this is the SSH-handshake-dominated network round-trip
#     measured by iter-144 at ~1.5-6s (high variance — exactly the kind of
#     thing the iter-147 variance harness above quantifies). Connection
#     multiplexing reduces warm-handshake cost to ~100-200ms.
#
# Safety:
#
#   - Idempotent dir create (mkdir -p) + correct 0700 perms (chmod 700) —
#     same invariants as iter-146 setup script.
#
#   - Only activates when operator explicitly sets the opt-in env var. No
#     surprise SSH multiplexing for operators who didn't ask for it.
#
#   - Empirical first release in any 10-min window still pays full
#     handshake cost (no cached session to reuse). Subsequent calls benefit.
#
# To validate the speedup empirically, capture a fresh dry-run and compare
# `semantic-release:get-git-auth-url` p50 BEFORE and AFTER:
#
#   # before
#   ITER147_VARIANCE_PROFILE_RUN_COUNT=5 \\
#     scripts/iter147-empirical-n-run-variance-characterization-harness-for-semantic-release-namespace-timings-via-iter144-parser-emitting-p50-p95-mean-stddev-min-max-range.py
#   # after (env-var on)
#   RELEASE_SSH_MULTIPLEXING_ENABLED=1 GIT_SSH_COMMAND="ssh -o ControlMaster=auto -o ControlPath=$HOME/.ssh/controlmasters/%r@%h:%p -o ControlPersist=10m" \\
#     ITER147_VARIANCE_PROFILE_RUN_COUNT=5 \\
#     scripts/iter147-empirical-n-run-variance-characterization-harness-for-semantic-release-namespace-timings-via-iter144-parser-emitting-p50-p95-mean-stddev-min-max-range.py
if [[ "${RELEASE_SSH_MULTIPLEXING_ENABLED:-0}" == "1" ]]; then
    ITER147_SSH_CONTROLMASTERS_DIR_FOR_CACHED_SESSION_SOCKETS_PER_RELEASE_INVOCATION="$HOME/.ssh/controlmasters"
    mkdir -p "$ITER147_SSH_CONTROLMASTERS_DIR_FOR_CACHED_SESSION_SOCKETS_PER_RELEASE_INVOCATION"
    chmod 700 "$ITER147_SSH_CONTROLMASTERS_DIR_FOR_CACHED_SESSION_SOCKETS_PER_RELEASE_INVOCATION"
    export GIT_SSH_COMMAND="ssh -o ControlMaster=auto -o ControlPath=$ITER147_SSH_CONTROLMASTERS_DIR_FOR_CACHED_SESSION_SOCKETS_PER_RELEASE_INVOCATION/%r@%h:%p -o ControlPersist=10m"
    echo "    ⧗ RELEASE_SSH_MULTIPLEXING_ENABLED=1 — GIT_SSH_COMMAND set for this release-pipeline process tree (iter-147)"
    echo "      ControlPath=$ITER147_SSH_CONTROLMASTERS_DIR_FOR_CACHED_SESSION_SOCKETS_PER_RELEASE_INVOCATION/%r@%h:%p, ControlPersist=10m"

    # ─── ITER-149: PRE-WARM the SSH ControlMaster session BEFORE any pipeline-phase
    # SSH operation runs, so the in-pipeline `git push --dry-run` verifyAuth call
    # in Phase 2 gets the WARM-handshake cost (~1.8s per iter-148 measurement),
    # not the COLD-handshake cost (~6.0s per iter-148 BEFORE-condition baseline).
    #
    # WHY THIS IS NEEDED (gap the iter-147 block above leaves open):
    #
    #   The iter-147 block above only EXPORTS `GIT_SSH_COMMAND`. It does NOT
    #   create a cached SSH session. The first SSH operation in the pipeline
    #   (Phase 2 verifyAuth) is the one that creates the cached session — and
    #   thus the FIRST verifyAuth call pays the full cold handshake (~6.0s),
    #   regardless of how many SSH operations come later in the pipeline.
    #   The multiplexing benefit only kicks in for the SECOND+ SSH ops.
    #
    #   iter-148 measured this empirically: the harness's first-run get-git-auth-url
    #   was always slower than subsequent runs in the warm cohort. The iter-148
    #   wrapper pre-warmed BEFORE the AFTER-cohort measurement to eliminate this
    #   bias — that pre-warm pattern is the right thing for the production
    #   release pipeline too.
    #
    # PATTERN (lifted from
    # `scripts/iter148-empirical-validation-wrapper-...sh`):
    #
    #   `ssh -T -o BatchMode=yes -o ControlMaster=auto -o ControlPath=...
    #        -o ControlPersist=10m git@github.com`
    #
    #   - `-T` disables pseudo-TTY allocation (we just want auth + session
    #     creation, not a shell).
    #   - `-o BatchMode=yes` makes it non-interactive — if auth would prompt
    #     (e.g., MFA / key passphrase), the command fails fast instead of
    #     hanging the release pipeline.
    #   - `timeout 10` budget — GitHub typically responds in <1s; 10s is
    #     pessimistic-but-bounded.
    #   - GitHub closes the connection immediately after auth (replies "Hi
    #     <user>! You've successfully authenticated, but GitHub does not
    #     provide shell access."), so the foreground ssh call returns
    #     quickly. The ControlMaster session socket persists per `ControlPersist=10m`.
    #
    # EXPECTED EMPIRICAL IMPACT (per iter-148 measurement):
    #
    #   Pre-warm itself: ~1.5-2s (cold handshake during pre-warm)
    #   Saved on first in-pipeline SSH op: ~4.2s (6.0s cold → 1.8s warm)
    #   Net per release: ~2.2-2.7s saved when knob is on
    #
    #   Additional benefit: ALL in-pipeline SSH ops (verifyAuth +
    #   @semantic-release/git push + successCmd push) get warm cost,
    #   compounding the savings across the 3-4 SSH calls in a release.
    echo "    ⧗ ITER-149: pre-warming ControlMaster session to github.com (10s budget) so verifyAuth pays warm cost..."
    iter149_release_pipeline_ssh_controlmaster_prewarm_to_github_com_to_pay_cold_handshake_upfront() {
        # Run inline; on success, GitHub sends "Hi <user>!..." then closes.
        # On failure (no key, no network), `|| true` keeps the pipeline going
        # — release will still work, just without the iter-149 prewarm benefit.
        # shellcheck disable=SC2086  # timeout takes int seconds, not a quoted string
        timeout 10 ssh \
            -T \
            -o BatchMode=yes \
            -o ControlMaster=auto \
            -o ControlPath="$ITER147_SSH_CONTROLMASTERS_DIR_FOR_CACHED_SESSION_SOCKETS_PER_RELEASE_INVOCATION/%r@%h:%p" \
            -o ControlPersist=10m \
            git@github.com 2>&1 | head -1 || true
    }
    iter149_release_pipeline_ssh_controlmaster_prewarm_to_github_com_to_pay_cold_handshake_upfront
    if [[ -S "$ITER147_SSH_CONTROLMASTERS_DIR_FOR_CACHED_SESSION_SOCKETS_PER_RELEASE_INVOCATION/git@github.com:22" ]]; then
        echo "    ✓ ITER-149: cached ControlMaster session active at git@github.com:22 — in-pipeline SSH ops will pay WARM cost"
    else
        echo "    ⚠ ITER-149: pre-warm did not create a cached session socket (auth issue? network?) — release will proceed but pay cold SSH cost"
    fi
fi

echo ""
echo "╔═══════════════════════════════════════════════════════════╗"
echo "║  cc-skills Full Release Workflow                          ║"
echo "╚═══════════════════════════════════════════════════════════╝"
echo ""

# Phase 1: Preflight (explicitly invoked rather than via `depends=` so iter-139
# instrumentation can wrap it; functionally identical to a mise dep).
__iter139_wrap_release_phase_invocation_with_epochrealtime_wall_clock_capture_for_release_timing_profile_top_n_bottleneck_ranking \
    "Phase 1: preflight (sixty test files + seventeen audits parallel-pre-warm + plugin manifest validation)" \
    mise run release:preflight

# Phase 1.5: Pre-sync
# Mirrors current HEAD to ~/.claude so the live environment reflects
# pending plugin changes BEFORE semantic-release runs. Idempotent with
# Phase 3 post-sync; skips gracefully if local commits are unpushed.
__iter139_wrap_release_phase_invocation_with_epochrealtime_wall_clock_capture_for_release_timing_profile_top_n_bottleneck_ranking \
    "Phase 1.5: presync (mirror current HEAD to live ~/.claude marketplace clone)" \
    mise run release:presync

# Phase 2: Version
__iter139_wrap_release_phase_invocation_with_epochrealtime_wall_clock_capture_for_release_timing_profile_top_n_bottleneck_ranking \
    "Phase 2: version (semantic-release commit-analyzer + version-bump + changelog + git-tag + GitHub-release + jsDelivr-CDN-purge)" \
    mise run release:version

# Phase 3: Sync
__iter139_wrap_release_phase_invocation_with_epochrealtime_wall_clock_capture_for_release_timing_profile_top_n_bottleneck_ranking \
    "Phase 3: sync (post-release marketplace clone update + hook installation + cache population + jsDelivr smoke-test)" \
    mise run release:sync

# Phase 4: Verify
__iter139_wrap_release_phase_invocation_with_epochrealtime_wall_clock_capture_for_release_timing_profile_top_n_bottleneck_ranking \
    "Phase 4: verify (cross-validate marketplace.json + plugin manifests + installed cache + enabled-plugins state for drift)" \
    mise run release:verify

# Phase 4.5: Session Chronicle (PRIVATE REPOS ONLY)
# Bundles sanitized session JSONLs from the previous-release window into a
# tarball attached to the GitHub release. Skips silently for public repos.
__iter139_wrap_release_phase_invocation_with_epochrealtime_wall_clock_capture_for_release_timing_profile_top_n_bottleneck_ranking \
    "Phase 4.5: chronicle (sanitize-and-bundle session JSONLs from previous-release window; SKIPPED on public repos)" \
    mise run release:chronicle

# Phase 5: Postflight
__iter139_wrap_release_phase_invocation_with_epochrealtime_wall_clock_capture_for_release_timing_profile_top_n_bottleneck_ranking \
    "Phase 5: postflight (lockfile-drift + working-directory-clean + all-commits-pushed-to-remote validation)" \
    mise run release:postflight

echo ""
echo "╔═══════════════════════════════════════════════════════════╗"
echo "║  ✓ Release workflow complete!                             ║"
echo "╚═══════════════════════════════════════════════════════════╝"
echo ""

# Iter-139: emit whole-pipeline wall-clock total + top-N bottleneck ranking
# so operators can confirm sum-of-phases ≈ whole-pipeline and see which
# phase to attack next.
if [[ "${RELEASE_TIMING_PROFILE:-0}" == "1" ]] && [[ -n "$release_timing_profile_whole_pipeline_start_seconds_using_epochrealtime" ]]; then
    release_timing_profile_whole_pipeline_end_seconds_using_epochrealtime="$EPOCHREALTIME"
    release_timing_profile_whole_pipeline_elapsed_milliseconds=$(awk \
        -v s="$release_timing_profile_whole_pipeline_start_seconds_using_epochrealtime" \
        -v e="$release_timing_profile_whole_pipeline_end_seconds_using_epochrealtime" \
        'BEGIN { printf "%.0f", (e - s) * 1000 }')
    echo "    ⧗ whole-pipeline elapsed: ${release_timing_profile_whole_pipeline_elapsed_milliseconds}ms (release:full total)"
fi
__iter139_emit_top_n_slowest_release_phases_ranked_by_elapsed_milliseconds_descending_bottleneck_summary
