set -euo pipefail
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
readonly GENERATED_DIR="${PROJECT_ROOT}/generated"
readonly BACKUP_DIR="${PROJECT_ROOT}/.generated-backup"
readonly LOG_DIR="${PROJECT_ROOT}/logs"
readonly RED='\033[0;31m'
readonly GREEN='\033[0;32m'
readonly YELLOW='\033[1;33m'
readonly BLUE='\033[0;34m'
readonly CYAN='\033[0;36m'
readonly MAGENTA='\033[0;35m'
readonly NC='\033[0m'
SKIP_BACKUP=false
VERBOSE=false
mkdir -p "${LOG_DIR}"
print_pass() { echo -e "${GREEN}✅ PASS${NC}: $*"; }
print_fail() { echo -e "${RED}❌ FAIL${NC}: $*"; }
print_info() { echo -e "${BLUE}ℹ️ INFO${NC}: $*"; }
print_warn() { echo -e "${YELLOW}⚠️ WARN${NC}: $*"; }
print_step() { echo -e "${CYAN}▶${NC} $*"; }
print_test() { echo -e "${MAGENTA}🧪 TEST${NC}: $*"; }
usage() {
cat << 'EOF'
ln_ctrl Regeneration Script - Test Determinism
Validates that ggen produces identical output on repeated runs (μ ∘ μ = μ).
Usage: ./regen.sh [options]
Options:
--skip-backup Skip backing up current generated/
-v, --verbose Enable verbose output
-h, --help Show this help message
Process:
1. Backup current generated/ directory
2. Compute hash of current artifacts (HASH_1)
3. Delete generated/ directory
4. Re-run ggen sync (full pipeline)
5. Compute hash of new artifacts (HASH_2)
6. Compare HASH_1 vs HASH_2 (must match)
7. Run verification
8. Restore from backup if regeneration fails
Examples:
./regen.sh # Full determinism test
./regen.sh --verbose # With detailed output
./regen.sh --skip-backup # No backup (faster, risky)
Exit codes:
0 - Success (deterministic generation confirmed)
1 - Failure (non-deterministic or verification failed)
2 - Error (missing dependencies, invalid state)
EOF
}
compute_hash() {
local dir="$1"
if [[ ! -d "$dir" ]]; then
echo "NONE"
return
fi
find "$dir" -type f ! -path "*/target/*" ! -name ".ggen-hash" -exec sha256sum {} \; 2>/dev/null \
| sort \
| sha256sum \
| cut -d' ' -f1
}
backup_generated() {
print_step "Backing up generated directory..."
if [[ ! -d "${GENERATED_DIR}" ]]; then
print_info "No generated directory to backup"
return 0
fi
if [[ "$SKIP_BACKUP" == "true" ]]; then
print_info "Skipping backup (--skip-backup flag)"
return 0
fi
if [[ -d "${BACKUP_DIR}" ]]; then
rm -rf "${BACKUP_DIR}"
fi
cp -r "${GENERATED_DIR}" "${BACKUP_DIR}"
local file_count
file_count=$(find "${BACKUP_DIR}" -type f | wc -l)
print_pass "Backup created (${file_count} files)"
return 0
}
restore_backup() {
print_step "Restoring from backup..."
if [[ ! -d "${BACKUP_DIR}" ]]; then
print_warn "No backup found to restore"
return 1
fi
if [[ -d "${GENERATED_DIR}" ]]; then
rm -rf "${GENERATED_DIR}"
fi
cp -r "${BACKUP_DIR}" "${GENERATED_DIR}"
print_pass "Backup restored"
return 0
}
delete_generated() {
print_step "Deleting generated directory..."
if [[ ! -d "${GENERATED_DIR}" ]]; then
print_info "Generated directory does not exist"
return 0
fi
local file_count
file_count=$(find "${GENERATED_DIR}" -type f | wc -l)
rm -rf "${GENERATED_DIR}"
print_pass "Deleted ${file_count} files"
return 0
}
run_sync() {
print_step "Running ggen sync (full pipeline)..."
local run_script="${SCRIPT_DIR}/run.sh"
if [[ ! -f "$run_script" ]]; then
print_fail "Run script not found: ${run_script}"
return 1
fi
if [[ ! -x "$run_script" ]]; then
chmod +x "$run_script"
fi
local log_file="${LOG_DIR}/regen-sync-$(date +%Y%m%d-%H%M%S).log"
if [[ "$VERBOSE" == "true" ]]; then
if bash "$run_script" --no-audit 2>&1 | tee "$log_file"; then
print_pass "Sync completed"
return 0
else
print_fail "Sync failed (see ${log_file})"
return 1
fi
else
if bash "$run_script" --no-audit > "$log_file" 2>&1; then
print_pass "Sync completed"
return 0
else
print_fail "Sync failed (see ${log_file})"
tail -n 20 "$log_file"
return 1
fi
fi
}
compare_hashes() {
local hash1="$1"
local hash2="$2"
print_test "Comparing hashes (determinism check)..."
if [[ "$VERBOSE" == "true" ]]; then
print_info "HASH_1 (original): ${hash1}"
print_info "HASH_2 (regenerated): ${hash2}"
fi
if [[ "$hash1" == "NONE" ]]; then
print_warn "Original hash not available (first run)"
return 0
fi
if [[ "$hash2" == "NONE" ]]; then
print_fail "Regeneration produced no output"
return 1
fi
if [[ "$hash1" == "$hash2" ]]; then
print_pass "Hashes match (μ ∘ μ = μ confirmed)"
return 0
else
print_fail "Hash mismatch (non-deterministic generation detected)"
print_info "This indicates the generation process is not deterministic"
print_info "Possible causes: timestamps, random values, file ordering"
return 1
fi
}
run_verification() {
print_step "Running verification..."
local verify_script="${SCRIPT_DIR}/verify.sh"
if [[ ! -f "$verify_script" ]]; then
print_warn "Verification script not found: ${verify_script}"
return 0
fi
if [[ ! -x "$verify_script" ]]; then
chmod +x "$verify_script"
fi
if bash "$verify_script"; then
print_pass "Verification passed"
return 0
else
print_fail "Verification failed"
return 1
fi
}
print_summary() {
local hash1="$1"
local hash2="$2"
local deterministic="$3"
local verification="$4"
local overall="$5"
echo ""
echo "=============================================="
echo "ln_ctrl Regeneration Summary"
echo "=============================================="
echo "Project: ${PROJECT_ROOT}"
echo "Timestamp: $(date -u +"%Y-%m-%dT%H:%M:%SZ")"
echo "----------------------------------------------"
echo "HASH_1: ${hash1}"
echo "HASH_2: ${hash2}"
echo "----------------------------------------------"
if [[ "$deterministic" -eq 0 ]]; then
echo -e "Determinism: ${GREEN}✅ PASS${NC}"
else
echo -e "Determinism: ${RED}❌ FAIL${NC}"
fi
if [[ "$verification" -eq 0 ]]; then
echo -e "Verification: ${GREEN}✅ PASS${NC}"
else
echo -e "Verification: ${RED}❌ FAIL${NC}"
fi
echo "=============================================="
if [[ "$overall" -eq 0 ]]; then
echo -e "${GREEN}RESULT: SUCCESS${NC}"
echo -e "${GREEN}Formula μ ∘ μ = μ validated${NC}"
else
echo -e "${RED}RESULT: FAILURE${NC}"
fi
echo ""
}
main() {
while [[ $# -gt 0 ]]; do
case "$1" in
--skip-backup)
SKIP_BACKUP=true
shift
;;
-v|--verbose)
VERBOSE=true
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1"
usage
exit 2
;;
esac
done
echo ""
echo "=============================================="
echo "ln_ctrl Regeneration - Determinism Test"
echo "=============================================="
echo "Formula: μ ∘ μ = μ"
echo "Testing: HASH(μ(O)) = HASH(μ(μ(O)))"
echo "----------------------------------------------"
echo ""
local hash1="NONE"
local hash2="NONE"
local deterministic=1
local verification=1
local overall=1
if ! backup_generated; then
print_fail "Backup failed"
exit 2
fi
print_step "Computing original hash..."
hash1=$(compute_hash "${GENERATED_DIR}")
if [[ "$hash1" != "NONE" ]]; then
print_info "HASH_1: ${hash1}"
else
print_info "No existing generated/ directory"
fi
if ! delete_generated; then
print_fail "Failed to delete generated directory"
exit 2
fi
if ! run_sync; then
print_fail "Regeneration failed"
restore_backup
exit 1
fi
print_step "Computing regenerated hash..."
hash2=$(compute_hash "${GENERATED_DIR}")
if [[ "$hash2" != "NONE" ]]; then
print_info "HASH_2: ${hash2}"
fi
if compare_hashes "$hash1" "$hash2"; then
deterministic=0
else
deterministic=1
fi
if run_verification; then
verification=0
else
verification=1
fi
if [[ $deterministic -eq 0 ]] && [[ $verification -eq 0 ]]; then
overall=0
else
overall=1
fi
print_summary "$hash1" "$hash2" "$deterministic" "$verification" "$overall"
if [[ $overall -eq 0 ]] && [[ -d "${BACKUP_DIR}" ]]; then
rm -rf "${BACKUP_DIR}"
print_info "Backup removed (regeneration successful)"
fi
exit $overall
}
main "$@"