#!/usr/bin/env bash
# v1.7.2 AC2 载体 —— `fuzz` **语料回归**门(固定时长 · **非**开放 fuzz)
#
# 承路标 `AC2` 逐字: 「`cargo-fuzz`(或同等)靶 + 语料库入库; `CI` 跑**语料回归**(固定时长,
#   非开放 `fuzz`), 新崩溃 ⇒ 必红 ∧ 语料入库」。
# 承 `ar` 裁决 `05` 裁3: 靶 = `parse_worker_threads` 纯解析面(**真分支非空函数**)∧
#   语料入库(`≥1`)∧ `CI` 固定时长回放(**确定性**; 开放 `fuzz` 非确定, 不合门禁)。
#
# ★★ 何以为【回放】而非【开放 fuzz】(**决定性**): 开放 fuzz 之**耗时与结果皆非确定**
#   ⇒ 作门禁即「以掷骰充判据」。回放 = `-runs=0`(libFuzzer 逐语料各执行**一次**, 无变异)
#   ⇒ **确定性 ∧ 有界**(本席实测: `6` 语料 ⇒ `7` runs ∧ `0` 秒)。
#
# ★★ 红侧之**可判形**(承裁决05 裁3): 语料含**已知崩溃输入** ⇒ 回放**必红**(`rc≠0`)。
#   本载体之红侧由腿件 `scripts/tests/ac2_fuzz_leg.sh` 之 `R1` 承载(**临时面**注入必崩靶 +
#   触发语料 ⇒ 必红 · **不入库**)。
#
# 判据面: `fuzz/`(靶 crate ∧ 语料)∧ `deep/`(靶所引之同源纯函数)
# 器: `cargo` + `nightly-2026-09-29` + `cargo-fuzz` + `libfuzzer-sys`
#
# 用法: bash scripts/fuzz_replay_gate.sh [仓根]
# 退出码: 0 = 靶面非空 ∧ 语料非空 ∧ 回放 rc=0 / 1 = 任一不符
set -uo pipefail

ROOT="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
cd "$ROOT" || { echo "仓根不可达: $ROOT" >&2; exit 1; }
TC="nightly-2026-09-29"
FUZZ_DIR="$ROOT/fuzz"
[ -d "$FUZZ_DIR" ] || { echo "::error::fuzz 门(AC2): 缺 $FUZZ_DIR"; exit 1; }

# ① 靶面非空(禁「为满足 AC 而 fuzz 空函数」—— 靶数 0 即失真, 非绿)
N_TARGETS="$(find "$FUZZ_DIR/fuzz_targets" -maxdepth 1 -name '*.rs' 2>/dev/null | wc -l)"
[ "$N_TARGETS" -ge 1 ] || { echo "::error::fuzz 门(AC2): 靶面空(fuzz_targets/*.rs = 0)—— 禁空跑绿"; exit 1; }
TARGET="$(find "$FUZZ_DIR/fuzz_targets" -maxdepth 1 -name '*.rs' -printf '%f\n' 2>/dev/null | sed 's/\.rs$//' | head -1)"
CORPUS="$FUZZ_DIR/corpus/$TARGET"

# ② 语料入库且非空
# ★★ 并载(**本席当场实测之订正** · 须显名): libFuzzer **不加载 0 字节语料档**
#   (实测: 文件系统 7 档 ⇒ `files found` 6 ⇒ 差 1 = 0 字节之 `empty`)⇒ 语料档须**非空**
#   (否则其**不入回放面** —— 「语料入库 ≥1」之谓词会**高估**覆盖面)。本席已删该空档,
#   并使下行【非空档】计数与 libFuzzer 之 `files found` **对表**(二源同值方为真覆盖面)。
[ -d "$CORPUS" ] || { echo "::error::fuzz 门(AC2): 缺语料库 $CORPUS"; exit 1; }
N_EMPTY="$(find "$CORPUS" -maxdepth 1 -type f -size 0 | wc -l)"
[ "$N_EMPTY" -eq 0 ] || { echo "::error::fuzz 门(AC2): 语料库含 $N_EMPTY 个 0 字节档 —— libFuzzer 不加载之 ⇒ 不入回放面(高估覆盖面)"; exit 1; }
N_CORPUS="$(find "$CORPUS" -maxdepth 1 -type f | wc -l)"
[ "$N_CORPUS" -ge 1 ] || { echo "::error::fuzz 门(AC2): 语料库空 ⇒ 回放无对象(禁空跑绿)"; exit 1; }
echo "[fuzz] 靶 = $TARGET ∧ 靶面 = $N_TARGETS 档 ∧ 语料 = $N_CORPUS 档($CORPUS)"

# ③ 语料回归(固定时长 · `-runs=0` ⇒ 逐语料一次 · 确定性)
OUT="$(cd "$FUZZ_DIR" && timeout 1800 cargo "+$TC" fuzz run "$TARGET" "corpus/$TARGET" -- -runs=0 2>&1)"
RC=$?
printf '%s\n' "$OUT" | grep -E 'files found|seed corpus|DONE|Done [0-9]+ runs|ERROR|SUMMARY' | tail -6
if [ "$RC" -ne 0 ]; then
    echo "::error::fuzz 门(AC2): 语料回归 rc=$RC ⇒ **存在崩溃输入**(新崩溃 ⇒ 必红 · 承 AC2 逐字)"
    printf '%s\n' "$OUT" | grep -iE 'crash|panic|ERROR|SUMMARY|artifact' | tail -8
    exit 1
fi
# ★ 非空跑之证: 回放须**真执行**语料(`seed corpus` 行须见)
printf '%s\n' "$OUT" | grep -q 'seed corpus' \
    || { echo "::error::fuzz 门(AC2): 未见 seed corpus 行 ⇒ 回放未真跑(禁空跑绿)"; exit 1; }
echo "[fuzz] 语料回归 rc=0 ⇒ 零崩溃 ✓"
exit 0