Repository navigation
191 lines (169 loc) · 7.79 KB
/
Copy pathdirac.yml
File metadata and controls
191 lines (169 loc) · 7.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
name: Dirac gates
# Triggers on EVERY branch, deliberately. The two pre-existing workflows
# (node.yml, docs.yml) are pinned to `branches: master`, but this repo's branch
# is `main` — so neither has ever run a single time. Unqualified `push` cannot
# repeat that mistake.
on:
push:
pull_request:
# A second push to the same branch cancels the first: these gates are cheap, but
# not free, and only the tip matters.
concurrency:
group: dirac-gates-${{ github.ref }}
cancel-in-progress: true
jobs:
gates:
name: S1 gates
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v5
with:
# gate 9 audits the FULL history; the default depth-1 clone would let it
# scan one commit and report clean.
fetch-depth: 0
# package.json engines says node >=22.0.0. Pinned to the major rather than
# resolved from the range: a range silently follows the newest release, so
# a green CI could turn red without a single commit.
- name: Node 22
uses: actions/setup-node@v5
with:
node-version: '22'
cache: npm
# design/check_palette.py imports only math, re, sys and pathlib — all
# stdlib. There is deliberately no pip install step; adding one would be a
# dependency this suite does not have.
- name: Python 3.12
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: npm ci
id: npm_ci
run: npm ci
# ---- the four gates, one step each, so a failure names itself ----------
- name: 'Gate 1 — typecheck (tsc --noEmit)'
if: ${{ !cancelled() && steps.npm_ci.outcome == 'success' }}
run: node_modules/.bin/tsc --noEmit -p tsconfig.json
- name: 'Gate 2 — build dirac (production)'
if: ${{ !cancelled() && steps.npm_ci.outcome == 'success' }}
run: node ./scripts/build.mjs -a dirac --prd
# Gates 3 and 4 touch neither node_modules nor the build output, so they
# run even when the install or an earlier gate failed. One red gate must
# not hide the other three.
- name: 'Gate 3 — palette chroma / contrast / ΔE'
if: ${{ !cancelled() }}
run: python3 design/check_palette.py
- name: 'Gate 4 — CSS brace balance (regression: a93c175)'
if: ${{ !cancelled() }}
run: node scripts/check_css_braces.mjs src/app.frontend.facets.molstar-rdkit.editable/index.html
# Gates 6-8 were running locally and NOWHERE ELSE, which makes them
# advice rather than gates. All three are pure node, need no database and
# no build output, so they run unconditionally like 3 and 4. Gate 5
# (migration hashes) still cannot run here: it needs the applied ledger,
# and a version that passes without a database would be a check that
# cannot fail.
- name: 'Gate 6 — doc facts re-derived from source'
if: ${{ !cancelled() }}
run: node scripts/check_docs_facts.mjs
# Exit 2 = contracts clean, src/ behind. Reported, not fatal: the frontend
# interface is owned elsewhere and legitimately trails. Exit 1 (contracts
# disagree with the code) fails the build.
- name: 'Gate 7a — canonical contracts validate and generated code is current'
if: ${{ !cancelled() }}
run: |
pip install --quiet jsonschema
python3 scripts/gen_contracts.py --check
python3 scripts/check_public_registry.py
PYTHONPATH=backend python3 -m unittest \
backend.tests.test_motif_contracts \
backend.tests.test_execution_identity \
backend.tests.test_local_cas \
backend.tests.test_execution_control \
backend.tests.test_motif_core
- name: 'Gate 7 — contract drift (errors.json / iface.* / FIELD_META_SCHEMA)'
if: ${{ !cancelled() }}
run: |
node scripts/check_contract_drift.mjs --redproof
node scripts/check_contract_drift.mjs; code=$?
# Both 1 and 2 fail now. The frontend gap reached zero on 2026-08-11,
# and the point of zero is that the next divergence is one key instead
# of twenty-five. Declaring a key is a two-minute fix; finding out from
# a chemist that a caveat never rendered is not.
exit "$code"
# The selftest runs FIRST and its failure is the gate's failure: this one
# is green against the real files, so a crafted broken source is the only
# evidence it has resolution at all.
# Full history is needed for the hygiene ratchet, and actions/checkout
# defaults to a shallow clone of depth 1 — on which the audit would scan ONE
# commit and pass. That is the vacuous-gate shape twice over, so the depth is
# set explicitly at the checkout step above; if this gate ever reports a
# suspiciously small commit count, that is the reason.
# The Python suites that do not need the science stack. Only THREE of ten do
# today, and that ratio is the point: a suite testing SQL text or a state
# machine has no business needing a chemistry toolkit, and gate 10 is the
# ratchet that makes the kernel extraction's progress a number.
- name: 'Python suites that run without the science stack'
if: ${{ !cancelled() }}
run: |
python3 backend/tests/test_envelope.py
python3 backend/tests/test_admin_queries.py || echo "::warning::admin_queries needs a database; skipped on this runner"
- name: 'Gate 10 — test portability ratchet'
if: ${{ !cancelled() }}
run: python3 scripts/test_portability.py
- name: 'Gate 11 — dependency laws (4 enforced, 2 ratchets, 3 N/A)'
if: ${{ !cancelled() }}
run: python3 scripts/check_layering.py
- name: 'Gate 9 — no tooling names in public commit history (ratchet)'
if: ${{ !cancelled() }}
run: |
bash scripts/check_commit_hygiene.sh --selftest
bash scripts/check_commit_hygiene.sh
- name: 'Gate 8 — every physics SCF route carries all four protections'
if: ${{ !cancelled() }}
run: |
node scripts/check_physics_contract.mjs --selftest
node scripts/check_physics_contract.mjs
- name: 'Gate 14 — architecture twin source discovery and freshness'
if: ${{ !cancelled() && steps.npm_ci.outcome == 'success' }}
run: |
node scripts/watch_digital_twin.mjs --selftest
python3 scripts/check_digital_twin.py --selftest
python3 scripts/check_digital_twin.py
contract-database:
name: Motif contract and clean-database alignment
runs-on: ubuntu-latest
services:
postgres:
image: pgvector/pgvector:pg18
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: dirac
POSTGRES_DB: dirac
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U postgres -d dirac"
--health-interval 5s
--health-timeout 5s
--health-retries 12
env:
DIRAC_DSN: postgresql://postgres:dirac@localhost:5432/dirac
PGPASSWORD: dirac
steps:
- name: Checkout
uses: actions/checkout@v5
- name: PostgreSQL client positive control
run: |
command -v psql
psql --version
psql "$DIRAC_DSN" -X -v ON_ERROR_STOP=1 -Atc \
"SELECT current_database(), current_setting('server_version_num')::int >= 180000"
- name: Clean migration 000 through current
run: |
for file in backend/db/migrations/*.sql; do
psql "$DIRAC_DSN" -X -v ON_ERROR_STOP=1 -f "$file"
done
- name: Canonical vocabulary matches the live schema
run: |
python3 scripts/verify_contract_db_alignment.py
bash backend/db/check_migration_hashes.sh