#!/bin/sh
set -eu

PROJECT_ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
DIST_DIR="$PROJECT_ROOT/dist"
MACHINE=$(uname -m)

if [ "$MACHINE" != "arm64" ]; then
    printf '%s\n' "The current bootstrap targets Apple Silicon arm64; current machine is $MACHINE." >&2
    exit 1
fi

for tool in clang cmp xattr codesign jq; do
    if ! command -v "$tool" >/dev/null 2>&1; then
        printf '%s\n' "Required developer build tool not found: $tool" >&2
        exit 1
    fi
done

cd "$PROJECT_ROOT"
# Let all compiler stages resolve the standard library from this checkout,
# including smoke fixtures built in temporary working directories.
export YAZA_STDLIB_DIR="$PROJECT_ROOT"
mkdir -p "$DIST_DIR"
STAGE_DIR=$(mktemp -d "${TMPDIR:-/tmp}/yaza-bootstrap.XXXXXX")
cleanup() {
    rm -rf "$STAGE_DIR"
}
trap cleanup EXIT HUP INT TERM

BOOTSTRAP_BIN=${YAZA_BOOTSTRAP:-"$DIST_DIR/yaza"}
if [ ! -x "$BOOTSTRAP_BIN" ]; then
    printf '%s\n' "A native YAZA bootstrap binary is required. Install dist/yaza or set YAZA_BOOTSTRAP to an existing native YAZA compiler." >&2
    exit 1
fi
printf 'Using native YAZA compiler as stage zero: %s\n' "$BOOTSTRAP_BIN"
"$BOOTSTRAP_BIN" build compiler/native_cli.yz -o "$STAGE_DIR/yaza-stage1"
"$STAGE_DIR/yaza-stage1" build compiler/native_cli.yz -o "$STAGE_DIR/yaza-stage2"
"$STAGE_DIR/yaza-stage2" build compiler/native_cli.yz -o "$STAGE_DIR/yaza-stage3"

if ! cmp -s "$STAGE_DIR/yaza-stage2.yz.c" "$STAGE_DIR/yaza-stage3.yz.c"; then
    printf '%s\n' "Self-host check failed: consecutive native compiler stages emitted different C source." >&2
    exit 1
fi

