Files
gbrain/scripts/ship-remote-tests.sh
T
f79c1306a2 v0.41.32.0 fix(staleness): commit-relative sync staleness (supersedes #1623) (#1656)
* fix(staleness): commit-relative sync staleness (HEAD-hash local, durable column remote)

Quiet, fully-caught-up repos no longer false-alarm as SEVERELY STALE in
gbrain doctor / sources status. Staleness now means "is there committed
content the sync hasn't ingested?" not raw wall-clock since the last sync.

- git-head.ts: requireCleanWorkingTree gains 'ignore-untracked' mode (git
  status --porcelain --untracked-files=no). Untracked dirs no longer defeat
  the freshness short-circuit — sync's incremental path keys off the commit
  diff and never imports untracked files, so doctor agrees with sync.
- source-health.ts: newestCommitMs (HEAD committer time) + pure
  lagFromContentMs comparator; computeAllSourceMetrics {probeContent} routes
  local→live commit-hash, remote→stored column. Dead isSourceStale removed.
- migration v108 sources.newest_content_at + fresh-schema blobs.
- sync.ts: writeSyncAnchor stamps newest_content_at atomically with
  last_commit/last_sync_at; buildSyncStatusReport (remote get_status_snapshot)
  reads the column — no git subprocess (v0.41.27.0 trust boundary intact).
- doctor.ts: checkSyncFreshness short-circuit ignores untracked; remote path
  reads the column; clock-skew check stays on raw wall-clock.

Local consumers probe live git (catch HEAD moving to an old-dated commit, which
a timestamp compare would miss); remote consumers read the durable column so a
remote-callable endpoint never shells out to a DB-supplied local_path.

Supersedes #1623 (re-implemented in base repo with the trust boundary preserved).

Co-Authored-By: t <t@t>

* chore(ci): offload tests to on-demand cloud runners from a local CLI

scripts/ship-remote-tests.sh pushes the branch, dispatches the test workflow,
and blocks on `gh run watch --exit-status` — a local caller (human or agent)
awaits the GitHub run exactly like a local `bun run test`, with a real pass/fail
exit code. Frees a load-saturated local machine (many Conductor agents running
their own bun-test suites at once → load avg 120 on 16 cores → PGLite OOM/crawl).

test.yml gains workflow_dispatch so the suite can be triggered from any branch.

* chore: bump version and changelog (v0.41.32.0)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: t <t@t>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-30 10:56:46 -07:00

92 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# ship-remote-tests.sh — run the unit suite on GitHub's on-demand cloud
# runners instead of locally, and block until it finishes with a real
# pass/fail exit code.
#
# WHY: a local machine running many Conductor agents at once gets CPU/memory
# saturated (observed: load avg 120 on 16 cores, ~15 sibling `bun test`
# processes). The PGLite WASM test suite then OOMs (8-shard) or crawls
# (~12min for 1/3 of files vs ~85s normally). The suite already runs on
# GitHub's ephemeral runners on every PR push; this script makes a local
# caller (human or agent, e.g. /ship Step 5) AWAIT that cloud run exactly
# like a local `bun run test` — push, dispatch, `gh run watch --exit-status`.
#
# USAGE:
# scripts/ship-remote-tests.sh [--workflow test.yml] [--branch <name>]
# [--no-push] [--ref <sha>]
#
# EXIT: mirrors the GitHub run — 0 on success, non-zero on failure (so it
# drops into a test gate unchanged). 2 = usage/precondition error.
#
# REQUIRES: `gh` authenticated; the workflow must declare `workflow_dispatch:`
# (test.yml does as of v0.41.32.0).
set -euo pipefail
WORKFLOW="test.yml"
BRANCH=""
DO_PUSH=1
REF=""
while [ $# -gt 0 ]; do
case "$1" in
--workflow) WORKFLOW="$2"; shift 2 ;;
--branch) BRANCH="$2"; shift 2 ;;
--ref) REF="$2"; shift 2 ;;
--no-push) DO_PUSH=0; shift ;;
-h|--help)
sed -n '2,30p' "$0"; exit 0 ;;
*) echo "ship-remote-tests: unknown arg '$1'" >&2; exit 2 ;;
esac
done
command -v gh >/dev/null 2>&1 || { echo "ship-remote-tests: gh CLI not found" >&2; exit 2; }
gh auth status >/dev/null 2>&1 || { echo "ship-remote-tests: gh not authenticated — run 'gh auth login'" >&2; exit 2; }
[ -n "$BRANCH" ] || BRANCH="$(git branch --show-current 2>/dev/null || true)"
[ -n "$BRANCH" ] || { echo "ship-remote-tests: could not determine branch (detached HEAD?) — pass --branch" >&2; exit 2; }
if [ "$DO_PUSH" = "1" ]; then
echo "ship-remote-tests: pushing $BRANCH ..." >&2
git push -u origin "$BRANCH"
fi
# Dispatch against the branch (or an explicit ref). Requires workflow_dispatch
# on the workflow. The HEAD sha lets us disambiguate OUR run from any
# concurrent pull_request run on the same branch.
HEAD_SHA="$(git rev-parse "${REF:-HEAD}")"
echo "ship-remote-tests: dispatching $WORKFLOW on $BRANCH @ ${HEAD_SHA:0:8} ..." >&2
gh workflow run "$WORKFLOW" --ref "${REF:-$BRANCH}" >/dev/null
# Poll for the dispatched run to register (cli/cli#8194: `gh run watch` can
# skip a not-yet-registered run, so we resolve the databaseId ourselves first).
RUN_ID=""
for _ in $(seq 1 30); do
RUN_ID="$(gh run list --workflow "$WORKFLOW" --branch "$BRANCH" \
--event workflow_dispatch --limit 10 \
--json databaseId,headSha,status \
-q "[.[] | select(.headSha==\"$HEAD_SHA\")] | sort_by(.databaseId) | last | .databaseId" 2>/dev/null || true)"
[ -n "$RUN_ID" ] && [ "$RUN_ID" != "null" ] && break
sleep 3
done
if [ -z "$RUN_ID" ] || [ "$RUN_ID" = "null" ]; then
echo "ship-remote-tests: could not find the dispatched run after 90s." >&2
echo " Check manually: gh run list --workflow $WORKFLOW --branch $BRANCH" >&2
exit 2
fi
RUN_URL="$(gh run view "$RUN_ID" --json url -q .url 2>/dev/null || echo "")"
echo "ship-remote-tests: watching run $RUN_ID $RUN_URL" >&2
# Block until the cloud run finishes; mirror its pass/fail as our exit code.
if gh run watch "$RUN_ID" --exit-status; then
echo "ship-remote-tests: PASS $RUN_URL" >&2
exit 0
else
rc=$?
echo "ship-remote-tests: FAIL (exit $rc) $RUN_URL" >&2
echo "--- failed logs ---" >&2
gh run view "$RUN_ID" --log-failed 2>/dev/null | tail -120 >&2 || true
exit "$rc"
fi