gazeaudit 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. gazeaudit-0.1.0/.github/workflows/distribution.yml +84 -0
  2. gazeaudit-0.1.0/.github/workflows/interop.yml +45 -0
  3. gazeaudit-0.1.0/.github/workflows/korthals-scientific-execution.yml +160 -0
  4. gazeaudit-0.1.0/.github/workflows/korthals-source-freeze.yml +139 -0
  5. gazeaudit-0.1.0/.github/workflows/pedrotti-scientific-execution.yml +159 -0
  6. gazeaudit-0.1.0/.github/workflows/pedrotti-source-freeze.yml +150 -0
  7. gazeaudit-0.1.0/.github/workflows/release-candidate.yml +104 -0
  8. gazeaudit-0.1.0/.github/workflows/tests.yml +56 -0
  9. gazeaudit-0.1.0/.gitignore +13 -0
  10. gazeaudit-0.1.0/CHANGELOG.md +58 -0
  11. gazeaudit-0.1.0/CITATION.cff +19 -0
  12. gazeaudit-0.1.0/LICENSE +21 -0
  13. gazeaudit-0.1.0/PKG-INFO +309 -0
  14. gazeaudit-0.1.0/README.md +246 -0
  15. gazeaudit-0.1.0/docs/CITATION_AND_REUSE.md +102 -0
  16. gazeaudit-0.1.0/docs/PUBLICATION_SUMMARY.md +105 -0
  17. gazeaudit-0.1.0/docs/RELEASE.md +107 -0
  18. gazeaudit-0.1.0/docs/REPRODUCIBILITY_INDEX.json +116 -0
  19. gazeaudit-0.1.0/docs/SCIENTIFIC_METHODS.md +153 -0
  20. gazeaudit-0.1.0/docs/VALIDATION_MATRIX.md +124 -0
  21. gazeaudit-0.1.0/docs/case_studies/GAZEBASE_MULTIDETECTOR_PROTOCOL.md +260 -0
  22. gazeaudit-0.1.0/docs/case_studies/gazebase_multidetector_protocol.json +127 -0
  23. gazeaudit-0.1.0/docs/case_studies/gazebase_real_data_execution.md +93 -0
  24. gazeaudit-0.1.0/docs/protocols/PEDROTTI2023_SAMPLING_MISSINGNESS_V1.md +86 -0
  25. gazeaudit-0.1.0/docs/protocols/korthals2026_target_tracking_aoi_v1.json +116 -0
  26. gazeaudit-0.1.0/docs/protocols/korthals2026_target_tracking_aoi_v2.json +125 -0
  27. gazeaudit-0.1.0/docs/protocols/pedrotti2023_sampling_missingness_v1.json +144 -0
  28. gazeaudit-0.1.0/docs/results/korthals2026_target_tracking_aoi_v2.json +129 -0
  29. gazeaudit-0.1.0/docs/results/korthals2026_target_tracking_aoi_v2.md +91 -0
  30. gazeaudit-0.1.0/docs/results/pedrotti_sampling_missingness_v1.md +141 -0
  31. gazeaudit-0.1.0/docs/validation/korthals_memory_bounded_intake_v2.md +58 -0
  32. gazeaudit-0.1.0/docs/validation/korthals_osf_download_resilience_v2.md +82 -0
  33. gazeaudit-0.1.0/docs/validation/korthals_scientific_execution_v2.md +76 -0
  34. gazeaudit-0.1.0/docs/validation/korthals_source_lock_v2.md +77 -0
  35. gazeaudit-0.1.0/docs/validation/korthals_tutorial_scope_v1.md +11 -0
  36. gazeaudit-0.1.0/docs/validation/korthals_zero_finite_cell_amendment_v2.md +36 -0
  37. gazeaudit-0.1.0/docs/validation/pedrotti_source_freeze_v1.md +149 -0
  38. gazeaudit-0.1.0/pyproject.toml +95 -0
  39. gazeaudit-0.1.0/src/gazeaudit/__init__.py +309 -0
  40. gazeaudit-0.1.0/src/gazeaudit/adapters.py +84 -0
  41. gazeaudit-0.1.0/src/gazeaudit/aoi.py +69 -0
  42. gazeaudit-0.1.0/src/gazeaudit/aoi_artifacts.py +295 -0
  43. gazeaudit-0.1.0/src/gazeaudit/aoi_audit.py +154 -0
  44. gazeaudit-0.1.0/src/gazeaudit/aoi_propagation.py +267 -0
  45. gazeaudit-0.1.0/src/gazeaudit/aoi_protocol.py +165 -0
  46. gazeaudit-0.1.0/src/gazeaudit/benchmark.py +154 -0
  47. gazeaudit-0.1.0/src/gazeaudit/bids_adapter.py +386 -0
  48. gazeaudit-0.1.0/src/gazeaudit/conclusion.py +448 -0
  49. gazeaudit-0.1.0/src/gazeaudit/data/__init__.py +1 -0
  50. gazeaudit-0.1.0/src/gazeaudit/data/gazebase_multidetector_protocol.json +127 -0
  51. gazeaudit-0.1.0/src/gazeaudit/data/korthals2026_source_lock_v2.json +89 -0
  52. gazeaudit-0.1.0/src/gazeaudit/data/korthals2026_target_tracking_aoi_v1.json +116 -0
  53. gazeaudit-0.1.0/src/gazeaudit/data/korthals2026_target_tracking_aoi_v2.json +125 -0
  54. gazeaudit-0.1.0/src/gazeaudit/data/pedrotti2023_sampling_missingness_v1.json +144 -0
  55. gazeaudit-0.1.0/src/gazeaudit/data/pedrotti2023_source_lock_v1.json +95 -0
  56. gazeaudit-0.1.0/src/gazeaudit/endpoints.py +47 -0
  57. gazeaudit-0.1.0/src/gazeaudit/gazebase_artifacts.py +281 -0
  58. gazeaudit-0.1.0/src/gazeaudit/gazebase_cli.py +112 -0
  59. gazeaudit-0.1.0/src/gazeaudit/gazebase_execution.py +571 -0
  60. gazeaudit-0.1.0/src/gazeaudit/gazebase_failure.py +164 -0
  61. gazeaudit-0.1.0/src/gazeaudit/gazebase_partitioned.py +458 -0
  62. gazeaudit-0.1.0/src/gazeaudit/gazebase_pymovements.py +164 -0
  63. gazeaudit-0.1.0/src/gazeaudit/korthals_execution.py +882 -0
  64. gazeaudit-0.1.0/src/gazeaudit/korthals_execution_archive_v2.py +122 -0
  65. gazeaudit-0.1.0/src/gazeaudit/korthals_execution_v2.py +510 -0
  66. gazeaudit-0.1.0/src/gazeaudit/korthals_execution_v2_cli.py +86 -0
  67. gazeaudit-0.1.0/src/gazeaudit/korthals_freeze.py +318 -0
  68. gazeaudit-0.1.0/src/gazeaudit/korthals_freeze_cli.py +86 -0
  69. gazeaudit-0.1.0/src/gazeaudit/korthals_freeze_v2.py +263 -0
  70. gazeaudit-0.1.0/src/gazeaudit/korthals_freeze_v2_cli.py +84 -0
  71. gazeaudit-0.1.0/src/gazeaudit/korthals_osf.py +248 -0
  72. gazeaudit-0.1.0/src/gazeaudit/korthals_reveal_v2_cli.py +28 -0
  73. gazeaudit-0.1.0/src/gazeaudit/korthals_source.py +697 -0
  74. gazeaudit-0.1.0/src/gazeaudit/korthals_source_cli.py +64 -0
  75. gazeaudit-0.1.0/src/gazeaudit/korthals_source_lock.py +165 -0
  76. gazeaudit-0.1.0/src/gazeaudit/korthals_source_v2_cli.py +57 -0
  77. gazeaudit-0.1.0/src/gazeaudit/korthals_streaming.py +277 -0
  78. gazeaudit-0.1.0/src/gazeaudit/korthals_v2.py +667 -0
  79. gazeaudit-0.1.0/src/gazeaudit/missingness.py +161 -0
  80. gazeaudit-0.1.0/src/gazeaudit/multiverse.py +104 -0
  81. gazeaudit-0.1.0/src/gazeaudit/pedrotti_execution.py +1234 -0
  82. gazeaudit-0.1.0/src/gazeaudit/pedrotti_execution_cli.py +54 -0
  83. gazeaudit-0.1.0/src/gazeaudit/pedrotti_fetch.py +410 -0
  84. gazeaudit-0.1.0/src/gazeaudit/pedrotti_freeze.py +336 -0
  85. gazeaudit-0.1.0/src/gazeaudit/pedrotti_freeze_cli.py +87 -0
  86. gazeaudit-0.1.0/src/gazeaudit/pedrotti_prefetch.py +186 -0
  87. gazeaudit-0.1.0/src/gazeaudit/pedrotti_reveal_cli.py +36 -0
  88. gazeaudit-0.1.0/src/gazeaudit/pedrotti_source.py +587 -0
  89. gazeaudit-0.1.0/src/gazeaudit/pedrotti_source_cli.py +52 -0
  90. gazeaudit-0.1.0/src/gazeaudit/pedrotti_source_lock.py +213 -0
  91. gazeaudit-0.1.0/src/gazeaudit/peyes_adapter.py +223 -0
  92. gazeaudit-0.1.0/src/gazeaudit/provenance.py +129 -0
  93. gazeaudit-0.1.0/src/gazeaudit/publication.py +473 -0
  94. gazeaudit-0.1.0/src/gazeaudit/pymovements_adapter.py +285 -0
  95. gazeaudit-0.1.0/src/gazeaudit/report.py +108 -0
  96. gazeaudit-0.1.0/src/gazeaudit/robustness.py +184 -0
  97. gazeaudit-0.1.0/src/gazeaudit/sampling.py +100 -0
  98. gazeaudit-0.1.0/src/gazeaudit/scientific_benchmark.py +180 -0
  99. gazeaudit-0.1.0/src/gazeaudit/sensitivity.py +130 -0
  100. gazeaudit-0.1.0/src/gazeaudit/sensitivity_protocol.py +242 -0
  101. gazeaudit-0.1.0/src/gazeaudit/study.py +109 -0
  102. gazeaudit-0.1.0/src/gazeaudit/task_contrast.py +452 -0
  103. gazeaudit-0.1.0/src/gazeaudit/uncertainty.py +404 -0
  104. gazeaudit-0.1.0/tests/test_aoi_propagation.py +212 -0
  105. gazeaudit-0.1.0/tests/test_aoi_protocol_artifacts.py +249 -0
  106. gazeaudit-0.1.0/tests/test_aoi_uncertainty.py +297 -0
  107. gazeaudit-0.1.0/tests/test_bids_adapter.py +306 -0
  108. gazeaudit-0.1.0/tests/test_conclusion_recovery.py +223 -0
  109. gazeaudit-0.1.0/tests/test_core.py +128 -0
  110. gazeaudit-0.1.0/tests/test_gazebase_artifacts.py +212 -0
  111. gazeaudit-0.1.0/tests/test_gazebase_execution.py +400 -0
  112. gazeaudit-0.1.0/tests/test_gazebase_failure.py +219 -0
  113. gazeaudit-0.1.0/tests/test_gazebase_partitioned.py +253 -0
  114. gazeaudit-0.1.0/tests/test_gazebase_protocol.py +89 -0
  115. gazeaudit-0.1.0/tests/test_gazebase_pymovements_contract.py +150 -0
  116. gazeaudit-0.1.0/tests/test_grouped_uncertainty.py +220 -0
  117. gazeaudit-0.1.0/tests/test_interoperability.py +325 -0
  118. gazeaudit-0.1.0/tests/test_korthals_aoi_protocol.py +94 -0
  119. gazeaudit-0.1.0/tests/test_korthals_execution.py +252 -0
  120. gazeaudit-0.1.0/tests/test_korthals_execution_v2.py +177 -0
  121. gazeaudit-0.1.0/tests/test_korthals_freeze.py +223 -0
  122. gazeaudit-0.1.0/tests/test_korthals_osf.py +171 -0
  123. gazeaudit-0.1.0/tests/test_korthals_participant_identity.py +192 -0
  124. gazeaudit-0.1.0/tests/test_korthals_source.py +257 -0
  125. gazeaudit-0.1.0/tests/test_korthals_source_lock.py +105 -0
  126. gazeaudit-0.1.0/tests/test_korthals_streaming.py +258 -0
  127. gazeaudit-0.1.0/tests/test_korthals_tutorial_scope.py +107 -0
  128. gazeaudit-0.1.0/tests/test_korthals_v2.py +271 -0
  129. gazeaudit-0.1.0/tests/test_missingness_provenance.py +147 -0
  130. gazeaudit-0.1.0/tests/test_optional_interop.py +99 -0
  131. gazeaudit-0.1.0/tests/test_pedrotti_execution.py +415 -0
  132. gazeaudit-0.1.0/tests/test_pedrotti_fetch.py +61 -0
  133. gazeaudit-0.1.0/tests/test_pedrotti_fetch_fallback.py +234 -0
  134. gazeaudit-0.1.0/tests/test_pedrotti_prefetch.py +154 -0
  135. gazeaudit-0.1.0/tests/test_pedrotti_scientific_workflow.py +46 -0
  136. gazeaudit-0.1.0/tests/test_pedrotti_source_freeze.py +245 -0
  137. gazeaudit-0.1.0/tests/test_pedrotti_source_gate_runtime.py +258 -0
  138. gazeaudit-0.1.0/tests/test_pedrotti_source_lock.py +140 -0
  139. gazeaudit-0.1.0/tests/test_publication_bundle.py +214 -0
  140. gazeaudit-0.1.0/tests/test_publication_index.py +127 -0
  141. gazeaudit-0.1.0/tests/test_release_gate.py +125 -0
  142. gazeaudit-0.1.0/tests/test_release_metadata.py +60 -0
  143. gazeaudit-0.1.0/tests/test_report_interactions.py +17 -0
  144. gazeaudit-0.1.0/tests/test_scientific_benchmark_sampling.py +179 -0
  145. gazeaudit-0.1.0/tests/test_sensitivity_protocol.py +167 -0
  146. gazeaudit-0.1.0/tests/test_task_contrast.py +285 -0
  147. gazeaudit-0.1.0/tools/release_gate.py +86 -0
  148. gazeaudit-0.1.0/tools/verify_distribution.py +171 -0