"$STAGE_DIR/yaza-stage3" --version
clang -std=c11 -O2 tests/memory_arena.c -o "$STAGE_DIR/memory-arena-test"
"$STAGE_DIR/memory-arena-test"
clang -std=c11 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer tests/memory_arena.c -o "$STAGE_DIR/memory-arena-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/memory-arena-sanitized"
clang -std=c11 -O2 -pthread tests/runtime_thread_context.c -o "$STAGE_DIR/runtime-thread-context-test"
"$STAGE_DIR/runtime-thread-context-test"
clang -std=c11 -O1 -g -pthread -fsanitize=address,undefined -fno-omit-frame-pointer tests/runtime_thread_context.c -o "$STAGE_DIR/runtime-thread-context-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/runtime-thread-context-sanitized"
clang -std=c11 -D_DARWIN_C_SOURCE -D_POSIX_C_SOURCE=200809L -O2 -pthread tests/http_worker_concurrency.c -o "$STAGE_DIR/http-worker-concurrency-test"
"$STAGE_DIR/http-worker-concurrency-test"
clang -std=c11 -D_DARWIN_C_SOURCE -D_POSIX_C_SOURCE=200809L -O1 -g -pthread -fsanitize=address,undefined -fno-omit-frame-pointer tests/http_worker_concurrency.c -o "$STAGE_DIR/http-worker-concurrency-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/http-worker-concurrency-sanitized"
clang -std=c11 -D_DARWIN_C_SOURCE -D_POSIX_C_SOURCE=200809L -O1 -g -pthread -fsanitize=thread -fno-omit-frame-pointer tests/http_worker_concurrency.c -o "$STAGE_DIR/http-worker-concurrency-thread-sanitized"
"$STAGE_DIR/http-worker-concurrency-thread-sanitized"
clang -std=c11 -O2 tests/scheduler.c -o "$STAGE_DIR/scheduler-test"
"$STAGE_DIR/scheduler-test"
clang -std=c11 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer tests/scheduler.c -o "$STAGE_DIR/scheduler-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/scheduler-sanitized"
clang -std=c11 -O2 tests/io_backend.c -o "$STAGE_DIR/io-backend-test"
"$STAGE_DIR/io-backend-test"
clang -std=c11 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer tests/io_backend.c -o "$STAGE_DIR/io-backend-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/io-backend-sanitized"
clang -std=c11 -O2 tests/http_async_response.c -o "$STAGE_DIR/http-async-response-test"
"$STAGE_DIR/http-async-response-test"
clang -std=c11 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer tests/http_async_response.c -o "$STAGE_DIR/http-async-response-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/http-async-response-sanitized"
clang -std=c11 -O2 tests/http_rate_limit.c -o "$STAGE_DIR/http-rate-limit-test"
"$STAGE_DIR/http-rate-limit-test"
clang -std=c11 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer tests/http_rate_limit.c -o "$STAGE_DIR/http-rate-limit-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/http-rate-limit-sanitized"
clang -std=c11 -O2 tests/json_depth.c -o "$STAGE_DIR/json-depth-test"
"$STAGE_DIR/json-depth-test"
clang -std=c11 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer tests/json_depth.c -o "$STAGE_DIR/json-depth-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/json-depth-sanitized"
clang -std=c11 -O2 tests/secure_random.c -o "$STAGE_DIR/secure-random-test"
"$STAGE_DIR/secure-random-test"
clang -std=c11 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer tests/secure_random.c -o "$STAGE_DIR/secure-random-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/secure-random-sanitized"
clang -std=c11 -O2 tests/net_transport.c -o "$STAGE_DIR/net-transport-test"
"$STAGE_DIR/net-transport-test"
clang -std=c11 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer tests/net_transport.c -o "$STAGE_DIR/net-transport-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/net-transport-sanitized"
clang -std=c11 -O2 -pthread tests/pg_pool.c -o "$STAGE_DIR/pg-pool-test"
"$STAGE_DIR/pg-pool-test"
clang -std=c11 -O1 -g -pthread -fsanitize=address,undefined -fno-omit-frame-pointer tests/pg_pool.c -o "$STAGE_DIR/pg-pool-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/pg-pool-sanitized"
clang -std=c11 -O2 -pthread tests/fsroot.c -o "$STAGE_DIR/fsroot-test"
"$STAGE_DIR/fsroot-test"
clang -std=c11 -O1 -g -pthread -fsanitize=address,undefined -fno-omit-frame-pointer tests/fsroot.c -o "$STAGE_DIR/fsroot-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/fsroot-sanitized"
clang -std=c11 -O2 -pthread tests/ttl_cache.c -o "$STAGE_DIR/ttl-cache-test"
"$STAGE_DIR/ttl-cache-test"
clang -std=c11 -O1 -g -pthread -fsanitize=address,undefined -fno-omit-frame-pointer tests/ttl_cache.c -o "$STAGE_DIR/ttl-cache-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/ttl-cache-sanitized"
ASAN_OPTIONS=detect_leaks=0 YAZA_FUZZ_RUNS=10000 YAZA_FUZZ_BINARY="$STAGE_DIR/fuzz-runtime" sh scripts/fuzz-runtime.sh -runs=10000
"$STAGE_DIR/yaza-stage3" check compiler/native_cli.yz
"$STAGE_DIR/yaza-stage3" arch check test-fixtures/architecture-multiline
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-break.yz > "$STAGE_DIR/invalid-break.log" 2>&1; then
    printf '%s\n' "Compiler accepted break outside a loop." >&2
    exit 1
fi
grep -F 'break is only valid inside a loop' "$STAGE_DIR/invalid-break.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-continue.yz > "$STAGE_DIR/invalid-continue.log" 2>&1; then
    printf '%s\n' "Compiler accepted continue outside a loop." >&2
    exit 1
fi
grep -F 'continue is only valid inside a loop' "$STAGE_DIR/invalid-continue.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-inline-elif-after-else.yz > "$STAGE_DIR/invalid-inline-elif-after-else.log" 2>&1; then
    printf '%s\n' "Compiler accepted an inline elif after else." >&2
    exit 1
fi
grep -F 'elif has no matching if' "$STAGE_DIR/invalid-inline-elif-after-else.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-return-path.yz > "$STAGE_DIR/invalid-return-path.log" 2>&1; then
    printf '%s\n' "Compiler accepted a function with a conditional path that falls through without a return." >&2
    exit 1
fi
grep -F 'function must return on every path' "$STAGE_DIR/invalid-return-path.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-nested-match-return-path.yz > "$STAGE_DIR/invalid-nested-match-return-path.log" 2>&1; then
    printf '%s\n' "Compiler treated a nested match return as covering an outer conditional path." >&2
    exit 1
fi
grep -F 'function must return on every path' "$STAGE_DIR/invalid-nested-match-return-path.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-numeric-range-type.yz > "$STAGE_DIR/invalid-numeric-range-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted non-integer numeric range bounds." >&2
    exit 1
