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
69 changes: 57 additions & 12 deletions .github/workflows/opencode-model-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,40 @@ jobs:
id: probe
run: |
set +e
node --experimental-strip-types scripts/check-opencode-models.ts --output model-health-report.md
node --experimental-strip-types scripts/check-opencode-models.ts \
--output model-health-report.md \
--json > model-health-output.log
EXIT_CODE=$?
set -e

cat model-health-output.log || true
# --json prints human progress first and the report object last, so keep
# the tail from the first line that opens an object. Later steps read
# dead/degraded counts from this file instead of probing again.
sed -n '/^{/,$p' model-health-output.log > model-health.json

echo "exit_code=$EXIT_CODE" >> "$GITHUB_OUTPUT"

if [ $EXIT_CODE -eq 2 ]; then
echo "Probe infra failure (exit code 2) — report only, no alert issue"
echo "AFFECTED_MODELS=false" >> "$GITHUB_ENV"
echo "INFRA_FAILURE=true" >> "$GITHUB_ENV"
elif [ $EXIT_CODE -ne 0 ]; then
echo "Affected models detected (exit code $EXIT_CODE)"
elif [ $EXIT_CODE -eq 1 ]; then
echo "Dead model(s) detected (exit code 1)"
echo "AFFECTED_MODELS=true" >> "$GITHUB_ENV"
echo "INFRA_FAILURE=false" >> "$GITHUB_ENV"
else
echo "All OpenCode free models healthy (exit code 0)"
elif [ $EXIT_CODE -eq 0 ]; then
# Exit 0 covers healthy, unavailable, and timeout alike: availability
# faults are reported in the summary above but never open an issue.
echo "No dead OpenCode free model (exit code 0)"
echo "AFFECTED_MODELS=false" >> "$GITHUB_ENV"
echo "INFRA_FAILURE=false" >> "$GITHUB_ENV"
else
# A signal death or an unhandled crash must not look like a healthy
# run: only exit 0 may close an alert, and only exit 1 may file one.
echo "Unexpected probe exit code $EXIT_CODE — treating as infra failure"
echo "AFFECTED_MODELS=false" >> "$GITHUB_ENV"
echo "INFRA_FAILURE=true" >> "$GITHUB_ENV"
fi

- name: Publish Step Summary
Expand All @@ -79,7 +95,26 @@ jobs:
run: |
echo "::error::OpenCode free-model probe infra failure — see step summary; no alert issue filed."

