diff --git a/.github/workflows/verify.yml b/.github/workflows/verify.yml index ccc2a8763d..6ee9bc7c5b 100644 --- a/.github/workflows/verify.yml +++ b/.github/workflows/verify.yml @@ -304,6 +304,8 @@ jobs: - name: Install dependencies run: uv sync --locked --all-groups --all-extras - name: Compare fixtures, examples, generated seeds and the failure corpus (python vs native-preview) + env: + SQB_DIAG_SCRIPT: ${{ github.workspace }}/scripts/_diag_sql_test_cache.py run: >- make compiler-differential COMPILER_DIFFERENTIAL_ARGS="--stage-captures --require-discovery-coverage @@ -318,6 +320,8 @@ jobs: if-no-files-found: warn retention-days: 30 - name: Compare generated seeds and the failure corpus (python vs shipped native) + env: + SQB_DIAG_SCRIPT: ${{ github.workspace }}/scripts/_diag_sql_test_cache.py run: >- make compiler-differential-shipped COMPILER_DIFFERENTIAL_ARGS="--stage-captures --require-discovery-coverage diff --git a/scripts/_diag_sql_test_cache.py b/scripts/_diag_sql_test_cache.py new file mode 100644 index 0000000000..9df9ae14cf --- /dev/null +++ b/scripts/_diag_sql_test_cache.py @@ -0,0 +1,65 @@ +"""Throwaway CI diagnostic: report why a warm SQL-test artifact cache lookup missed.""" + +import json +import sys +from pathlib import Path + +import sqlbuild.cli.commands._helpers.compile.sql_test_artifact_cache as cache +import sqlbuild.cli.commands._helpers.compile.target_writer as tw + +_STATE = Path("target") / "diag-identities.json" +_previous = json.loads(_STATE.read_text()) if _STATE.is_file() else {} +_current = {} +_orig_identity = tw.sql_test_artifact_identity +_orig_match = tw.artifact_matches_cache_record + + +def _identity(**kw): + test = kw["test"] + context = kw["context"] + _current[test.name] = { + "common": context.common_identity, + "test": cache._payload_digest(cache._test_payload(test=test)), + "chain": [[n, context.model_identities.get(n)] for n in kw["model_chain_names"]], + } + return _orig_identity(**kw) + + +def _match(**kw): + found = _orig_match(**kw) + if found is None: + record = kw["record"] + path = kw["tests_root"] / record.relative_path + stat = path.stat() if path.exists() else None + name = next((n for n in _current if n in str(record.relative_path)), None) + changed = { + key: [_previous.get(name, {}).get(key), _current.get(name, {}).get(key)] + for key in ("common", "test", "chain") + if _previous.get(name, {}).get(key) != _current.get(name, {}).get(key) + } + print( + "DIAG miss " + + json.dumps( + { + "rel": str(record.relative_path), + "id_eq": record.identity == kw["identity"], + "size": [record.size, stat and stat.st_size], + "mtime": [record.mtime_ns, stat and stat.st_mtime_ns], + "changed": changed, + } + ), + file=sys.stderr, + ) + return found + + +tw.sql_test_artifact_identity = _identity +tw.artifact_matches_cache_record = _match +from sqlbuild.cli.entry.main.entry import main # noqa: E402 + +try: + code = main() +finally: + if _current and Path("target").is_dir(): + _STATE.write_text(json.dumps({**_previous, **_current})) +sys.exit(code) diff --git a/scripts/compiler_differential/constants.py b/scripts/compiler_differential/constants.py index 008e546c06..71f84dde29 100644 --- a/scripts/compiler_differential/constants.py +++ b/scripts/compiler_differential/constants.py @@ -13,7 +13,7 @@ RECORDS_DIRECTORY: str = "records" ENGINE_NAMES: tuple[str, ...] = ("python", "native", "native-preview") DEFAULT_ENGINES: tuple[str, str] = ("python", "native-preview") -SQB_ENTRY: str = "import sys; from sqlbuild.cli.entry.main.entry import main; sys.exit(main())" +SQB_ENTRY: str = "import runpy; runpy.run_path(__import__('os').environ['SQB_DIAG_SCRIPT'], run_name='__main__')" EXCLUDED_ENVIRONMENT_KEYS: frozenset[str] = frozenset( {"VIRTUAL_ENV", ENGINE_ENV_VAR, STAGE_CAPTURE_ENV_VAR, ANALYSIS_RECORD_ENV_VAR} )