fi
grep -F 'numeric for range bounds must be Number' "$STAGE_DIR/invalid-numeric-range-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-option-type.yz > "$STAGE_DIR/invalid-option-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted a value with the wrong Option payload type." >&2
    exit 1
fi
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-secret-display.yz > "$STAGE_DIR/invalid-secret-display.log" 2>&1; then
    printf '%s\n' "Compiler allowed SecretText to be printed without an explicit reveal." >&2
    exit 1
fi
grep -F 'say does not support this value type' "$STAGE_DIR/invalid-secret-display.log" >/dev/null
grep -F 'does not match expression type' "$STAGE_DIR/invalid-option-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-type-depth.yz > "$STAGE_DIR/invalid-type-depth.log" 2>&1; then
    printf '%s\n' "Compiler accepted a type nested beyond its configured depth limit." >&2
    exit 1
fi
grep -F 'Option/Result/List nesting exceeds 16 levels' "$STAGE_DIR/invalid-type-depth.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-option-untyped-none.yz > "$STAGE_DIR/invalid-option-untyped-none.log" 2>&1; then
    printf '%s\n' "Compiler accepted none without a concrete Option type context." >&2
    exit 1
fi
grep -F 'option_is_some expects Option[T]' "$STAGE_DIR/invalid-option-untyped-none.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-option-equality.yz > "$STAGE_DIR/invalid-option-equality.log" 2>&1; then
    printf '%s\n' "Compiler accepted direct Option equality without matching." >&2
    exit 1
fi
grep -F 'inspect Option/Result with their variant checks instead of equality' "$STAGE_DIR/invalid-option-equality.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-result-equality.yz > "$STAGE_DIR/invalid-result-equality.log" 2>&1; then
    printf '%s\n' "Compiler accepted direct Result equality without matching." >&2
    exit 1
fi
grep -F 'inspect Option/Result with their variant checks instead of equality' "$STAGE_DIR/invalid-result-equality.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-secure-random-type.yz > "$STAGE_DIR/invalid-secure-random-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted a non-Number secure_random_bytes length." >&2
    exit 1
fi
grep -F 'secure_random_bytes expects (Number length)' "$STAGE_DIR/invalid-secure-random-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-float64-exponent.yz > "$STAGE_DIR/invalid-float64-exponent.log" 2>&1; then
    printf '%s\n' "Compiler accepted a Float64 exponent without digits." >&2
    exit 1
fi
if "$STAGE_DIR/yaza-stage3" run test-fixtures/invalid-int32-range.yz > "$STAGE_DIR/invalid-int32-range.log" 2>&1; then
    printf '%s\n' "Runtime accepted a Number outside the Int32 range." >&2
    exit 1
fi
grep -F 'Number to Int32 conversion is out of range' "$STAGE_DIR/invalid-int32-range.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" run test-fixtures/invalid-int32-overflow.yz > "$STAGE_DIR/invalid-int32-overflow.log" 2>&1; then
    printf '%s\n' "Runtime accepted overflowing Int32 arithmetic." >&2
    exit 1
fi
grep -F 'Int32 overflow during addition' "$STAGE_DIR/invalid-int32-overflow.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-field.yz > "$STAGE_DIR/invalid-shape-field.log" 2>&1; then
    printf '%s\n' "Compiler accepted access to an undeclared shape field." >&2
    exit 1
fi
grep -F "has no field 'unknown'" "$STAGE_DIR/invalid-shape-field.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-constructor.yz > "$STAGE_DIR/invalid-shape-constructor.log" 2>&1; then
    printf '%s\n' "Compiler accepted a shape constructor with a mismatched field type." >&2
    exit 1
fi
grep -F "shape constructor argument type mismatch for field 'id'" "$STAGE_DIR/invalid-shape-constructor.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-field-assignment-type.yz > "$STAGE_DIR/invalid-shape-field-assignment-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted an incompatible value for a shape field." >&2
    exit 1
fi
grep -F 'shape field assignment value has the wrong type' "$STAGE_DIR/invalid-shape-field-assignment-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-field-assignment-immutable.yz > "$STAGE_DIR/invalid-shape-field-assignment-immutable.log" 2>&1; then
    printf '%s\n' "Compiler accepted a shape field update through an immutable value." >&2
    exit 1
fi
grep -F 'shape fields can only be updated on a var declaration' "$STAGE_DIR/invalid-shape-field-assignment-immutable.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-recursive-shape-layout.yz > "$STAGE_DIR/invalid-recursive-shape-layout.log" 2>&1; then
    printf '%s\n' "Compiler accepted a recursive by-value shape layout." >&2
    exit 1
