From 9922631d1fd9052c7e332451bba5c4d69296308a Mon Sep 17 00:00:00 2001 From: David Snelling Date: Wed, 2 Sep 2026 09:09:33 -0700 Subject: [PATCH 1/2] ci: add the delta-gate workflow for the capped functional lane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit workflow_dispatch, runs-on gate-functional — a host-mode, Bun-only lane with no Node.js runtime, so every step is plain git + bun in shell rather than a JS-based action. Clones candidate and control, runs the full vitest suite on each, enforces a >=3,000-collected guard per side, and diffs the two fail lists for genuinely new reds. The lane's own tripwire marker (host pressure — never our own red or green) is checked before the verdict is printed, and the job cleans up its own checkouts so repeat runs don't feed the lane's disk-budget trip. --- .forgejo/workflows/delta-gate.yml | 127 ++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 .forgejo/workflows/delta-gate.yml diff --git a/.forgejo/workflows/delta-gate.yml b/.forgejo/workflows/delta-gate.yml new file mode 100644 index 00000000..f9209e39 --- /dev/null +++ b/.forgejo/workflows/delta-gate.yml @@ -0,0 +1,127 @@ +name: Delta Gate + +# On-demand candidate-vs-control gate on the capped functional CI lane +# (label: gate-functional). That lane is Bun-only host-mode — there is no +# Node.js runtime available to it, so this workflow deliberately avoids every +# JS-based action (checkout/setup-node/setup-bun/upload-artifact all require +# one) and does everything with plain git + bun in shell steps instead. +# +# Verdict lines a caller should grep for in the run log: +# COLLECTED patch= control= — collection-truncation guard inputs +# NEW-RED-COUNT: — failures on candidate absent from control +# DELTA-GATE: CLEAN | NEW REDS | INVALID | STOPPED-BY-REGISTRY-TRIPWIRE +# +# The lane's own housekeeping stops the runner and drops a marker file when +# host pressure (I/O, registry latency, disk budget) trips — never ours to +# interpret as a red or a green. The final step checks for that marker before +# it says anything about pass/fail. + +on: + workflow_dispatch: + inputs: + candidate: + description: 'Candidate ref (branch or sha) to gate' + required: true + type: string + control: + description: 'Control sha to diff against' + required: true + type: string + +concurrency: + group: delta-gate + cancel-in-progress: false + +jobs: + delta-gate: + name: Delta gate — candidate vs control + runs-on: gate-functional + timeout-minutes: 120 + steps: + - name: Clean any residue from a prior run + run: rm -rf "ob-cand-${{ github.run_id }}" "ob-ctrl-${{ github.run_id }}" "/tmp/ob-${{ github.run_id }}-"* + + - name: Clone + test — candidate + id: patch + run: | + set -o pipefail + git clone --quiet "https://source.soulcraft.com/soulcraftlabs/open-brainy.git" "ob-cand-${{ github.run_id }}" + cd "ob-cand-${{ github.run_id }}" + git checkout --quiet "${{ github.event.inputs.candidate }}" + git log --oneline -1 + bun install + rc=0 + bun x vitest run > "/tmp/ob-${{ github.run_id }}-patch.log" 2>&1 || rc=$? + echo "PATCH-RC:$rc" + grep -aE "Tests .*(passed|failed)" "/tmp/ob-${{ github.run_id }}-patch.log" | tail -1 + grep -aE "^ FAIL |^\s+×" "/tmp/ob-${{ github.run_id }}-patch.log" | sed -E "s/ [0-9]+ms$//" | sed -E "s/^\s+//" | sort -u > "/tmp/ob-${{ github.run_id }}-patch.fail" + echo "PATCH-FAILING:$(wc -l < "/tmp/ob-${{ github.run_id }}-patch.fail")" + + - name: Clone + test — control + id: control + run: | + set -o pipefail + git clone --quiet "https://source.soulcraft.com/soulcraftlabs/open-brainy.git" "ob-ctrl-${{ github.run_id }}" + cd "ob-ctrl-${{ github.run_id }}" + git checkout --quiet "${{ github.event.inputs.control }}" + git log --oneline -1 + bun install + rc=0 + bun x vitest run > "/tmp/ob-${{ github.run_id }}-control.log" 2>&1 || rc=$? + echo "CONTROL-RC:$rc" + grep -aE "Tests .*(passed|failed)" "/tmp/ob-${{ github.run_id }}-control.log" | tail -1 + grep -aE "^ FAIL |^\s+×" "/tmp/ob-${{ github.run_id }}-control.log" | sed -E "s/ [0-9]+ms$//" | sed -E "s/^\s+//" | sort -u > "/tmp/ob-${{ github.run_id }}-control.fail" + echo "CONTROL-FAILING:$(wc -l < "/tmp/ob-${{ github.run_id }}-control.fail")" + + - name: Delta gate verdict + if: always() + run: | + set -o pipefail + + # The lane's own tripwire wins over anything we would otherwise say: + # a bare failure/timeout above with this marker present is host + # pressure, never a real red and never a real green. + if [ -f /srv/gate-lane/TRIPWIRE-STOPPED ]; then + echo "DELTA-GATE: STOPPED-BY-REGISTRY-TRIPWIRE" + head -1 /srv/gate-lane/TRIPWIRE-STOPPED + exit 3 + fi + + patch_log="/tmp/ob-${{ github.run_id }}-patch.log" + control_log="/tmp/ob-${{ github.run_id }}-control.log" + patch_fail="/tmp/ob-${{ github.run_id }}-patch.fail" + control_fail="/tmp/ob-${{ github.run_id }}-control.fail" + + if [ ! -s "$patch_log" ] || [ ! -s "$control_log" ]; then + echo "DELTA-GATE: INVALID — a leg produced no log (see the two steps above for the real cause)" + exit 2 + fi + + pt=$(grep -aoE "\(([0-9]+)\)$" "$patch_log" | tail -1 | tr -d "()") + ct=$(grep -aoE "\(([0-9]+)\)$" "$control_log" | tail -1 | tr -d "()") + echo "COLLECTED patch=${pt:-0} control=${ct:-0}" + if [ "${pt:-0}" -lt 3000 ] || [ "${ct:-0}" -lt 3000 ]; then + echo "DELTA-GATE: INVALID — truncated collection" + exit 2 + fi + + echo "=== NEW REDS ===" + comm -23 "$patch_fail" "$control_fail" + new=$(comm -23 "$patch_fail" "$control_fail" | wc -l) + echo "NEW-RED-COUNT:$new" + + echo "=== full candidate fail list ===" + cat "$patch_fail" + echo "=== full control fail list ===" + cat "$control_fail" + + if [ "$new" -eq 0 ]; then + echo "DELTA-GATE: CLEAN" + else + echo "DELTA-GATE: NEW REDS" + exit 1 + fi + + - name: Clean up (mind the lane's disk budget) + if: always() + run: rm -rf "ob-cand-${{ github.run_id }}" "ob-ctrl-${{ github.run_id }}" "/tmp/ob-${{ github.run_id }}-"* From 67ae0046de4063cf74bc9d57eb68adccd575ed5e Mon Sep 17 00:00:00 2001 From: David Snelling Date: Wed, 2 Sep 2026 09:36:12 -0700 Subject: [PATCH 2/2] ci(delta-gate): add a push fallback trigger alongside workflow_dispatch workflow_dispatch needs Actions-unit write on the dispatching credential; push does not, since Forgejo runs the workflow straight from the pushed ref's tree. A plain push to a rel/** or ci/** branch now also fires the gate, resolving candidate to the pushed commit and control to the last released, known-good tip (10.4.9) when the workflow_dispatch inputs aren't present. --- .forgejo/workflows/delta-gate.yml | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/.forgejo/workflows/delta-gate.yml b/.forgejo/workflows/delta-gate.yml index f9209e39..c320594e 100644 --- a/.forgejo/workflows/delta-gate.yml +++ b/.forgejo/workflows/delta-gate.yml @@ -27,6 +27,12 @@ on: description: 'Control sha to diff against' required: true type: string + # workflow_dispatch needs Actions-unit write on the dispatching credential; + # push does not (it runs from the pushed ref's own tree), so a plain push + # to a release or CI branch is the fallback trigger while that grant is + # outstanding — see the ref-resolution step below for what it gates against. + push: + branches: ['rel/**', 'ci/**'] concurrency: group: delta-gate @@ -38,6 +44,21 @@ jobs: runs-on: gate-functional timeout-minutes: 120 steps: + - name: Resolve candidate/control refs + id: refs + run: | + candidate="${{ github.event.inputs.candidate }}" + control="${{ github.event.inputs.control }}" + # workflow_dispatch supplies both explicitly; a push event carries + # neither — fall back to the pushed commit as candidate and the + # last released, known-good tip (10.4.9) as control, so a plain + # push still produces a meaningful gate instead of an empty ref. + if [ -z "$candidate" ]; then candidate="${{ github.sha }}"; fi + if [ -z "$control" ]; then control="eec90bdd"; fi + echo "candidate=$candidate" >> "$GITHUB_OUTPUT" + echo "control=$control" >> "$GITHUB_OUTPUT" + echo "Resolved (trigger=${{ github.event_name }}): candidate=$candidate control=$control" + - name: Clean any residue from a prior run run: rm -rf "ob-cand-${{ github.run_id }}" "ob-ctrl-${{ github.run_id }}" "/tmp/ob-${{ github.run_id }}-"* @@ -47,7 +68,7 @@ jobs: set -o pipefail git clone --quiet "https://source.soulcraft.com/soulcraftlabs/open-brainy.git" "ob-cand-${{ github.run_id }}" cd "ob-cand-${{ github.run_id }}" - git checkout --quiet "${{ github.event.inputs.candidate }}" + git checkout --quiet "${{ steps.refs.outputs.candidate }}" git log --oneline -1 bun install rc=0 @@ -63,7 +84,7 @@ jobs: set -o pipefail git clone --quiet "https://source.soulcraft.com/soulcraftlabs/open-brainy.git" "ob-ctrl-${{ github.run_id }}" cd "ob-ctrl-${{ github.run_id }}" - git checkout --quiet "${{ github.event.inputs.control }}" + git checkout --quiet "${{ steps.refs.outputs.control }}" git log --oneline -1 bun install rc=0