#!/usr/bin/env bash # Run the complete CADFS corpus while retaining a snapshot of the prior run. set -Eeuo pipefail ROOT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" INPUT_DIR="${ROOT_DIR}/data/cadfs-sample/CADFS_test" OUTPUT_DIR="${ROOT_DIR}/cadfs_to_cdsl/output" HISTORY_DIR="${ROOT_DIR}/cadfs_to_cdsl/output-history" WORKERS=4 TIMEOUT_SECONDS=60 COMPARE_MODE=rp FORCE=true usage() { cat <<'EOF' Usage: ./cadfs_to_cdsl/run_full_rebuild.sh [options] Runs conversion, CDSL rebuild, STEP comparison, and the Markdown report for every sample in data/cadfs-sample/CADFS_test. By default the existing cadfs_to_cdsl/output directory is moved to cadfs_to_cdsl/output-history// before a forced full rerun. Options: --resume Reuse cached results in output; do not archive or force rerun. --workers N Concurrent samples (1-8, default: 4). --timeout-seconds N Per-model rebuild timeout in seconds (default: 60). --compare-mode rp|strict Comparison acceptance mode (default: rp). -h, --help Show this help message. EOF } while [[ $# -gt 0 ]]; do case "$1" in --resume) FORCE=false shift ;; --workers) [[ $# -ge 2 ]] || { echo "--workers requires a value" >&2; exit 2; } WORKERS="$2" shift 2 ;; --timeout-seconds) [[ $# -ge 2 ]] || { echo "--timeout-seconds requires a value" >&2; exit 2; } TIMEOUT_SECONDS="$2" shift 2 ;; --compare-mode) [[ $# -ge 2 ]] || { echo "--compare-mode requires a value" >&2; exit 2; } COMPARE_MODE="$2" shift 2 ;; -h|--help) usage exit 0 ;; *) echo "Unknown option: $1" >&2 usage >&2 exit 2 ;; esac done [[ "$WORKERS" =~ ^[1-8]$ ]] || { echo "--workers must be an integer between 1 and 8" >&2; exit 2; } [[ "$TIMEOUT_SECONDS" =~ ^[0-9]+([.][0-9]+)?$ ]] && (( $(awk "BEGIN { print (${TIMEOUT_SECONDS} > 0) }") )) || { echo "--timeout-seconds must be positive" >&2 exit 2 } [[ "$COMPARE_MODE" == "rp" || "$COMPARE_MODE" == "strict" ]] || { echo "--compare-mode must be rp or strict" >&2 exit 2 } [[ -d "$INPUT_DIR" ]] || { echo "CADFS input directory not found: $INPUT_DIR" >&2; exit 1; } [[ -f "$INPUT_DIR/CADFS_text_test.jsonl" ]] || { echo "CADFS text manifest not found: $INPUT_DIR/CADFS_text_test.jsonl" >&2; exit 1; } if [[ -x "${ROOT_DIR}/backend/.venv/bin/python" ]]; then PYTHON_BIN="${PYTHON_BIN:-${ROOT_DIR}/backend/.venv/bin/python}" else PYTHON_BIN="${PYTHON_BIN:-python3}" fi command -v "$PYTHON_BIN" >/dev/null 2>&1 || { echo "Python executable not found: $PYTHON_BIN" >&2; exit 1; } archive_output() { [[ -d "$OUTPUT_DIR" ]] || return [[ -n "$(find "$OUTPUT_DIR" -mindepth 1 -maxdepth 1 -print -quit)" ]] || return mkdir -p "$HISTORY_DIR" local timestamp archive_dir suffix=1 timestamp="$(date +%Y%m%d-%H%M%S)" archive_dir="${HISTORY_DIR}/${timestamp}" while [[ -e "$archive_dir" ]]; do archive_dir="${HISTORY_DIR}/${timestamp}-${suffix}" ((suffix += 1)) done mv "$OUTPUT_DIR" "$archive_dir" echo "Previous output archived at: $archive_dir" } on_error() { local code=$? echo "Run stopped with exit code ${code}. Partial artifacts remain in: $OUTPUT_DIR" >&2 exit "$code" } trap on_error ERR if [[ "$FORCE" == true ]]; then archive_output echo "Starting forced full corpus rebuild." else echo "Resuming existing full corpus rebuild without archiving output." fi mkdir -p "$OUTPUT_DIR" cd "$ROOT_DIR" pipeline_args=( pipeline --input "$INPUT_DIR" --output "$OUTPUT_DIR" --workers "$WORKERS" --timeout-seconds "$TIMEOUT_SECONDS" --compare-mode "$COMPARE_MODE" ) if [[ "$FORCE" == true ]]; then pipeline_args+=(--force) fi PYTHONPATH="${ROOT_DIR}/backend:${ROOT_DIR}${PYTHONPATH:+:${PYTHONPATH}}" \ "$PYTHON_BIN" -m cadfs_to_cdsl "${pipeline_args[@]}" PYTHONPATH="${ROOT_DIR}/backend:${ROOT_DIR}${PYTHONPATH:+:${PYTHONPATH}}" \ "$PYTHON_BIN" -m cadfs_to_cdsl report --input "$INPUT_DIR" --output "$OUTPUT_DIR" --markdown echo "Current results: $OUTPUT_DIR" echo "Full report: $OUTPUT_DIR/full_run_report.md"