fi
grep -F 'recursive by-value shape fields create an infinite layout' "$STAGE_DIR/invalid-recursive-shape-layout.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-validation-field.yz > "$STAGE_DIR/invalid-shape-validation-field.log" 2>&1; then
    printf '%s\n' "Compiler accepted a validation for an unknown shape field." >&2
    exit 1
fi
grep -F 'validation refers to unknown field' "$STAGE_DIR/invalid-shape-validation-field.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-validation-type.yz > "$STAGE_DIR/invalid-shape-validation-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted a numeric validator for a Boolean field." >&2
    exit 1
fi
grep -F 'min and max require a numeric JSON field' "$STAGE_DIR/invalid-shape-validation-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-validation-email-type.yz > "$STAGE_DIR/invalid-shape-validation-email-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted email validation for a numeric field." >&2
    exit 1
fi
grep -F 'email validation requires a Text field' "$STAGE_DIR/invalid-shape-validation-email-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-validation-integer-type.yz > "$STAGE_DIR/invalid-shape-validation-integer-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted integer validation for a Text field." >&2
    exit 1
fi
grep -F 'integer validation requires a numeric JSON field' "$STAGE_DIR/invalid-shape-validation-integer-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-validation-pattern-type.yz > "$STAGE_DIR/invalid-shape-validation-pattern-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted pattern validation for a non-Text field." >&2
    exit 1
fi
grep -F 'pattern validation requires a Text field' "$STAGE_DIR/invalid-shape-validation-pattern-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-validation-pattern-syntax.yz > "$STAGE_DIR/invalid-shape-validation-pattern-syntax.log" 2>&1; then
    printf '%s\n' "Compiler accepted an unsupported regular-expression pattern." >&2
    exit 1
fi
grep -F 'invalid bounded regular-expression pattern' "$STAGE_DIR/invalid-shape-validation-pattern-syntax.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-validation-duplicate.yz > "$STAGE_DIR/invalid-shape-validation-duplicate.log" 2>&1; then
    printf '%s\n' "Compiler accepted duplicate validators for a shape field." >&2
    exit 1
fi
grep -F 'duplicate' "$STAGE_DIR/invalid-shape-validation-duplicate.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-validation-list-type.yz > "$STAGE_DIR/invalid-shape-validation-list-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted a list validator for a Text field." >&2
    exit 1
fi
grep -F 'min_items and max_items require a TextList or a supported List field' "$STAGE_DIR/invalid-shape-validation-list-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-validation-list-bound.yz > "$STAGE_DIR/invalid-shape-validation-list-bound.log" 2>&1; then
    printf '%s\n' "Compiler accepted a TextList limit above its runtime maximum." >&2
    exit 1
fi
grep -F 'list item limits must be integers from 0 to 64' "$STAGE_DIR/invalid-shape-validation-list-bound.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-validation-list-order.yz > "$STAGE_DIR/invalid-shape-validation-list-order.log" 2>&1; then
    printf '%s\n' "Compiler accepted min_items greater than max_items." >&2
    exit 1
fi
grep -F 'min_items cannot exceed max_items' "$STAGE_DIR/invalid-shape-validation-list-order.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-shape-reserved-name.yz > "$STAGE_DIR/invalid-shape-reserved-name.log" 2>&1; then
    printf '%s\n' "Compiler accepted a shape that shadows a built-in type." >&2
    exit 1
fi
grep -F 'shape name conflicts with a built-in type' "$STAGE_DIR/invalid-shape-reserved-name.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" run test-fixtures/invalid-secure-random-length.yz > "$STAGE_DIR/invalid-secure-random-length.log" 2>&1; then
    printf '%s\n' "Runtime accepted a negative secure_random_bytes length." >&2
    exit 1
fi
grep -F 'secure_random_bytes length must be between 0 and 64 MiB' "$STAGE_DIR/invalid-secure-random-length.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-match-non-exhaustive.yz > "$STAGE_DIR/invalid-match-non-exhaustive.log" 2>&1; then
    printf '%s\n' "Compiler accepted a non-exhaustive Option match." >&2
    exit 1
fi
grep -F 'match must cover every case exactly once' "$STAGE_DIR/invalid-match-non-exhaustive.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-match-duplicate-arm.yz > "$STAGE_DIR/invalid-match-duplicate-arm.log" 2>&1; then
    printf '%s\n' "Compiler accepted a duplicate Result match arm." >&2
    exit 1
fi
grep -F 'duplicate match arm' "$STAGE_DIR/invalid-match-duplicate-arm.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-variant-match-non-exhaustive.yz > "$STAGE_DIR/invalid-variant-match-non-exhaustive.log" 2>&1; then
    printf '%s\n' "Compiler accepted a non-exhaustive user-defined variant match." >&2
    exit 1
