mirror of
https://github.com/ruvnet/RuView
synced 2026-07-25 17:51:48 +00:00
2d2b16a458
verify.py's HASH_QUANTIZATION_DECIMALS is now overridable via PROOF_HASH_DECIMALS. Finding: the determinism divergence is NOT Windows-vs-Linux — Windows and a second Linux box (ruvultra, same numpy/scipy) produce identical hashes at every precision, including ca58956c at 6 decimals. Only the GitHub Azure CI runner diverges (667eb054), i.e. a CPU-microarchitecture pocketfft/BLAS reordering (the #560 Skylake-vs-Cascade-Lake class). Temporary diagnostic sweep step prints the CI runner's hash at decimals 6..2 so we can pick the coarsest precision that collapses the microarch divergence to the common hash. Both the sweep step and the PROOF_HASH_DECIMALS plumbing are removed/finalized in the follow-up. Co-Authored-By: claude-flow <ruv@ruv.net>
139 lines
5.2 KiB
YAML
139 lines
5.2 KiB
YAML
name: Verify Pipeline Determinism
|
|
|
|
on:
|
|
push:
|
|
branches: [ main, master, 'claude/**' ]
|
|
paths:
|
|
- 'archive/v1/src/core/**'
|
|
- 'archive/v1/src/hardware/**'
|
|
- 'archive/v1/data/proof/**'
|
|
- 'archive/v1/requirements-lock.txt'
|
|
- '.github/workflows/verify-pipeline.yml'
|
|
pull_request:
|
|
branches: [ main, master ]
|
|
paths:
|
|
- 'archive/v1/src/core/**'
|
|
- 'archive/v1/src/hardware/**'
|
|
- 'archive/v1/data/proof/**'
|
|
- 'archive/v1/requirements-lock.txt'
|
|
- '.github/workflows/verify-pipeline.yml'
|
|
workflow_dispatch:
|
|
|
|
jobs:
|
|
verify-determinism:
|
|
name: Verify Pipeline Determinism
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
matrix:
|
|
python-version: ['3.11']
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Set up Python ${{ matrix.python-version }}
|
|
uses: actions/setup-python@v6
|
|
with:
|
|
python-version: ${{ matrix.python-version }}
|
|
|
|
- name: Install pinned dependencies
|
|
run: |
|
|
python -m pip install --upgrade pip
|
|
pip install -r archive/v1/requirements-lock.txt
|
|
|
|
- name: Verify reference signal is reproducible
|
|
run: |
|
|
echo "=== Regenerating reference signal ==="
|
|
python archive/v1/data/proof/generate_reference_signal.py
|
|
echo ""
|
|
echo "=== Checking data file matches committed version ==="
|
|
# The regenerated file should be identical to the committed one
|
|
# (We compare the metadata file since data file is large)
|
|
python -c "
|
|
import json, hashlib
|
|
with open('archive/v1/data/proof/sample_csi_meta.json') as f:
|
|
meta = json.load(f)
|
|
assert meta['is_synthetic'] == True, 'Metadata must mark signal as synthetic'
|
|
assert meta['numpy_seed'] == 42, 'Seed must be 42'
|
|
print('Reference signal metadata validated.')
|
|
"
|
|
|
|
- name: Quantization sweep (diagnostic — cross-microarch precision)
|
|
working-directory: archive/v1
|
|
env:
|
|
OMP_NUM_THREADS: "1"
|
|
OPENBLAS_NUM_THREADS: "1"
|
|
MKL_NUM_THREADS: "1"
|
|
VECLIB_MAXIMUM_THREADS: "1"
|
|
NUMEXPR_NUM_THREADS: "1"
|
|
run: |
|
|
for d in 6 5 4 3 2; do
|
|
h=$(PROOF_HASH_DECIMALS=$d python data/proof/verify.py --generate-hash 2>/dev/null | grep -i 'Computed:' | sed 's/.*Computed:[[:space:]]*//')
|
|
echo "SWEEP d=$d $h"
|
|
done
|
|
|
|
- name: Run pipeline verification
|
|
working-directory: archive/v1
|
|
env:
|
|
# Pin thread count for scipy.fft / BLAS — multi-threaded reduction
|
|
# order is otherwise non-deterministic across CI runs (issue #560
|
|
# follow-up: 9- and 6-decimal quantization were not enough because
|
|
# the divergence is from threading order, not SIMD reordering).
|
|
# Single-threaded keeps the proof reproducible at a ~2-3x slowdown.
|
|
OMP_NUM_THREADS: "1"
|
|
OPENBLAS_NUM_THREADS: "1"
|
|
MKL_NUM_THREADS: "1"
|
|
VECLIB_MAXIMUM_THREADS: "1"
|
|
NUMEXPR_NUM_THREADS: "1"
|
|
run: |
|
|
echo "=== Running pipeline verification ==="
|
|
python data/proof/verify.py
|
|
echo ""
|
|
echo "Pipeline verification PASSED."
|
|
|
|
- name: Run verification twice to confirm determinism
|
|
working-directory: archive/v1
|
|
env:
|
|
OMP_NUM_THREADS: "1"
|
|
OPENBLAS_NUM_THREADS: "1"
|
|
MKL_NUM_THREADS: "1"
|
|
VECLIB_MAXIMUM_THREADS: "1"
|
|
NUMEXPR_NUM_THREADS: "1"
|
|
run: |
|
|
echo "=== Second run for determinism confirmation ==="
|
|
python data/proof/verify.py
|
|
echo "Determinism confirmed across multiple runs."
|
|
|
|
- name: Check for unseeded np.random in production code
|
|
run: |
|
|
echo "=== Scanning for unseeded np.random usage in production code ==="
|
|
# Search for np.random calls without a seed in production code
|
|
# Exclude test files, proof data generators, and known parser placeholders
|
|
VIOLATIONS=$(grep -rn "np\.random\." archive/v1/src/ \
|
|
--include="*.py" \
|
|
--exclude-dir="__pycache__" \
|
|
| grep -v "np\.random\.RandomState" \
|
|
| grep -v "np\.random\.seed" \
|
|
| grep -v "np\.random\.default_rng" \
|
|
| grep -v "# placeholder" \
|
|
| grep -v "# mock" \
|
|
| grep -v "# test" \
|
|
|| true)
|
|
|
|
if [ -n "$VIOLATIONS" ]; then
|
|
echo ""
|
|
echo "WARNING: Found potential unseeded np.random usage in production code:"
|
|
echo "$VIOLATIONS"
|
|
echo ""
|
|
echo "Each np.random call should either:"
|
|
echo " 1. Use np.random.RandomState(seed) or np.random.default_rng(seed)"
|
|
echo " 2. Be in a test/mock context (add '# placeholder' comment)"
|
|
echo ""
|
|
# Note: This is a warning, not a failure, because some existing
|
|
# placeholder code in parsers uses np.random for mock data.
|
|
# Once hardware integration is complete, these should be removed.
|
|
echo "WARNING: Review the above usages. Existing parser placeholders are expected."
|
|
else
|
|
echo "No unseeded np.random usage found in production code."
|
|
fi
|