Skip to content

Commit 95117ae

Browse files
authored
Merge pull request #760 from PolicyEngine/codex/h5-migration-pr3b-traceability-fingerprinting
Add traceability and scope fingerprinting
2 parents a2f3bb3 + 228bb45 commit 95117ae

67 files changed

Lines changed: 6100 additions & 698 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/copilot-instructions.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Copilot Instructions
2+
3+
Follow the repository's canonical engineering skills under
4+
`docs/engineering/skills/`.
5+
6+
For tests, read `docs/engineering/skills/testing.md` before adding, moving, or
7+
reviewing test files. Do not duplicate or override that testing guidance here.

.github/workflows/pr.yaml

Lines changed: 62 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ jobs:
2323
runs-on: ubuntu-latest
2424
needs: check-fork
2525
steps:
26-
- uses: actions/checkout@v4
27-
- uses: actions/setup-python@v5
26+
- uses: actions/checkout@v6
27+
- uses: actions/setup-python@v6
2828
with:
2929
python-version: "3.14"
30-
- uses: astral-sh/setup-uv@v5
30+
- uses: astral-sh/setup-uv@v8.1.0
3131
- name: Check lock file is up-to-date
3232
run: |
3333
uv lock --locked || {
@@ -39,21 +39,33 @@ jobs:
3939
runs-on: ubuntu-latest
4040
needs: check-fork
4141
steps:
42-
- uses: actions/checkout@v4
42+
- uses: actions/checkout@v6
4343
- run: pip install ruff>=0.9.0
4444
- run: ruff format --check .
4545

46+
quality-guards:
47+
name: Quality guards
48+
runs-on: ubuntu-latest
49+
needs: check-fork
50+
steps:
51+
- uses: actions/checkout@v6
52+
- uses: actions/setup-python@v6
53+
with:
54+
python-version: "3.14"
55+
- name: Run quality guards
56+
run: python scripts/run_quality_guards.py
57+
4658
check-changelog:
4759
runs-on: ubuntu-latest
4860
needs: check-fork
4961
steps:
50-
- uses: actions/checkout@v4
62+
- uses: actions/checkout@v6
5163
with:
5264
fetch-depth: 0
53-
- uses: actions/setup-python@v5
65+
- uses: actions/setup-python@v6
5466
with:
5567
python-version: "3.14"
56-
- uses: astral-sh/setup-uv@v5
68+
- uses: astral-sh/setup-uv@v8.1.0
5769
- run: uv sync --dev
5870
- name: Check for changelog fragment
5971
run: uv run towncrier check --compare-with origin/main
@@ -62,11 +74,11 @@ jobs:
6274
runs-on: ubuntu-latest
6375
needs: [check-fork, lint]
6476
steps:
65-
- uses: actions/checkout@v4
66-
- uses: actions/setup-python@v5
77+
- uses: actions/checkout@v6
78+
- uses: actions/setup-python@v6
6779
with:
6880
python-version: "3.14"
69-
- uses: astral-sh/setup-uv@v5
81+
- uses: astral-sh/setup-uv@v8.1.0
7082
- run: uv sync --dev
7183
- name: Run unit tests with coverage
7284
env:
@@ -86,18 +98,11 @@ jobs:
8698
env:
8799
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
88100

89-
optimized-integration-tests:
101+
target-integration-tests:
90102
runs-on: ubuntu-latest
91-
needs:
92-
[
93-
check-fork,
94-
check-lock-freshness,
95-
lint,
96-
check-changelog,
97-
unit-tests,
98-
smoke-test,
99-
docs-build,
100-
]
103+
needs: [check-fork, lint, unit-tests, smoke-test, decide-test-scope]
104+
if: needs.decide-test-scope.outputs.run_integration == 'true'
105+
name: Integration tests
101106
env:
102107
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
103108
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
@@ -107,36 +112,51 @@ jobs:
107112
MODAL_APP_NAME: policyengine-us-data-pipeline
108113
MODAL_LOCAL_AREA_APP_NAME: policyengine-us-data-local-area
109114
MODAL_H5_TEST_HARNESS_APP_NAME: policyengine-us-data-h5-test-harness
110-
name: Optimized integration tests (PR staging)
111115
steps:
112-
- uses: actions/checkout@v4
113-
- uses: actions/setup-python@v5
116+
- uses: actions/checkout@v6
117+
- uses: actions/setup-python@v6
114118
with:
115119
python-version: "3.14"
116-
- name: Install optimized test deps
117-
run: pip install modal pytest numpy pandas
120+
- uses: astral-sh/setup-uv@v8.1.0
121+
- run: uv sync --dev
122+
- name: Install integration test deps
123+
run: uv pip install modal pytest numpy pandas
118124
- name: Ensure PR Modal environment exists
119-
run: python .github/scripts/ensure_modal_environment.py
125+
run: uv run python .github/scripts/ensure_modal_environment.py
120126
- name: Sync Modal secrets to PR environment
121-
run: python .github/scripts/sync_modal_secrets.py
127+
run: uv run python .github/scripts/sync_modal_secrets.py
122128
- name: Deploy Modal pipeline app to PR staging
123-
run: modal deploy --env="${MODAL_ENVIRONMENT}" modal_app/pipeline.py
129+
run: uv run modal deploy --env="${MODAL_ENVIRONMENT}" modal_app/pipeline.py
124130
- name: Deploy Modal local-area app to PR staging
125-
run: modal deploy --env="${MODAL_ENVIRONMENT}" modal_app/local_area.py
131+
run: uv run modal deploy --env="${MODAL_ENVIRONMENT}" modal_app/local_area.py
126132
- name: Deploy Modal H5 test harness to PR staging
127-
run: modal deploy --env="${MODAL_ENVIRONMENT}" modal_app/h5_test_harness.py
128-
- name: Run optimized integration tests against PR staging
129-
run: python -m pytest tests/optimized/ -v
133+
run: uv run modal deploy --env="${MODAL_ENVIRONMENT}" modal_app/h5_test_harness.py
134+
- name: Run integration tests
135+
run: >
136+
uv run pytest
137+
tests/integration/test_tiny_pipeline_workspace.py
138+
tests/integration/test_tiny_stage_1_artifacts.py
139+
tests/integration/test_tiny_stage_2_artifacts.py
140+
tests/integration/test_tiny_stage_3_artifacts.py
141+
tests/integration/test_tiny_stage_4_artifacts.py
142+
tests/integration/test_tiny_stage_5_artifacts.py
143+
tests/integration/test_tiny_pipeline_e2e.py
144+
tests/integration/test_tiny_pipeline_h5_e2e.py
145+
tests/integration/local_h5/
146+
tests/integration/test_modal_pipeline_seams.py
147+
tests/integration/test_tiny_h5_pipeline.py
148+
tests/integration/test_modal_pipeline_e2e.py
149+
-v
130150
- name: Cleanup PR Modal environment
131151
if: always()
132-
run: python .github/scripts/delete_modal_environment.py
152+
run: uv run python .github/scripts/delete_modal_environment.py
133153

134154
smoke-test:
135155
runs-on: ubuntu-latest
136156
needs: [check-fork, lint]
137157
steps:
138-
- uses: actions/checkout@v4
139-
- uses: actions/setup-python@v5
158+
- uses: actions/checkout@v6
159+
- uses: actions/setup-python@v6
140160
with:
141161
python-version: "3.14"
142162
- run: python -m pip install .
@@ -147,14 +167,14 @@ jobs:
147167
runs-on: ubuntu-latest
148168
needs: [check-fork]
149169
steps:
150-
- uses: actions/checkout@v4
151-
- uses: actions/setup-python@v5
170+
- uses: actions/checkout@v6
171+
- uses: actions/setup-python@v6
152172
with:
153173
python-version: "3.14"
154-
- uses: actions/setup-node@v4
174+
- uses: actions/setup-node@v6
155175
with:
156176
node-version: "24"
157-
- uses: astral-sh/setup-uv@v5
177+
- uses: astral-sh/setup-uv@v8.1.0
158178
- run: uv sync --dev
159179
- name: Test documentation builds
160180
run: uv run make documentation
@@ -165,51 +185,15 @@ jobs:
165185
outputs:
166186
run_integration: ${{ steps.check.outputs.run_integration }}
167187
steps:
168-
- uses: actions/checkout@v4
188+
- uses: actions/checkout@v6
169189
with:
170190
fetch-depth: 0
171191
- name: Check changed files for integration scope
172192
id: check
173193
run: |
174194
CHANGED=$(git diff --name-only origin/main...HEAD)
175-
if echo "$CHANGED" | grep -qE '^(policyengine_us_data/|modal_app/|tests/integration/)'; then
195+
if echo "$CHANGED" | grep -qE '^(\.github/scripts/|\.github/workflows/pr\.yaml|modal_app/|policyengine_us_data/|tests/integration/|tests/support/|pyproject\.toml|uv\.lock)'; then
176196
echo "run_integration=true" >> "$GITHUB_OUTPUT"
177197
else
178198
echo "run_integration=false" >> "$GITHUB_OUTPUT"
179199
fi
180-
181-
integration-tests:
182-
runs-on: ubuntu-latest
183-
needs: [check-fork, lint, decide-test-scope]
184-
if: needs.decide-test-scope.outputs.run_integration == 'true'
185-
env:
186-
MODAL_TOKEN_ID: ${{ secrets.MODAL_TOKEN_ID }}
187-
MODAL_TOKEN_SECRET: ${{ secrets.MODAL_TOKEN_SECRET }}
188-
MODAL_ENVIRONMENT: main
189-
HUGGING_FACE_TOKEN: ${{ secrets.HUGGING_FACE_TOKEN }}
190-
steps:
191-
- uses: actions/checkout@v4
192-
with:
193-
fetch-depth: 0
194-
- uses: actions/setup-python@v5
195-
with:
196-
python-version: "3.14"
197-
- run: pip install modal
198-
- name: Build datasets and run integration tests on Modal
199-
run: |
200-
STAGE_ARGS=""
201-
if git diff --name-only origin/main...HEAD | grep -qx 'pyproject.toml'; then
202-
VERSION=$(python .github/fetch_version.py)
203-
STAGE_ARGS="--upload --stage-only --run-id=${VERSION}"
204-
{
205-
echo "## Release Artifact Staging"
206-
echo ""
207-
echo "- package version: \`${VERSION}\`"
208-
echo "- staged HF prefix: \`staging/${VERSION}/\`"
209-
echo "- promote with: \`uv run python policyengine_us_data/storage/upload_completed_datasets.py --promote-only --run-id=${VERSION} --version=${VERSION}\`"
210-
} >> "$GITHUB_STEP_SUMMARY"
211-
fi
212-
213-
modal run --env="${MODAL_ENVIRONMENT}" modal_app/data_build.py \
214-
--branch=${{ github.head_ref || github.ref_name }} \
215-
${STAGE_ARGS}

.github/workflows/push.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ jobs:
1212
- run: pip install ruff>=0.9.0
1313
- run: ruff format --check .
1414

15-
# ── Build and linear integration tests ──────────────────────
16-
build-and-linear-integration-tests:
17-
name: Build and linear integration tests
15+
# ── Dataset build ───────────────────────────────────────────
16+
build-datasets:
17+
name: Build datasets
1818
runs-on: ubuntu-latest
1919
needs: lint
2020
if: github.event.head_commit.message != 'Update package version'
@@ -29,7 +29,7 @@ jobs:
2929
with:
3030
python-version: "3.14"
3131
- run: pip install modal
32-
- name: Run linear integration tests on Modal
32+
- name: Build datasets on Modal
3333
run: |
3434
modal run --env="${MODAL_ENVIRONMENT}" modal_app/data_build.py \
3535
--upload \

AGENTS.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Codex Instructions
2+
3+
These instructions apply repository-wide.
4+
5+
## Skills system
6+
7+
Canonical AI-facing engineering skills live under `docs/engineering/skills/`.
8+
Use those files as the source of truth across Codex, Claude, Copilot, and other
9+
AI tools.
10+
11+
When adding, moving, or reviewing tests, read
12+
`docs/engineering/skills/testing.md`. Do not put pytest files under
13+
`policyengine_us_data/tests/`, do not import from `tests.conftest`, and do not
14+
import helpers across test lanes.

CLAUDE.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,33 @@
77

88
## Testing
99

10+
Canonical testing guidance lives in `docs/engineering/skills/testing.md`. If
11+
this file conflicts with that skill, follow the skill and update this adapter.
12+
1013
### Running Tests
1114
- `make test-unit` - Run unit tests only (fast, no data dependencies)
1215
- `make test-integration` - Run integration tests (requires built H5 datasets)
1316
- `make test` - Run all tests
1417
- `pytest tests/unit/ -v` - Unit tests directly
1518
- `pytest tests/integration/test_cps.py -v` - Specific integration test
19+
- `python scripts/run_quality_guards.py` - Run layout/import quality guards
1620

1721
### Test Organization
18-
Tests are in the top-level `tests/` directory, split into two sub-directories:
22+
Tests are in the top-level `tests/` directory, split into these sub-directories:
1923

2024
- **`tests/unit/`** — Self-contained tests that use synthetic data, mocks, patches, or checked-in fixtures. Run in seconds with no external dependencies.
2125
- `unit/datasets/` — unit tests for dataset code
2226
- `unit/calibration/` — unit tests for calibration code
2327

2428
- **`tests/integration/`** — Tests that require built H5 datasets, HuggingFace downloads, Microsimulation objects, or database ETL. Named after the dataset they test.
29+
- **`tests/optimized/`** — Tests that exercise deployed Modal/staging seams.
2530

2631
### Test Placement Rules
32+
- **NEVER** put pytest files under `policyengine_us_data/tests/`; CI does not collect that tree
2733
- **NEVER** put tests that require H5 files or Microsimulation in `unit/`
2834
- **NEVER** put tests that use only synthetic data or mocks in `integration/`
35+
- **NEVER** import from `tests.conftest`; fixtures are discovered automatically and helper functions belong in local support modules
36+
- **NEVER** import helpers across test lanes, such as `tests.unit` from an integration test
2937
- Integration test files are named after their dataset dependency: `test_cps.py` tests `cps_2024.h5`
3038
- Sanity checks (value ranges, population counts) belong in the per-dataset integration test file, not in a separate sanity file
3139
- When adding a new integration test, add it to the existing per-dataset file if one exists

changelog.d/760.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Added local H5 traceability metadata and scope fingerprinting for calibration artifacts.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add quality guards for test layout and document the testing skill for AI tooling.

docs/engineering/skills/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Engineering Skills
2+
3+
This directory is the canonical source for AI-facing engineering rules.
4+
5+
Tool-specific instruction files such as `AGENTS.md`, `CLAUDE.md`, and
6+
`.github/copilot-instructions.md` should point here instead of duplicating
7+
implementation-specific guidance. When a rule changes, update the skill here
8+
first, then keep adapters thin.
9+
10+
Current skills:
11+
12+
- `testing.md`: test layout, fixture scope, helper placement, and quality guard
13+
expectations.

0 commit comments

Comments
 (0)