fi
grep -F 'match must cover every case exactly once' "$STAGE_DIR/invalid-variant-match-non-exhaustive.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-numeric-match-non-exhaustive.yz > "$STAGE_DIR/invalid-numeric-match-non-exhaustive.log" 2>&1; then
    printf '%s\n' "Compiler accepted a numeric return match without an else arm." >&2
    exit 1
fi
grep -F 'match must cover every case exactly once' "$STAGE_DIR/invalid-numeric-match-non-exhaustive.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-numeric-match-set-immutable.yz > "$STAGE_DIR/invalid-numeric-match-set-immutable.log" 2>&1; then
    printf '%s\n' "Compiler accepted a guarded match assignment to an immutable variable." >&2
    exit 1
fi
grep -F 'guarded match assignment requires a var declaration' "$STAGE_DIR/invalid-numeric-match-set-immutable.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-numeric-match-set-type.yz > "$STAGE_DIR/invalid-numeric-match-set-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted a guarded match arm with the wrong assignment type." >&2
    exit 1
fi
grep -F 'numeric match arm result has the wrong destination type' "$STAGE_DIR/invalid-numeric-match-set-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-value-match-non-exhaustive.yz > "$STAGE_DIR/invalid-value-match-non-exhaustive.log" 2>&1; then
    printf '%s\n' "Compiler accepted a non-exhaustive value match." >&2
    exit 1
fi
grep -F 'match must cover every case exactly once' "$STAGE_DIR/invalid-value-match-non-exhaustive.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-value-match-result-type.yz > "$STAGE_DIR/invalid-value-match-result-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted a value match arm with the wrong result type." >&2
    exit 1
fi
grep -F 'match value arm result has the wrong destination type' "$STAGE_DIR/invalid-value-match-result-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-match-declaration-incomplete.yz > "$STAGE_DIR/invalid-match-declaration-incomplete.log" 2>&1; then
    printf '%s\n' "Compiler accepted an incomplete match in a let initializer." >&2
    exit 1
fi
grep -F 'match must cover every case exactly once' "$STAGE_DIR/invalid-match-declaration-incomplete.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-match-declaration-result-type.yz > "$STAGE_DIR/invalid-match-declaration-result-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted a match initializer with an incompatible result type." >&2
    exit 1
fi
grep -F 'match value arm result has the wrong destination type' "$STAGE_DIR/invalid-match-declaration-result-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-value-match-duplicate.yz > "$STAGE_DIR/invalid-value-match-duplicate.log" 2>&1; then
    printf '%s\n' "Compiler accepted a duplicate value match arm." >&2
    exit 1
fi
grep -F 'duplicate match arm' "$STAGE_DIR/invalid-value-match-duplicate.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-variant-match-duplicate.yz > "$STAGE_DIR/invalid-variant-match-duplicate.log" 2>&1; then
    printf '%s\n' "Compiler accepted a duplicate user-defined variant match arm." >&2
    exit 1
fi
grep -F 'duplicate match arm' "$STAGE_DIR/invalid-variant-match-duplicate.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-variant-constructor-arity.yz > "$STAGE_DIR/invalid-variant-constructor-arity.log" 2>&1; then
    printf '%s\n' "Compiler accepted a variant constructor with the wrong payload arity." >&2
    exit 1
fi
grep -F 'variant constructor called with the wrong number of payload fields' "$STAGE_DIR/invalid-variant-constructor-arity.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-variant-constructor-type.yz > "$STAGE_DIR/invalid-variant-constructor-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted a variant constructor with an incompatible payload type." >&2
    exit 1
fi
grep -F 'variant constructor payload type mismatch' "$STAGE_DIR/invalid-variant-constructor-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-variant-unknown-case.yz > "$STAGE_DIR/invalid-variant-unknown-case.log" 2>&1; then
    printf '%s\n' "Compiler accepted an unknown variant case." >&2
    exit 1
fi
grep -F "unknown variant constructor 'Fault::Unexpected'" "$STAGE_DIR/invalid-variant-unknown-case.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-variant-match-unknown-case.yz > "$STAGE_DIR/invalid-variant-match-unknown-case.log" 2>&1; then
    printf '%s\n' "Compiler accepted an unknown user-defined variant match case." >&2
    exit 1
fi
grep -F 'unknown variant match case' "$STAGE_DIR/invalid-variant-match-unknown-case.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-result-propagation-error.yz > "$STAGE_DIR/invalid-result-propagation-error.log" 2>&1; then
    printf '%s\n' "Compiler accepted a propagated error with the wrong type." >&2
    exit 1
