Skip to content

Commit ed35f45

Browse files
Merge branch 'run4-authority-v1.2'
2 parents 00d05af + 01244d1 commit ed35f45

10 files changed

Lines changed: 3673 additions & 343 deletions

File tree

.github/workflows/ci.yml

Lines changed: 113 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -47,20 +47,45 @@ jobs:
4747
# Run 4 Gate + Signature Binding
4848
# -------------------------------
4949

50-
- name: Ensure INTENT.json exists (push fallback)
50+
- name: Select contract source (authority-first)
5151
shell: bash
5252
run: |
53-
if [ ! -f "INTENT.json" ]; then
54-
cat > INTENT.json <<'EOF'
55-
{
56-
"mode": "normal",
57-
"intent": "CI run (push fallback) — no explicit intent provided",
58-
"declared_authority": "low"
59-
}
60-
EOF
61-
echo "Wrote fallback INTENT.json"
53+
set -euo pipefail
54+
55+
# Prefer AUTHORITY.json (new)
56+
if [ -f "AUTHORITY.json" ]; then
57+
echo "CONTRACT_PATH=AUTHORITY.json" >> $GITHUB_ENV
58+
echo "CONTRACT_KIND=authority" >> $GITHUB_ENV
59+
exit 0
60+
fi
61+
62+
# Back-compat: AUTHORITY_CONTRACT.json (current repo reality)
63+
if [ -f "AUTHORITY_CONTRACT.json" ]; then
64+
echo "CONTRACT_PATH=AUTHORITY_CONTRACT.json" >> $GITHUB_ENV
65+
echo "CONTRACT_KIND=authority" >> $GITHUB_ENV
66+
echo "WARN: Using AUTHORITY_CONTRACT.json. Consider renaming to AUTHORITY.json."
67+
exit 0
68+
fi
69+
70+
# Legacy support: INTENT.json (old)
71+
if [ -f "INTENT.json" ]; then
72+
echo "CONTRACT_PATH=INTENT.json" >> $GITHUB_ENV
73+
echo "CONTRACT_KIND=intent" >> $GITHUB_ENV
74+
echo "WARN: Using legacy INTENT.json. Migrate to AUTHORITY.json."
75+
exit 0
76+
fi
77+
78+
# No contract present
79+
if [ "${{ github.event_name }}" = "pull_request" ]; then
80+
echo "ERROR: Missing contract file. Provide AUTHORITY.json (preferred) or INTENT.json (legacy)."
81+
exit 2
6282
fi
6383
84+
# For push runs: do NOT invent a contract silently.
85+
echo "No contract file on push; gate will be skipped."
86+
echo "CONTRACT_PATH=" >> $GITHUB_ENV
87+
echo "CONTRACT_KIND=none" >> $GITHUB_ENV
88+
6489
- name: Produce diff scope (stable)
6590
shell: bash
6691
run: |
@@ -79,38 +104,39 @@ jobs:
79104
- name: Run Gate (Run 4)
80105
shell: bash
81106
run: |
82-
# Force INTENT.json to be the authority source for CI runs
83-
if [ -f AUTHORITY_CONTRACT.json ]; then
84-
mv AUTHORITY_CONTRACT.json AUTHORITY_CONTRACT.json.bak
107+
set -euo pipefail
108+
109+
if [ "${CONTRACT_KIND}" = "none" ]; then
110+
echo "Skipping gate (no contract on push)."
111+
exit 0
112+
fi
113+
114+
if { [ -f "AUTHORITY.json" ] || [ -f "AUTHORITY_CONTRACT.json" ]; } && [ -f "INTENT.json" ]; then
115+
echo "ERROR: Authority contract present alongside INTENT.json. Remove INTENT.json."
116+
exit 2
85117
fi
86118
87-
# Run gate (may exit non-zero)
88119
set +e
89-
node -e "require('./src/gate-run4').runGate({ intentPath:'INTENT.json', registryPath: process.env.SURFACE_REGISTRY_PATH || 'surface_registry.yaml', bootstrapLockPath: process.env.BOOTSTRAP_LOCK_PATH || 'bootstrap.lock', meaningOutPath:'meaning.json' })"
120+
node -e "require('./src/gate-run4').runGate({ intentPath: process.env.CONTRACT_PATH, registryPath: process.env.SURFACE_REGISTRY_PATH || 'surface_registry.yaml', bootstrapLockPath: process.env.BOOTSTRAP_LOCK_PATH || 'bootstrap.lock', meaningOutPath:'meaning.json' })"
90121
GATE_RC=$?
91122
set -e
92123
93-
# Copy latest .prism run outputs to stable filenames for inspection + downstream steps
94-
RUN_DIR="$(ls -td .prism/runs/* 2>/dev/null | head -n 1 || true)"
95-
echo "Latest run dir: $RUN_DIR"
96-
if [ -n "$RUN_DIR" ] && [ -f "$RUN_DIR/meaning.json" ]; then
97-
cp "$RUN_DIR/meaning.json" meaning.json
98-
cp "$RUN_DIR/mutation_report.json" mutation_report.json || true
99-
echo "meaning.json (first 120 lines):"
100-
head -n 120 meaning.json
101-
else
102-
echo "No run outputs found under .prism/runs"
124+
echo "Gate exit code: $GATE_RC"
125+
if [ $GATE_RC -ne 0 ]; then
126+
exit $GATE_RC
103127
fi
104128
105-
# Re-emit gate exit code
106-
exit $GATE_RC
107-
108-
109-
129+
# HARD ASSERT: meaning.json must be valid JSON
130+
if [ ! -s meaning.json ]; then
131+
echo "ERROR: meaning.json missing or empty after gate."
132+
ls -la || true
133+
exit 2
134+
fi
110135
111-
test -f meaning.json
136+
node -e "JSON.parse(require('fs').readFileSync('meaning.json','utf8')); console.log('meaning.json is valid JSON');"
112137
113138
- name: Import signing key (GPG)
139+
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
114140
shell: bash
115141
run: |
116142
echo "${{ secrets.PRISM_GPG_PRIVATE_KEY }}" | gpg --batch --yes --import
@@ -119,80 +145,83 @@ jobs:
119145
- name: Attach integrity hashes
120146
shell: bash
121147
run: |
122-
node scripts/hash-and-attach-integrity.js \
123-
--artifact meaning.json \
124-
--intent INTENT.json \
125-
--diff diff.txt \
126-
--out meaning.with-integrity.json \
127-
--ci-run-id "${GITHUB_RUN_ID}"
148+
set -euo pipefail
149+
if [ "${CONTRACT_KIND}" = "none" ]; then
150+
echo "Skipping integrity (no contract on push)."
151+
exit 0
152+
fi
153+
154+
if [ "${CONTRACT_KIND}" = "authority" ]; then
155+
node scripts/hash-and-attach-integrity.js \
156+
--artifact meaning.json \
157+
--authority "${CONTRACT_PATH}" \
158+
--diff diff.txt \
159+
--out meaning.with-integrity.json \
160+
--ci-run-id "${GITHUB_RUN_ID}"
161+
else
162+
node scripts/hash-and-attach-integrity.js \
163+
--artifact meaning.json \
164+
--intent "${CONTRACT_PATH}" \
165+
--diff diff.txt \
166+
--out meaning.with-integrity.json \
167+
--ci-run-id "${GITHUB_RUN_ID}"
168+
fi
128169
129170
- name: Sign artifact
171+
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
130172
shell: bash
131173
run: |
174+
set -euo pipefail
175+
if [ "${CONTRACT_KIND}" = "none" ]; then
176+
echo "Skipping sign (no contract on push)."
177+
exit 0
178+
fi
179+
132180
node scripts/sign-artifact.js \
133181
--artifact meaning.with-integrity.json \
134182
--out meaning.signed.json \
135183
--sig-out artifact.sig \
136184
--pubkey-out pubkey.asc \
137185
--gpg-fpr "${{ secrets.PRISM_GPG_FPR }}"
138186
139-
- name: Verify signed contract
140-
shell: bash
141-
run: |
142-
echo "Skipping verify-authority-contract.js: signed file is an interpretation artifact."
143-
144-
- name: Run Gate (runGate → meaning.json)
145-
shell: bash
146-
run: |
147-
node -e "require('./src/gate-run4').runGate({ intentPath:'INTENT.json', registryPath: process.env.SURFACE_REGISTRY_PATH || 'surface_registry.yaml', bootstrapLockPath: process.env.BOOTSTRAP_LOCK_PATH || 'bootstrap.lock', meaningOutPath:'meaning.json' })"
148-
test -f meaning.json
149-
150-
- name: Import signing key (GPG)
151-
# Avoid failing on fork PRs where secrets are not available:
187+
- name: Verify signed interpretation artifact
152188
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
153189
shell: bash
154190
run: |
155-
echo "${{ secrets.PRISM_GPG_PRIVATE_KEY }}" | gpg --batch --yes --import
156-
gpg --list-secret-keys --keyid-format LONG
191+
set -euo pipefail
192+
if [ "${CONTRACT_KIND}" = "none" ]; then
193+
echo "Skipping verify (no contract on push)."
194+
exit 0
195+
fi
157196
158-
- name: Canonicalize inputs (optional debug artifacts)
159-
shell: bash
160-
run: |
161-
node scripts/canonicalize.js INTENT.json > intent.canon.json
162-
node scripts/canon-diff.js diff.txt > diff.canon.txt
197+
if [ "${CONTRACT_KIND}" = "authority" ]; then
198+
node scripts/verify-interpretation-artifact.js \
199+
--artifact meaning.signed.json \
200+
--authority "${CONTRACT_PATH}" \
201+
--diff diff.txt \
202+
--pubkey pubkey.asc
203+
else
204+
node scripts/verify-interpretation-artifact.js \
205+
--artifact meaning.signed.json \
206+
--intent "${CONTRACT_PATH}" \
207+
--allow-intent-hash \
208+
--diff diff.txt \
209+
--pubkey pubkey.asc
210+
fi
163211
164-
- name: Attach integrity hashes
165-
shell: bash
166-
run: |
167-
node scripts/hash-and-attach-integrity.js \
168-
--artifact meaning.json \
169-
--intent INTENT.json \
170-
--diff diff.txt \
171-
--out meaning.with-integrity.json \
172-
--ci-run-id "${GITHUB_RUN_ID}"
173-
174-
- name: Sign artifact (detached) + embed signature
175-
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork == false }}
212+
- name: Stage artifacts for upload
213+
if: ${{ always() }}
176214
shell: bash
177215
run: |
178-
node scripts/sign-artifact.js \
179-
--artifact meaning.with-integrity.json \
180-
--out meaning.signed.json \
181-
--sig-out artifact.sig \
182-
--pubkey-out pubkey.asc \
183-
--gpg-fpr "${{ secrets.PRISM_GPG_FPR }}"
216+
set -euo pipefail
217+
mkdir -p out_artifacts
218+
cp -f meaning.with-integrity.json meaning.signed.json artifact.sig pubkey.asc diff.txt meaning.json mutation_report.json out_artifacts/ 2>/dev/null || true
219+
cp -f INTENT.json out_artifacts/ 2>/dev/null || true
220+
cp -f AUTHORITY.json out_artifacts/ 2>/dev/null || true
184221
185222
- name: Upload signed artifacts
186223
if: ${{ always() }}
187224
uses: actions/upload-artifact@v4
188225
with:
189226
name: prism-signed-artifacts
190-
path: |
191-
meaning.with-integrity.json
192-
meaning.signed.json
193-
artifact.sig
194-
pubkey.asc
195-
diff.txt
196-
INTENT.json
197-
mutation_report.json
198-
meaning.json
227+
path: out_artifacts

.github/workflows/enforce.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
- name: Run Execution Boundary Interpretation
1717
uses: ./
1818
with:
19-
intent_path: "INTENT.json"
19+
intent_path: "AUTHORITY_CONTRACT.json"
2020
fail_on: "scope,file_count,deletions,renames,moves"
2121
env:
2222
GITHUB_TOKEN: ${{ github.token }}

.github/workflows/prism-gate.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ on:
1616
- "src/**"
1717
- "dist/**"
1818
- ".github/workflows/prism-gate.yml"
19-
- "INTENT.json"
19+
- "AUTHORITY_CONTRACT.json"
2020

2121
jobs:
2222
prism:
@@ -33,7 +33,7 @@ jobs:
3333
- name: Run Prism Gate (local)
3434
uses: ./
3535
env:
36-
INTENT_PATH: "INTENT.json"
36+
INTENT_PATH: "AUTHORITY_CONTRACT.json"
3737
REGISTRY_PATH: ".prism/surface_registry.yaml"
3838
BOOTSTRAP_LOCK_PATH: ".prism/bootstrap.lock"
3939
MEANING_OUT_PATH: "meaning.json"

0 commit comments

Comments
 (0)