@@ -0,0 +1,84 @@
1
+ name: distribution
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches:
7
+ - main
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ build-and-verify:
14
+ runs-on: ubuntu-24.04
15
+ timeout-minutes: 20
16
+ steps:
17
+ - name: Checkout
18
+ uses: actions/checkout@v7
19
+
20
+ - name: Set up Python 3.12.14
21
+ uses: actions/setup-python@v7
22
+ with:
23
+ python-version: '3.12.14'
24
+ cache: pip
25
+
26
+ - name: Install build validators
27
+ shell: bash
28
+ run: |
29
+ set -euo pipefail
30
+ python -m pip install --upgrade pip
31
+ python -m pip install build twine
32
+
33
+ - name: Build clean sdist and wheel
34
+ shell: bash
35
+ run: |
36
+ set -euo pipefail
37
+ rm -rf build dist
38
+ python -m build
39
+ test "$(find dist -maxdepth 1 -type f | wc -l)" -eq 2
40
+
41
+ - name: Validate package metadata
42
+ shell: bash
43
+ run: |
44
+ set -euo pipefail
45
+ python -m twine check dist/*
46
+ python tools/verify_distribution.py dist
47
+
48
+ - name: Install wheel in fresh environment
49
+ shell: bash
50
+ run: |
51
+ set -euo pipefail
52
+ wheel="$(find dist -maxdepth 1 -name '*.whl' -print -quit)"
53
+ test -n "$wheel"
54
+ python -m venv .wheel-smoke
55
+ .wheel-smoke/bin/python -m pip install --upgrade pip
56
+ .wheel-smoke/bin/python -m pip install "$wheel"
57
+ .wheel-smoke/bin/python - <<'PY'
58
+ import tomllib
59
+ from importlib import metadata, resources
60
+ from pathlib import Path
61
+
62
+ import gazeaudit
63
+
64
+ project = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))
65
+ expected = project["project"]["version"]
66
+ if metadata.version("gazeaudit") != expected:
67
+ raise SystemExit("installed wheel version differs from pyproject.toml")
68
+ if not hasattr(gazeaudit, "GazeStudy"):
69
+ raise SystemExit("installed wheel does not expose GazeStudy")
70
+ resource = resources.files("gazeaudit.data").joinpath(
71
+ "pedrotti2023_sampling_missingness_v1.json"
72
+ )
73
+ if not resource.is_file():
74
+ raise SystemExit("installed wheel is missing frozen scientific package data")
75
+ PY
76
+
77
+ - name: Archive qualified distributions
78
+ uses: actions/upload-artifact@v7
79
+ with:
80
+ name: gazeaudit-distribution-${{ github.sha }}
81
+ path: dist/
82
+ if-no-files-found: error
83
+ retention-days: 30
84
+ compression-level: 0
@@ -0,0 +1,45 @@
1
+ name: interoperability
2
+
3
+ on:
4
+ push:
5
+ branches: [main, "dev/**"]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.head_ref || github.ref_name }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ live-contracts:
18
+ runs-on: ubuntu-latest
19
+
20
+ steps:
21
+ - name: Checkout
22
+ uses: actions/checkout@v4
23
+
24
+ - name: Set up Python
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version: "3.12"
28
+ cache: pip
29
+
30
+ - name: Install interoperability dependencies
31
+ run: |
32
+ python -m pip install --upgrade pip
33
+ python -m pip install -e ".[test,interop]"
34
+
35
+ - name: Verify upstream versions
36
+ run: |
37
+ python - <<'PY'
38
+ import peyes
39
+ import pymovements
40
+ print("pEYES", peyes.__version__)
41
+ print("pymovements", pymovements.__version__)
42
+ PY
43
+
44
+ - name: Run live interoperability contract tests
45
+ run: pytest -q tests/test_optional_interop.py
@@ -0,0 +1,160 @@
1
+ name: korthals-scientific-execution
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ concurrency:
10
+ group: korthals-scientific-execution-v2
11
+ cancel-in-progress: false
12
+
13
+ jobs:
14
+ scientific-execution:
15
+ if: github.ref == 'refs/heads/main'
16
+ runs-on: ubuntu-24.04
17
+ timeout-minutes: 180
18
+ steps:
19
+ - name: Checkout exact GazeAudit commit
20
+ uses: actions/checkout@v4
21
+
22
+ - name: Set up exact Python 3.12.14
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: '3.12.14'
26
+ cache: pip
27
+
28
+ - name: Verify exact main execution identity
29
+ shell: bash
30
+ run: |
31
+ set -euo pipefail
32
+ test "$GITHUB_REF" = "refs/heads/main"
33
+ test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
34
+
35
+ - name: Checkout frozen companion implementation
36
+ shell: bash
37
+ run: |
38
+ set -euo pipefail
39
+ git clone https://github.com/lukekorthals/pursuing-smooth-pursuits-data companion
40
+ git -C companion checkout 1d7ebec23e3fe20f6db952eefda1a0dd58ae09da
41
+ test "$(git -C companion rev-parse HEAD)" = \
42
+ "1d7ebec23e3fe20f6db952eefda1a0dd58ae09da"
43
+
44
+ - name: Install source-freeze-matched critical execution stack
45
+ shell: bash
46
+ run: |
47
+ set -euo pipefail
48
+ python -m pip install --upgrade pip
49
+ python -m pip install \
50
+ "numpy==2.5.3" \
51
+ "pandas==2.3.3" \
52
+ "scipy==1.18.1"
53
+ python -m pip install -e .
54
+ python -m pip install ./companion
55
+ python - <<'PY'
56
+ import platform
57
+ import numpy as np
58
+ import pandas as pd
59
+ import scipy
60
+
61
+ expected = {
62
+ "python": "3.12.14",
63
+ "numpy": "2.5.3",
64
+ "pandas": "2.3.3",
65
+ "scipy": "1.18.1",
66
+ }
67
+ observed = {
68
+ "python": platform.python_version(),
69
+ "numpy": np.__version__,
70
+ "pandas": pd.__version__,
71
+ "scipy": scipy.__version__,
72
+ }
73
+ if observed != expected:
74
+ raise SystemExit(f"execution environment differs from source freeze: {observed}")
75
+ PY
76
+
77
+ - name: Download complete published OSF source
78
+ shell: bash
79
+ run: |
80
+ set -euo pipefail
81
+ python - <<'PY'
82
+ from gazeaudit.korthals_osf import fetch_korthals_osf_resumable
83
+
84
+ summary = fetch_korthals_osf_resumable(
85
+ max_attempts=6,
86
+ initial_backoff_seconds=15.0,
87
+ )
88
+ print(
89
+ "verified endpoint-blind OSF transfer: "
90
+ f"files={summary['file_count']} attempts={summary['attempts']} "
91
+ f"retained={summary['retained_verified_files']} "
92
+ f"removed_partials={summary['removed_partial_files']}"
93
+ )
94
+ PY
95
+
96
+ - name: Verify locked public-source bytes before preprocessing
97
+ shell: bash
98
+ run: |
99
+ set -euo pipefail
100
+ python - <<'PY'
101
+ from gazeaudit.korthals_source_lock import verify_korthals_locked_source_manifest
102
+ from gazeaudit.korthals_v2 import build_korthals_source_manifest_v2
103
+
104
+ manifest = build_korthals_source_manifest_v2("data")
105
+ verify_korthals_locked_source_manifest(manifest)
106
+ PY
107
+
108
+ - name: Capture exact dependency environment before scientific execution
109
+ shell: bash
110
+ run: |
111
+ set -euo pipefail
112
+ python -m pip freeze | LC_ALL=C sort > pip-freeze.txt
113
+ test -s pip-freeze.txt
114
+ grep -Fx 'numpy==2.5.3' pip-freeze.txt
115
+ grep -Fx 'pandas==2.3.3' pip-freeze.txt
116
+ grep -Fx 'scipy==1.18.1' pip-freeze.txt
117
+
118
+ - name: Execute locked protocol v2 without revealing scientific results
119
+ shell: bash
120
+ run: |
121
+ set -euo pipefail
122
+ python -m gazeaudit.korthals_execution_v2_cli \
123
+ --data-root data \
124
+ --output-dir korthals-scientific-execution \
125
+ --environment-file pip-freeze.txt \
126
+ --execution-commit "$GITHUB_SHA" \
127
+ --run-id "$GITHUB_RUN_ID" \
128
+ --runner-os "$RUNNER_OS" \
129
+ --runner-arch "$RUNNER_ARCH"
130
+
131
+ - name: Verify locked scientific archive before upload
132
+ shell: bash
133
+ run: |
134
+ set -euo pipefail
135
+ python - <<'PY'
136
+ from gazeaudit.korthals_execution_archive_v2 import (
137
+ verify_korthals_locked_execution_artifacts_v2,
138
+ )
139
+
140
+ if not verify_korthals_locked_execution_artifacts_v2(
141
+ "korthals-scientific-execution"
142
+ ):
143
+ raise SystemExit("locked Korthals protocol-v2 archive verification failed")
144
+ PY
145
+
146
+ - name: Archive scientific execution before reveal
147
+ uses: actions/upload-artifact@v4
148
+ with:
149
+ name: korthals-scientific-v2-${{ github.sha }}
150
+ path: korthals-scientific-execution/
151
+ if-no-files-found: error
152
+ retention-days: 90
153
+ compression-level: 0
154
+
155
+ - name: Reveal archived scientific result
156
+ shell: bash
157
+ run: |
158
+ set -euo pipefail
159
+ python -m gazeaudit.korthals_reveal_v2_cli \
160
+ --artifact-dir korthals-scientific-execution
@@ -0,0 +1,139 @@
1
+ name: korthals-source-freeze
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ concurrency:
10
+ group: korthals-source-freeze-v2
11
+ cancel-in-progress: false
12
+
13
+ jobs:
14
+ source-freeze:
15
+ if: github.ref == 'refs/heads/main'
16
+ runs-on: ubuntu-24.04
17
+ timeout-minutes: 180
18
+ steps:
19
+ - name: Checkout exact GazeAudit commit
20
+ uses: actions/checkout@v4
21
+
22
+ - name: Set up Python 3.12
23
+ uses: actions/setup-python@v5
24
+ with:
25
+ python-version: '3.12'
26
+ cache: pip
27
+
28
+ - name: Verify exact main execution identity
29
+ shell: bash
30
+ run: |
31
+ set -euo pipefail
32
+ test "$GITHUB_REF" = "refs/heads/main"
33
+ test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
34
+ printf '%s\n' "$GITHUB_SHA" > execution-commit.txt
35
+
36
+ - name: Checkout frozen companion implementation
37
+ shell: bash
38
+ run: |
39
+ set -euo pipefail
40
+ git clone https://github.com/lukekorthals/pursuing-smooth-pursuits-data companion
41
+ git -C companion checkout 1d7ebec23e3fe20f6db952eefda1a0dd58ae09da
42
+ test "$(git -C companion rev-parse HEAD)" = "1d7ebec23e3fe20f6db952eefda1a0dd58ae09da"
43
+
44
+ - name: Install exact execution stack
45
+ shell: bash
46
+ run: |
47
+ set -euo pipefail
48
+ python -m pip install --upgrade pip
49
+ # The frozen companion relies on pandas 2.x DataFrameGroupBy.apply retaining
50
+ # the grouping column. pandas 3.x drops it by default, which removes
51
+ # trial_number before the companion's blink-masking step.
52
+ python -m pip install "pandas==2.3.3"
53
+ python -m pip install -e .
54
+ python -m pip install ./companion
55
+ python - <<'PY'
56
+ import pandas as pd
57
+
58
+ if pd.__version__ != "2.3.3":
59
+ raise SystemExit(f"unexpected pandas version: {pd.__version__}")
60
+ PY
61
+
62
+ - name: Download complete published OSF source
63
+ shell: bash
64
+ run: |
65
+ set -euo pipefail
66
+ # Frozen companion selection remains exactly:
67
+ # raw_clean="both", train_test="both", participants="all", overwrite=False.
68
+ python - <<'PY'
69
+ from gazeaudit.korthals_osf import fetch_korthals_osf_resumable
70
+
71
+ summary = fetch_korthals_osf_resumable(
72
+ max_attempts=6,
73
+ initial_backoff_seconds=15.0,
74
+ )
75
+ print(
76
+ "verified endpoint-blind OSF transfer: "
77
+ f"files={summary['file_count']} attempts={summary['attempts']} "
78
+ f"retained={summary['retained_verified_files']} "
79
+ f"removed_partials={summary['removed_partial_files']}"
80
+ )
81
+ PY
82
+
83
+ - name: Build endpoint-blind protocol-v2 source intake
84
+ shell: bash
85
+ run: |
86
+ set -euo pipefail
87
+ gazeaudit-korthals-source-intake-v2 \
88
+ --data-root data \
89
+ --output-dir source-intake \
90
+ > source-intake-status.txt
91
+
92
+ - name: Capture dependency environment
93
+ shell: bash
94
+ run: |
95
+ set -euo pipefail
96
+ python -m pip freeze | LC_ALL=C sort > pip-freeze.txt
97
+ test -s pip-freeze.txt
98
+
99
+ - name: Build protocol-v2 source-freeze envelope
100
+ shell: bash
101
+ run: |
102
+ set -euo pipefail
103
+ gazeaudit-korthals-source-freeze-v2 \
104
+ --intake-dir source-intake \
105
+ --output-dir korthals-source-freeze \
106
+ --environment-file pip-freeze.txt \
107
+ --execution-commit "$GITHUB_SHA" \
108
+ --run-id "$GITHUB_RUN_ID" \
109
+ --runner-os "$RUNNER_OS" \
110
+ --runner-arch "$RUNNER_ARCH" \
111
+ > source-freeze-status.json
112
+
113
+ - name: Verify protocol-v2 frozen source envelope before archive
114
+ shell: bash
115
+ run: |
116
+ set -euo pipefail
117
+ python - <<'PY'
118
+ from gazeaudit.korthals_freeze_v2 import (
119
+ verify_korthals_source_freeze_artifacts_v2,
120
+ )
121
+
122
+ if not verify_korthals_source_freeze_artifacts_v2("korthals-source-freeze"):
123
+ raise SystemExit("Korthals protocol-v2 source-freeze verification failed")
124
+ PY
125
+
126
+ - name: Archive source freeze before reveal
127
+ uses: actions/upload-artifact@v4
128
+ with:
129
+ name: korthals-source-freeze-v2-${{ github.sha }}
130
+ path: korthals-source-freeze/
131
+ if-no-files-found: error
132
+ retention-days: 90
133
+ compression-level: 0
134
+
135
+ - name: Reveal archived source identity
136
+ shell: bash
137
+ run: |
138
+ set -euo pipefail
139
+ cat source-freeze-status.json
@@ -0,0 +1,159 @@
1
+ name: pedrotti-scientific-execution
2
+
3
+ on:
4
+ workflow_dispatch:
5
+
6
+ permissions:
7
+ contents: read
8
+
9
+ concurrency:
10
+ group: pedrotti-scientific-execution-v1
11
+ cancel-in-progress: false
12
+
13
+ jobs:
14
+ scientific-execution:
15
+ if: github.ref == 'refs/heads/main'
16
+ runs-on: ubuntu-24.04
17
+ timeout-minutes: 180
18
+ steps:
19
+ - name: Checkout exact GazeAudit commit
20
+ uses: actions/checkout@v7
21
+
22
+ - name: Set up Python 3.12.14
23
+ uses: actions/setup-python@v7
24
+ with:
25
+ python-version: '3.12.14'
26
+ cache: pip
27
+
28
+ - name: Verify exact main execution identity
29
+ shell: bash
30
+ run: |
31
+ set -euo pipefail
32
+ test "$GITHUB_REF" = "refs/heads/main"
33
+ test "$(git rev-parse HEAD)" = "$GITHUB_SHA"
34
+
35
+ - name: Install frozen scientific stack
36
+ shell: bash
37
+ run: |
38
+ set -euo pipefail
39
+ python -m pip install --upgrade pip
40
+ python -m pip install "numpy==2.5.3" "pandas==2.3.3"
41
+ python -m pip install -e .
42
+ python - <<'PY'
43
+ import platform
44
+ import numpy as np
45
+ import pandas as pd
46
+
47
+ if platform.python_version() != "3.12.14":
48
+ raise SystemExit(f"unexpected Python version: {platform.python_version()}")
49
+ if np.__version__ != "2.5.3":
50
+ raise SystemExit(f"unexpected NumPy version: {np.__version__}")
51
+ if pd.__version__ != "2.3.3":
52
+ raise SystemExit(f"unexpected pandas version: {pd.__version__}")
53
+ PY
54
+
55
+ - name: Download exact checksum-locked Zenodo source
56
+ shell: bash
57
+ run: |
58
+ set -euo pipefail
59
+ python - <<'PY'
60
+ from gazeaudit.pedrotti_fetch import fetch_pedrotti_zenodo_source
61
+ from gazeaudit.pedrotti_prefetch import prefetch_pedrotti_source_bytes
62
+
63
+ prefetch = prefetch_pedrotti_source_bytes(
64
+ "pedrotti-source",
65
+ max_attempts=6,
66
+ initial_backoff_seconds=15.0,
67
+ timeout_seconds=180.0,
68
+ )
69
+ print(
70
+ "checksum-locked redundant byte prefetch: "
71
+ f"files={prefetch['file_count']} "
72
+ f"request_attempts={prefetch['request_attempts']} "
73
+ f"retained={prefetch['retained_verified_files']} "
74
+ f"removed_mismatches={prefetch['removed_mismatched_files']}"
75
+ )
76
+ summary = fetch_pedrotti_zenodo_source(
77
+ "pedrotti-source",
78
+ max_attempts=6,
79
+ initial_backoff_seconds=15.0,
80
+ timeout_seconds=180.0,
81
+ metadata_max_attempts=2,
82
+ metadata_timeout_seconds=30.0,
83
+ )
84
+ print(
85
+ "verified endpoint-blind Zenodo transfer: "
86
+ f"files={summary['file_count']} "
87
+ f"metadata_source={summary['metadata_source']} "
88
+ f"retained={summary['retained_verified_files']} "
89
+ f"removed_mismatches={summary['removed_mismatched_files']}"
90
+ )
91
+ PY
92
+
93
+ - name: Verify locked endpoint-blind intake before scientific execution
94
+ shell: bash
95
+ run: |
96
+ set -euo pipefail
97
+ python - <<'PY'
98
+ from gazeaudit.pedrotti_source import inspect_pedrotti_source
99
+ from gazeaudit.pedrotti_source_lock import (
100
+ verify_pedrotti_locked_intake,
101
+ verify_pedrotti_source_lock,
102
+ )
103
+
104
+ verify_pedrotti_source_lock()
105
+ intake = inspect_pedrotti_source("pedrotti-source")
106
+ verify_pedrotti_locked_intake(intake)
107
+ print("Pedrotti endpoint-blind source lock: verified")
108
+ PY
109
+
110
+ - name: Capture frozen dependency environment
111
+ shell: bash
112
+ run: |
113
+ set -euo pipefail
114
+ python -m pip freeze | LC_ALL=C sort > pip-freeze.txt
115
+ test -s pip-freeze.txt
116
+
117
+ - name: Execute frozen protocol and build hidden scientific archive
118
+ shell: bash
119
+ run: |
120
+ set -euo pipefail
121
+ python -m gazeaudit.pedrotti_execution_cli \
122
+ --source-dir pedrotti-source \
123
+ --output-dir pedrotti-scientific-archive \
124
+ --environment-file pip-freeze.txt \
125
+ --execution-commit "$GITHUB_SHA" \
126
+ --run-id "$GITHUB_RUN_ID" \
127
+ --runner-os "$RUNNER_OS" \
128
+ --runner-arch "$RUNNER_ARCH"
129
+
130
+ - name: Verify scientific archive before upload
131
+ shell: bash
132
+ run: |
133
+ set -euo pipefail
134
+ python - <<'PY'
135
+ from gazeaudit.pedrotti_execution import (
136
+ verify_pedrotti_locked_execution_artifacts,
137
+ )
138
+
139
+ if not verify_pedrotti_locked_execution_artifacts(
140
+ "pedrotti-scientific-archive"
141
+ ):
142
+ raise SystemExit("Pedrotti scientific archive verification failed")
143
+ PY
144
+
145
+ - name: Archive scientific result before reveal
146
+ uses: actions/upload-artifact@v7
147
+ with:
148
+ name: pedrotti-scientific-execution-v1-${{ github.sha }}
149
+ path: pedrotti-scientific-archive/
150
+ if-no-files-found: error
151
+ retention-days: 90
152
+ compression-level: 0
153
+
154
+ - name: Reveal archived scientific result
155
+ shell: bash
156
+ run: |
157
+ set -euo pipefail
158
+ python -m gazeaudit.pedrotti_reveal_cli \
159
+ --archive-dir pedrotti-scientific-archive