fi
grep -F "'?' error type must match the enclosing Result error type or have one From[Text] implementation for Number" "$STAGE_DIR/invalid-result-propagation-error.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-from-duplicate.yz > "$STAGE_DIR/invalid-from-duplicate.log" 2>&1; then
    printf '%s\n' "Compiler accepted duplicate From implementations for the same source and target types." >&2
    exit 1
fi
grep -F 'duplicate From[SourceError] implementation for TargetError' "$STAGE_DIR/invalid-from-duplicate.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-result-propagation-outside-function.yz > "$STAGE_DIR/invalid-result-propagation-outside-function.log" 2>&1; then
    printf '%s\n' "Compiler accepted '?' outside a Result-returning function." >&2
    exit 1
fi
grep -F "'?' is only valid in a function returning Result[T, E]" "$STAGE_DIR/invalid-result-propagation-outside-function.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" run test-fixtures/option-unwrapping-panic.yz > "$STAGE_DIR/option-unwrapping-panic.log" 2>&1; then
    printf '%s\n' "Runtime unwrapped none as a concrete payload." >&2
    exit 1
fi
grep -F 'attempted to unwrap none as Number' "$STAGE_DIR/option-unwrapping-panic.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-result-type.yz > "$STAGE_DIR/invalid-result-type.log" 2>&1; then
    printf '%s\n' "Compiler accepted a value with the wrong Result payload type." >&2
    exit 1
fi
grep -F 'does not match expression type' "$STAGE_DIR/invalid-result-type.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" check test-fixtures/invalid-result-untyped.yz > "$STAGE_DIR/invalid-result-untyped.log" 2>&1; then
    printf '%s\n' "Compiler accepted a Result without a concrete error type context." >&2
    exit 1
fi
grep -F 'result_is_ok expects Result[T, E]' "$STAGE_DIR/invalid-result-untyped.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" run test-fixtures/result-unwrapping-panic.yz > "$STAGE_DIR/result-unwrapping-panic.log" 2>&1; then
    printf '%s\n' "Runtime unwrapped an err Result as a success payload." >&2
    exit 1
fi
grep -F "attempted to read Result's ok payload from the other variant" "$STAGE_DIR/result-unwrapping-panic.log" >/dev/null
if "$STAGE_DIR/yaza-stage3" run test-fixtures/result-unwrapping-error-panic.yz > "$STAGE_DIR/result-unwrapping-error-panic.log" 2>&1; then
    printf '%s\n' "Runtime unwrapped an ok Result as an error payload." >&2
    exit 1
fi
grep -F "attempted to read Result's err payload from the other variant" "$STAGE_DIR/result-unwrapping-error-panic.log" >/dev/null
mkdir -p "$STAGE_DIR/audit-json"
printf '%s = %s\n' 'verify_tls' 'false' > "$STAGE_DIR/audit-json/settings.toml"
(
    cd "$STAGE_DIR/audit-json"
    if "$STAGE_DIR/yaza-stage3" audit --security --format json > "$STAGE_DIR/audit-report.json"; then
        printf '%s\n' "Security audit fixture did not report its configured TLS finding." >&2
        exit 1
    fi
    grep -F '"rule_id": "YZA-SEC-003"' "$STAGE_DIR/audit-report.json" >/dev/null
    grep -F '"line": 1' "$STAGE_DIR/audit-report.json" >/dev/null
)
YAZA_CLI="$STAGE_DIR/yaza-stage3" sh tests/audit-sarif.sh
YAZA_STDLIB_DIR="$PROJECT_ROOT" YAZA_CLI="$STAGE_DIR/yaza-stage3" sh tests/check-diagnostics.sh
YAZA_SANITIZE=1 ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 \
    "$STAGE_DIR/yaza-stage3" build compiler/native_cli.yz -o "$STAGE_DIR/yaza-stage3-sanitized"
YAZA_STDLIB_DIR="$PROJECT_ROOT" YAZA_CLI="$STAGE_DIR/yaza-stage3-sanitized" \
    ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 \
    sh tests/check-diagnostics.sh
"$STAGE_DIR/yaza-stage3" run examples/native_compiler_arguments.yz -- bootstrap-smoke
YAZA_CLI="$STAGE_DIR/yaza-stage3" sh tests/structured-logging-smoke.sh
YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" sh tests/api-layer-conformance-smoke.sh
YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" sh tests/defer-conformance.sh
YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" sh tests/pg-transaction-scope-smoke.sh
YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" sh tests/api-defer-smoke.sh
YAZA_SANITIZE=1 ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 \
    YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" sh tests/api-defer-smoke.sh
