diff --git a/.github/workflows/fstar-master-build.yml b/.github/workflows/fstar-master-build.yml index 8b844e33c7..44ba1ec508 100644 --- a/.github/workflows/fstar-master-build.yml +++ b/.github/workflows/fstar-master-build.yml @@ -90,6 +90,25 @@ jobs: ln -sf "$GITHUB_WORKSPACE/build/release/z3" /tmp/gh-aw/agent/z3-bin/z3-4.13.3 /tmp/gh-aw/agent/z3-bin/z3 --version + # Scheduled runs receive no workflow_dispatch inputs, so the effective F* options + # come from the hard-wired env defaults above. Resolve them once here, and make sure + # the options that cause F* to emit .smt2 files are always present: without them the + # build and the test suite fail without leaving any query behind to analyse. + - name: Resolve FStar options + run: | + set -euo pipefail + Z3_VERSION="$(sed -E -n 's/^Z3 version ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' /tmp/gh-aw/agent/z3-version.txt | head -1)" + test -n "$Z3_VERSION" || { echo "Error: Failed to extract Z3 version from /tmp/gh-aw/agent/z3-version.txt (expected: 'Z3 version X.Y.Z')"; cat /tmp/gh-aw/agent/z3-version.txt || true; exit 1; } + + OTHERFLAGS="--z3version $Z3_VERSION $FSTAR_OTHERFLAGS" + case " $OTHERFLAGS " in + *" --log_failing_queries "*) ;; + *) OTHERFLAGS="$OTHERFLAGS --log_failing_queries" ;; + esac + + echo "FSTAR_EFFECTIVE_OTHERFLAGS=$OTHERFLAGS" >> "$GITHUB_ENV" + printf '%s\n' "$OTHERFLAGS" | tee /tmp/gh-aw/agent/fstar-otherflags.txt + - name: Build FStar id: build_fstar continue-on-error: true @@ -105,10 +124,7 @@ jobs: eval "$(opam env --switch="$FSTAR_OPAM_SWITCH")" opam install --deps-only . --yes - Z3_VERSION="$(sed -E -n 's/^Z3 version ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' /tmp/gh-aw/agent/z3-version.txt | head -1)" - test -n "$Z3_VERSION" || { echo "Error: Failed to extract Z3 version from /tmp/gh-aw/agent/z3-version.txt (expected: 'Z3 version X.Y.Z')"; cat /tmp/gh-aw/agent/z3-version.txt || true; exit 1; } - - PATH="/tmp/gh-aw/agent/z3-bin:$PATH" OTHERFLAGS="--z3version $Z3_VERSION $FSTAR_OTHERFLAGS" make -j"$(nproc)" -k + PATH="/tmp/gh-aw/agent/z3-bin:$PATH" OTHERFLAGS="$FSTAR_EFFECTIVE_OTHERFLAGS" make -j"$(nproc)" -k 2>&1 | tee /tmp/gh-aw/agent/fstar-build.log test -x /tmp/gh-aw/agent/FStar/out/bin/fstar.exe || { echo "Error: FStar binary not found or not executable at /tmp/gh-aw/agent/FStar/out/bin/fstar.exe"; exit 1; } /tmp/gh-aw/agent/FStar/out/bin/fstar.exe --version | tee /tmp/gh-aw/agent/fstar-version.txt @@ -121,58 +137,129 @@ jobs: cd /tmp/gh-aw/agent/FStar eval "$(opam env --switch="$FSTAR_OPAM_SWITCH")" - Z3_VERSION="$(sed -E -n 's/^Z3 version ([0-9]+\.[0-9]+\.[0-9]+).*/\1/p' /tmp/gh-aw/agent/z3-version.txt | head -1)" - test -n "$Z3_VERSION" || { echo "Error: Failed to extract Z3 version from /tmp/gh-aw/agent/z3-version.txt (expected: 'Z3 version X.Y.Z')"; exit 1; } + PATH="/tmp/gh-aw/agent/z3-bin:$PATH" OTHERFLAGS="$FSTAR_EFFECTIVE_OTHERFLAGS" make -j"$(nproc)" -k test 2>&1 | tee /tmp/gh-aw/agent/fstar-test.log - PATH="/tmp/gh-aw/agent/z3-bin:$PATH" OTHERFLAGS="--z3version $Z3_VERSION $FSTAR_OTHERFLAGS" make -j"$(nproc)" -k test 2>&1 | tee /tmp/gh-aw/agent/fstar-test.log - - - name: Collect generated SMT2 files - id: collect_smt2 + # Collect everything needed to triage a failure offline: the logs, the failing SMT2 + # queries, and - for every expected-output test - the produced output, the .expected + # oracle and a unified diff between them. Test suite failures otherwise leave nothing + # behind, since only .smt2 files used to be uploaded. + - name: Collect FStar failure artifacts + id: collect_artifacts if: always() run: | set -euo pipefail - rm -rf /tmp/gh-aw/agent/smt2-artifact - mkdir -p /tmp/gh-aw/agent/smt2-artifact - SMT2_PREVIEW=/tmp/gh-aw/agent/smt2-preview.md - SMT2_HEAD_LINES=1000 - > "$SMT2_PREVIEW" + FSTAR_DIR=/tmp/gh-aw/agent/FStar + OUT=/tmp/gh-aw/agent/fstar-artifact + rm -rf "$OUT" + mkdir -p "$OUT/logs" "$OUT/smt2" "$OUT/test-output" - if [ -d /tmp/gh-aw/agent/FStar ]; then - mapfile -t SMT2_FILES < <(find /tmp/gh-aw/agent/FStar -type f -name '*.smt2' | sort) - else - SMT2_FILES=() - fi - - if [ "${#SMT2_FILES[@]}" -eq 0 ]; then - echo "has_files=false" >> "$GITHUB_OUTPUT" - exit 0 - fi - - for file in "${SMT2_FILES[@]}"; do - rel="${file#/tmp/gh-aw/agent/FStar/}" - target="/tmp/gh-aw/agent/smt2-artifact/${rel}" - mkdir -p "$(dirname "$target")" - cp "$file" "$target" - { - printf '#### `%s`\n\n' "$rel" - printf '```smt2\n' - head -n "$SMT2_HEAD_LINES" "$file" - printf '\n```\n\n' - } >> "$SMT2_PREVIEW" + for name in z3-version.txt z3-runtime-check.txt fstar-version.txt fstar-commit.txt fstar-otherflags.txt fstar-build.log fstar-test.log; do + if [ -f "/tmp/gh-aw/agent/$name" ]; then + cp "/tmp/gh-aw/agent/$name" "$OUT/logs/$name" + fi done - echo "has_files=true" >> "$GITHUB_OUTPUT" + SMT2_PREVIEW=/tmp/gh-aw/agent/smt2-preview.md + SMT2_HEAD_LINES=1000 + : > "$SMT2_PREVIEW" - - name: Upload generated SMT2 artifact - id: upload_smt2 - if: always() && steps.collect_smt2.outputs.has_files == 'true' + MISMATCH_LIST="$OUT/logs/mismatched-outputs.txt" + : > "$MISMATCH_LIST" + SMT2_COUNT=0 + MISMATCH_COUNT=0 + + if [ -d "$FSTAR_DIR" ]; then + while IFS= read -r file; do + rel="${file#"$FSTAR_DIR"/}" + target="$OUT/smt2/${rel}" + mkdir -p "$(dirname "$target")" + cp "$file" "$target" + { + printf '#### `%s`\n\n' "$rel" + printf '```smt2\n' + head -n "$SMT2_HEAD_LINES" "$file" + printf '\n```\n\n' + } >> "$SMT2_PREVIEW" + SMT2_COUNT=$((SMT2_COUNT + 1)) + done < <(find "$FSTAR_DIR" -type f -name '*.smt2' | sort) + + # An expected-output test compares