Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node --no-warnings \"$HOME/code/pineforge-workflow/campaign/hooks/pr-gate.mjs\""
}
]
}
]
}
}
43 changes: 30 additions & 13 deletions .github/workflows/gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,16 @@ name: Pyodide Gate
# native CPython on every corpus input (success + failure). Heavier than the
# unit matrix (loads Pyodide), so: on demand, nightly, and on PRs that touch the
# gate itself. It does NOT block releases yet β€” that wiring is Phase 3.
# NOTE: `gate` is a required status check on main, but the pull_request
# trigger below is path-filtered -- a PR touching none of these paths (for
# example a workflow-only change) never runs it and sits BLOCKED. For such a
# PR, include this file in the change (as that PR did) or dispatch this
# workflow on the branch.
# `gate` is a required status check on main, so this workflow runs on EVERY
# pull request and reports; the path filter lives in-job: when a PR touches no
# gate-relevant path the heavy steps are skipped and the check is trivially
# green. (A trigger-level paths: filter would leave path-untouching PRs
# BLOCKED forever -- the required context never reports.)
on:
workflow_dispatch:
schedule:
- cron: "27 5 * * *" # nightly 05:27 UTC
pull_request:
paths:
- "gate/**"
- "tests/gate-corpus/**"
- "package.json"
- "package-lock.json"
- ".github/workflows/gate.yml"
- "pineforge_codegen/**"

permissions:
contents: read
Expand All @@ -36,28 +29,52 @@ jobs:
PYTHONHASHSEED: "0"
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0

- name: Detect gate-relevant changes
id: changes
env:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
run: |
set -euo pipefail
if [ "${{ github.event_name }}" != "pull_request" ]; then
echo "relevant=true" >> "$GITHUB_OUTPUT"; exit 0
fi
if git diff --name-only "$BASE_SHA...HEAD" \
| grep -qE '^(gate/|tests/gate-corpus/|package(-lock)?\.json$|\.github/workflows/gate\.yml$|pineforge_codegen/)'; then
echo "relevant=true" >> "$GITHUB_OUTPUT"
else
echo "::notice::no gate-relevant paths changed β€” gate is trivially green"
echo "relevant=false" >> "$GITHUB_OUTPUT"
fi

- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
if: steps.changes.outputs.relevant == 'true'
with:
python-version: "3.14"

- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
if: steps.changes.outputs.relevant == 'true'
with:
node-version: "22"

- name: Install codegen (native oracle) + node deps
if: steps.changes.outputs.relevant == 'true'
run: |
python -m pip install -e .
npm ci

- name: Selftest (comparator catches divergences)
if: steps.changes.outputs.relevant == 'true'
run: npm run gate:selftest

- name: Run differential gate (full corpus)
if: steps.changes.outputs.relevant == 'true'
run: npm run gate:full

- name: Upload release.json (derived versions, for Phase 3 handoff)
if: always()
if: always() && steps.changes.outputs.relevant == 'true'
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: release-json
Expand Down
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,8 @@ temp/
.scratch/

# ─── Tooling caches (Claude Code, AI agents) ───────────────────────────────
.claude/
.claude/*
!.claude/settings.json
.cursor/
.aider*

Expand Down
Loading
Loading