YAZA_STDLIB_DIR="$PROJECT_ROOT" YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" sh tests/api-response-status-smoke.sh
"$STAGE_DIR/yaza-stage3" build templates/api/src/main.yz -o "$STAGE_DIR/api-template"
YAZA_STDLIB_DIR="$PROJECT_ROOT" YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" DATABASE_URL= \
    sh tests/fixtures/api-complete/tests/http-smoke.sh
YAZA_STDLIB_DIR="$PROJECT_ROOT" YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" \
    sh tests/fixtures/api-complete/tests/generation-smoke.sh
YAZA_STDLIB_DIR="$PROJECT_ROOT" YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" DATABASE_URL= YAZA_TEST_SANITIZE=1 \
    ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 \
    sh tests/fixtures/api-complete/tests/http-smoke.sh
"$STAGE_DIR/yaza-stage3" run examples/option.yz
"$STAGE_DIR/yaza-stage3" run examples/result.yz
"$STAGE_DIR/yaza-stage3" run examples/match.yz
"$STAGE_DIR/yaza-stage3" run examples/result_propagation.yz
"$STAGE_DIR/yaza-stage3" test tests/from_conversion.test.yz
"$STAGE_DIR/yaza-stage3" run examples/secure_random.yz
"$STAGE_DIR/yaza-stage3" test tests
"$STAGE_DIR/yaza-stage3" build tests/pg_local_plaintext_smoke.yz -o "$STAGE_DIR/pg-local-plaintext-smoke"
clang -std=c11 -O2 tests/pg_local_plaintext_fixture.c -o "$STAGE_DIR/pg-local-plaintext-fixture"
"$STAGE_DIR/pg-local-plaintext-fixture" "$STAGE_DIR/pg-local-plaintext-smoke"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/pg_local_plaintext_smoke.yz -o "$STAGE_DIR/pg-local-plaintext-sanitized"
clang -std=c11 -O1 -g -fsanitize=address,undefined -fno-omit-frame-pointer tests/pg_local_plaintext_fixture.c -o "$STAGE_DIR/pg-local-plaintext-fixture-sanitized"
ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 \
    "$STAGE_DIR/pg-local-plaintext-fixture-sanitized" "$STAGE_DIR/pg-local-plaintext-sanitized"