- name: Open or Update GitHub Issue on Affected Models
- name: Annotate Unavailable Models (No Alert)
if: always() && env.INFRA_FAILURE != 'true' && env.AFFECTED_MODELS != 'true'
run: |
# Availability faults and probe timeouts exit 0 and never open an
# issue; this annotation is the only trace on the run itself. Counts
# come from the probe's own --json output — never a second probe.
if [ ! -s model-health.json ]; then
echo "No probe JSON available; skipping degraded-model annotation"
exit 0
fi
DEGRADED=$(node -e '
const fs = require("node:fs");
const report = JSON.parse(fs.readFileSync("model-health.json", "utf8"));
process.stdout.write(String(report.degradedCount ?? 0));
')
if [ "${DEGRADED:-0}" -gt 0 ]; then
echo "::warning::${DEGRADED} OpenCode free-tier model(s) unavailable or inconclusive — availability fault retried at probe time; no catalog action and no alert issue filed."
fi

- name: Open or Update GitHub Issue on Dead Models
if: env.AFFECTED_MODELS == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -91,35 +126,45 @@ jobs:
# gh must always read a real file: an inline --body value would be split by the
# shell, so a missing report is replaced by a one-line fallback first.
if [ ! -f model-health-report.md ]; then
echo "OpenCode free tier models health probe detected affected models. Check workflow logs." > model-health-report.md
printf '%s\n' "OpenCode free-tier probe reported dead model(s) but model-health-report.md is missing. See the workflow run logs." > model-health-report.md
fi

EXISTING_ISSUE=$(gh issue list --label "$LABEL" --state open --json number --jq '.[0].number')
if [ -n "$EXISTING_ISSUE" ]; then
echo "Updating existing alert issue #$EXISTING_ISSUE"
gh issue comment "$EXISTING_ISSUE" --body-file model-health-report.md
# Replace the body, never append: otherwise every 12h run stacks a
# comment and the current verdict buries under stale ones.
echo "Replacing body of existing alert issue #$EXISTING_ISSUE"
gh issue edit "$EXISTING_ISSUE" --body-file model-health-report.md
else
echo "Creating new alert issue"
CURRENT_DATE=$(date -u +'%Y-%m-%d %H:%M UTC')
gh issue create \
--title "🚨 OpenCode Free Tier Model Disruption (${CURRENT_DATE})" \
--title "🚨 OpenCode Free Tier Model Dead (${CURRENT_DATE})" \
--label "$LABEL" \
--body-file model-health-report.md
fi

# A run that touched the alert must never also close it: the close step
# is exit-0-only, and this guard states the invariant in the shell too.
echo "ALERT_ISSUE_TOUCHED=true" >> "$GITHUB_ENV"

- name: Close Recovered Alert Issue
if: steps.probe.outputs.exit_code == '0'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
LABEL="opencode-model-alert"
if [ "${ALERT_ISSUE_TOUCHED:-false}" = "true" ]; then
echo "This run updated the alert issue; a later healthy run owns the close"
exit 0
fi
EXISTING_ISSUE=$(gh issue list --label "$LABEL" --state open --json number --jq '.[0].number')
if [ -z "$EXISTING_ISSUE" ]; then
echo "No open $LABEL issue to close"
else
CURRENT_DATE=$(date -u +'%Y-%m-%d %H:%M UTC')
echo "All OpenCode free-tier models healthy again — closing alert issue #$EXISTING_ISSUE"
gh issue comment "$EXISTING_ISSUE" --body "All OpenCode free-tier models are healthy again as of ${CURRENT_DATE}. Auto-closing this alert."
echo "No OpenCode free-tier model is dead as of ${CURRENT_DATE} — closing alert issue #$EXISTING_ISSUE"
gh issue comment "$EXISTING_ISSUE" --body "No OpenCode free-tier model is dead as of ${CURRENT_DATE}. Availability faults do not keep this alert open. Auto-closing."
gh issue close "$EXISTING_ISSUE" --reason completed
fi
79 changes: 56 additions & 23 deletions .github/workflows/opencode-watch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ on:
# Daily at 04:00 UTC
- cron: "0 4 * * *"
workflow_dispatch:
inputs:
rebaseline:
description: "Re-baseline the watcher state and close any open drift issue"
type: boolean
default: false

permissions:
contents: write
Expand All @@ -29,34 +34,43 @@ jobs:
with:
node-version: "lts/*"

- name: Rebaseline Watcher State
if: github.event.inputs.rebaseline == 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Manual path: trust live upstream for every watched file, critical
# included, and write the full baseline. No issue is created here.
node scripts/opencode-watch.mjs --update --output drift-report.md

- name: Run OpenCode Watch Check
id: check
if: github.event.inputs.rebaseline != 'true'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set +e
node scripts/opencode-watch.mjs --check --output drift-report.md
# --advance re-baselines informational signals (release, zen.mdx, the
# model listing) so they report once, while holding the previous SHA of
# a critically changed schema file: that alert repeats until a human
# re-baselines with the rebaseline dispatch input.
node scripts/opencode-watch.mjs --check --advance --output drift-report.md
EXIT_CODE=$?
set -e

echo "exit_code=$EXIT_CODE" >> "$GITHUB_OUTPUT"

if [ $EXIT_CODE -eq 2 ]; then
echo "Watcher infra failure (exit code 2) — report only, no drift issue"
echo "DRIFT_DETECTED=false" >> "$GITHUB_ENV"
echo "INFRA_FAILURE=true" >> "$GITHUB_ENV"
echo "drift=false" >> "$GITHUB_OUTPUT"
elif [ $EXIT_CODE -ne 0 ]; then
echo "Drift detected (exit code $EXIT_CODE)"
echo "DRIFT_DETECTED=true" >> "$GITHUB_ENV"
echo "Critical drift detected (exit code $EXIT_CODE)"
echo "INFRA_FAILURE=false" >> "$GITHUB_ENV"
echo "drift=true" >> "$GITHUB_OUTPUT"
else
echo "No drift detected (exit code 0)"
echo "DRIFT_DETECTED=false" >> "$GITHUB_ENV"
echo "No critical drift (exit code 0)"
echo "INFRA_FAILURE=false" >> "$GITHUB_ENV"
echo "drift=false" >> "$GITHUB_OUTPUT"
fi

- name: Publish Step Summary
if: always()
run: |
Expand All @@ -69,29 +83,30 @@ jobs:
run: |
echo "::error::OpenCode watcher infra failure — see step summary; no drift issue filed."

- name: Open or Update GitHub Issue on Drift
if: env.DRIFT_DETECTED == 'true'
- name: File or Update Critical Drift Issue
if: steps.check.outputs.exit_code == '1'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
LABEL="opencode-drift"
# Ensure label exists in repository
gh label create "$LABEL" --description "Upstream OpenCode drift detected" --color "d73a4a" --force || true
gh label create "$LABEL" --description "Critical upstream OpenCode drift (session-ID/auth format)" --color "d73a4a" --force || true

# Materialize the fallback so gh is always handed a file. A quoted
# "--body <text>" string kept in a variable is word-split and reaches
# gh as a broken argument list.
if [ ! -f drift-report.md ]; then
printf '%s\n' "OpenCode upstream drift detected but drift-report.md is missing. See workflow logs." > drift-report.md
printf '%s\n' "Critical OpenCode upstream drift detected but drift-report.md is missing. See workflow logs." > drift-report.md
fi

# Check for existing open issue with the opencode-drift label
# One issue per open drift: edit its body in place instead of
# commenting on every scheduled run.
EXISTING_ISSUE=$(gh issue list --label "$LABEL" --state open --json number --jq '.[0].number')

if [ -n "$EXISTING_ISSUE" ]; then
echo "Updating existing drift issue #$EXISTING_ISSUE"
gh issue comment "$EXISTING_ISSUE" --body-file drift-report.md
gh issue edit "$EXISTING_ISSUE" --body-file drift-report.md
else
echo "Creating new drift issue"
CURRENT_DATE=$(date -u +'%Y-%m-%d')
Expand All @@ -108,26 +123,44 @@ jobs:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
LABEL="opencode-drift"
# Only a clean run (exit 0) closes the alert: exit 1 is drift and
# exit 2 is a watcher infra failure, where upstream was never read.
# Exit 0 means no critical drift: informational signals may have moved
# (and were re-baselined by --advance), but session format is intact.
# Exit 1 keeps the issue open; exit 2 never reached upstream.
EXISTING_ISSUE=$(gh issue list --label "$LABEL" --state open --json number --jq '.[0].number')
if [ -z "$EXISTING_ISSUE" ]; then
echo "No open $LABEL issue to close"
else
CURRENT_DATE=$(date -u +'%Y-%m-%d %H:%M UTC')
echo "Upstream drift recovered — closing drift issue #$EXISTING_ISSUE"
gh issue comment "$EXISTING_ISSUE" --body "OpenCode upstream drift is back in sync as of ${CURRENT_DATE}. Auto-closing this drift alert."
echo "No critical drift — closing drift issue #$EXISTING_ISSUE"
gh issue comment "$EXISTING_ISSUE" --body "OpenCode upstream is back in sync as of ${CURRENT_DATE}: no critical schema change is outstanding. Auto-closing this drift alert."
gh issue close "$EXISTING_ISSUE" --reason completed
fi

- name: Update State and Commit
if: env.DRIFT_DETECTED == 'true'
- name: Close Drift Issue After Rebaseline
if: github.event.inputs.rebaseline == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
echo "Updating .github/opencode-watch-state.json..."
node scripts/opencode-watch.mjs --update
LABEL="opencode-drift"
EXISTING_ISSUE=$(gh issue list --label "$LABEL" --state open --json number --jq '.[0].number')
if [ -z "$EXISTING_ISSUE" ]; then
echo "No open $LABEL issue to close"
else
CURRENT_DATE=$(date -u +'%Y-%m-%d %H:%M UTC')
echo "Baseline re-established — closing drift issue #$EXISTING_ISSUE"
gh issue comment "$EXISTING_ISSUE" --body "Watcher baseline re-established by a manual rebaseline as of ${CURRENT_DATE}."
gh issue close "$EXISTING_ISSUE" --reason completed
fi

- name: Commit Watcher State
# Advance the committed baseline after any successful read (exit 0 or 1),
# not only when a critical alert fires: informational churn must not be
# re-reported on the next run.
if: github.event.inputs.rebaseline == 'true' || steps.check.outputs.exit_code == '0' || steps.check.outputs.exit_code == '1'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add .github/opencode-watch-state.json
Expand Down
Loading
Loading