"$STAGE_DIR/yaza-stage3" build tests/pg_api_records_smoke.yz -o "$STAGE_DIR/pg-api-records-smoke"
clang -std=c11 -O2 -Wall -Wextra -Werror tests/pg_api_records_fixture.c -o "$STAGE_DIR/pg-api-records-fixture"
"$STAGE_DIR/pg-api-records-fixture" "$STAGE_DIR/pg-api-records-smoke"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/pg_api_records_smoke.yz -o "$STAGE_DIR/pg-api-records-sanitized"
clang -std=c11 -O1 -g -Wall -Wextra -Werror -fsanitize=address,undefined -fno-omit-frame-pointer \
    tests/pg_api_records_fixture.c -o "$STAGE_DIR/pg-api-records-fixture-sanitized"
ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 \
    "$STAGE_DIR/pg-api-records-fixture-sanitized" "$STAGE_DIR/pg-api-records-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/option.test.yz -o "$STAGE_DIR/option-nested-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/option-nested-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/result.test.yz -o "$STAGE_DIR/result-nested-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/result-nested-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/int32.test.yz -o "$STAGE_DIR/int32-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/int32-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/shape.test.yz -o "$STAGE_DIR/shape-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/shape-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/shapes_module.test.yz -o "$STAGE_DIR/shapes-module-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/shapes-module-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/nested_shapes.test.yz -o "$STAGE_DIR/nested-shapes-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/nested-shapes-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/variants.test.yz -o "$STAGE_DIR/variants-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/variants-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/value_match.test.yz -o "$STAGE_DIR/value-match-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/value-match-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/return_flow.test.yz -o "$STAGE_DIR/return-flow-sanitized"
ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 "$STAGE_DIR/return-flow-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/from_conversion.test.yz -o "$STAGE_DIR/from-conversion-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/from-conversion-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/crypto.test.yz -o "$STAGE_DIR/crypto-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/crypto-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/password_hash.test.yz -o "$STAGE_DIR/password-hash-sanitized"
ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 "$STAGE_DIR/password-hash-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/secret_text.test.yz -o "$STAGE_DIR/secret-text-sanitized"
ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 "$STAGE_DIR/secret-text-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/typed_list.test.yz -o "$STAGE_DIR/typed-list-sanitized"
ASAN_OPTIONS=detect_leaks=0:halt_on_error=1 UBSAN_OPTIONS=halt_on_error=1 "$STAGE_DIR/typed-list-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/pg_scram.test.yz -o "$STAGE_DIR/pg-scram-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/pg-scram-sanitized"
"$STAGE_DIR/yaza-stage3" build --sanitize tests/fsroot.test.yz -o "$STAGE_DIR/fsroot-language-sanitized"
ASAN_OPTIONS=detect_leaks=0 "$STAGE_DIR/fsroot-language-sanitized"
YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" sh tests/fsroot-language-smoke.sh
mkdir -p "$STAGE_DIR/new-smoke"
(
    cd "$STAGE_DIR/new-smoke"
    ln -s "$PROJECT_ROOT/templates" templates
    "$STAGE_DIR/yaza-stage3" new --api yaza-smoke
    test -f yaza-smoke/src/controllers/ProductController.yz
    test -f yaza-smoke/src/services/ProductService.yz
    test -f yaza-smoke/src/repositories/ProductRepository.yz
    test -f yaza-smoke/src/interfaces/IProductService.yz
    test -f yaza-smoke/.env.example
    grep -F 'YAZA_API_TOKEN_SECONDARY=' yaza-smoke/.env.example >/dev/null
    test -f yaza-smoke/.gitignore
    test -f yaza-smoke/migrations/0001_create_api_records.sql
    test -f yaza-smoke/compose.yaml
    test -f yaza-smoke/tests/http-smoke.sh
    test -f yaza-smoke/src/application.yz
    test -f yaza-smoke/tests/generation-smoke.sh
    test ! -e yaza-smoke/src/controllers/GreetingControllerImpl.yz
    grep -F 'name = "yaza-smoke"' yaza-smoke/yaza.toml >/dev/null
    (cd yaza-smoke && "$STAGE_DIR/yaza-stage3" generate)
    test -f yaza-smoke/docs/api/yaza-smoke.postman_collection.json
    grep -F 'route2_query_limit' yaza-smoke/docs/api/yaza-smoke.postman_collection.json >/dev/null
    test -f yaza-smoke/docs/api/openapi.json
    test -f yaza-smoke/docs/api/swagger.json
    (cd yaza-smoke && "$STAGE_DIR/yaza-stage3" generate --openapi)
    test -f yaza-smoke/docs/api/openapi.json
    (cd yaza-smoke && "$STAGE_DIR/yaza-stage3" generate --swagger)
    test -f yaza-smoke/docs/api/swagger.json
    grep -F '"openapi": "3.1.0"' yaza-smoke/docs/api/openapi.json >/dev/null
    "$STAGE_DIR/yaza-stage3" new --minimal-api mini-smoke
    test -f mini-smoke/src/main.yz
    test ! -e mini-smoke/src/controllers
    grep -F 'get "/" => json' mini-smoke/src/main.yz >/dev/null
    (cd mini-smoke && "$STAGE_DIR/yaza-stage3" generate)
    test -f mini-smoke/docs/api/mini-smoke.postman_collection.json
    test -f mini-smoke/docs/api/openapi.json
    test -f mini-smoke/docs/api/swagger.json
    (cd mini-smoke && "$STAGE_DIR/yaza-stage3" build src/main.yz -o "$STAGE_DIR/minimal-api")
)
mkdir -p "$STAGE_DIR/run-smoke/src"
cp "$PROJECT_ROOT/hello.yz" "$STAGE_DIR/run-smoke/src/main.yz"
ln -s "$PROJECT_ROOT/runtime" "$STAGE_DIR/run-smoke/runtime"
(
    cd "$STAGE_DIR/run-smoke"
    "$STAGE_DIR/yaza-stage3" run
)
YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" sh tests/api-route-auth-smoke.sh
YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" sh tests/cli-secret-token-smoke.sh
YAZA_TEST_CLI="$STAGE_DIR/yaza-stage3" sh tests/dotenv-loader-smoke.sh
cp "$STAGE_DIR/yaza-stage3" "$DIST_DIR/yaza"
chmod 755 "$DIST_DIR/yaza"
# Managed macOS environments may attach provenance xattrs that prevent direct
# execution. Strip those attributes and apply an ad-hoc signature to the final
# native binary so the installed artifact remains runnable on this Mac.
xattr -c "$DIST_DIR/yaza"
codesign --force --sign - --timestamp=none "$DIST_DIR/yaza"
"$DIST_DIR/yaza" --version
printf 'Created self-hosted native CLI: %s\n' "$DIST_DIR/yaza"
