mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-30 19:49:14 +00:00
Schema-migration matrix + fuzz harness + RSS budget gate + read-latency
under sync + sync lock regression + tests/heavy convention + nightly CI
workflow + BFS frontier cap on traverseGraph.
CI infra (T1-T7):
- tests/heavy/ directory convention + scripts/run-heavy.sh + bun run test:heavy
- tests/heavy/pg_upgrade_matrix.sh: walk pre-v0.13 + pre-v0.18 brain shapes
forward to head via bootstrap → SCHEMA_SQL → migrations → verifySchema
- test/fuzz/{pure,mixed,filesystem}-validators.test.ts: 1000-run fast-check
property tests across 8 trust-boundary validators
- scripts/check-fuzz-purity.sh: bun-bundle + grep guard, wired into verify
- tests/heavy/measure_rss.sh: in-memory PGLite workload + peak RSS measurement
via /proc/self/status (Linux) or process.memoryUsage().rss fallback (macOS,
refuses to write baseline)
- tests/heavy/read_latency_under_sync.sh: phase A baseline + phase B under
parallel writer load, reports p50/p95/p99 + delta_pct
- tests/heavy/sync_lock_regression.sh: N concurrent gbrain sync against one
DB, asserts 1 winner + N-1 lock-busy + zero leaked gbrain_cycle_locks rows
- .github/workflows/heavy-tests.yml: cron '17 8 * * *' + heavy-tests label
trigger + Postgres service + artifact upload on failure
Engine (T8):
- BrainEngine.traverseGraph opts gain frontierCap?: number + onTruncation?:
(info: TruncationInfo) => void callback. Return shape preserved
(Promise<GraphNode[]>) for MCP wire stability.
- Postgres CTE: parenthesized LIMIT N ORDER BY (slug, id) inside recursive term.
- PGLite: same SQL with positional params.
- Per-call callback closure — not engine-instance state — so concurrent
traversals on the same engine don't cross-talk. 5 contracts pinned in
test/regressions/v0_36_frontier_cap.test.ts.
Three plan-review passes ran before any code: CEO scope review (Approach C),
Eng dual-voice review (Claude subagent + Codex), and Codex 2nd-pass against
the revised plan. The 2nd pass caught issues the first two missed (Bun ESM
vs require.cache; engine-instance metadata stomping under concurrency;
fixture-size inconsistency). All addressed.
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
90 lines
3.3 KiB
YAML
90 lines
3.3 KiB
YAML
name: Heavy Tests
|
|
|
|
# Heavy ops-shape tests under tests/heavy/. Cost minutes per run; NOT part
|
|
# of default PR CI. Two triggers:
|
|
# - Nightly schedule (catches regressions within 24h of merge to master).
|
|
# - On-demand opt-in via PR label `heavy-tests` (slow loop kept off by default).
|
|
# - Manual workflow_dispatch for triage.
|
|
#
|
|
# See CLAUDE.md "tests/heavy/*.sh" entry and tests/heavy/README.md.
|
|
|
|
on:
|
|
schedule:
|
|
- cron: '17 8 * * *' # 08:17 UTC daily — staggered to avoid noisy slots
|
|
pull_request:
|
|
# `synchronize` + `reopened` fire on subsequent pushes / reopens — without
|
|
# them, a PR labeled `heavy-tests` would NEVER re-run heavy on later
|
|
# commits. The job-level `if:` below filters to PRs that still carry the
|
|
# label so we don't fan out on unrelated label changes.
|
|
types: [labeled, synchronize, reopened]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
# When a PR gets the heavy-tests label, cancel any in-flight heavy-tests run on
|
|
# the same ref so we only ever measure the latest commit.
|
|
concurrency:
|
|
group: heavy-tests-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
heavy:
|
|
name: Heavy tests
|
|
# On pull_request: only run when the PR currently carries the `heavy-tests`
|
|
# label. Works for all three trigger types (labeled, synchronize, reopened)
|
|
# because `contains(labels.*.name, ...)` reads the live label set, not the
|
|
# event payload's `label.name` (which is only populated for `labeled`).
|
|
if: |
|
|
github.event_name != 'pull_request' ||
|
|
contains(github.event.pull_request.labels.*.name, 'heavy-tests')
|
|
runs-on: ubuntu-latest
|
|
timeout-minutes: 30
|
|
services:
|
|
postgres:
|
|
image: pgvector/pgvector:pg16
|
|
env:
|
|
POSTGRES_USER: postgres
|
|
POSTGRES_PASSWORD: postgres
|
|
POSTGRES_DB: gbrain_test
|
|
ports:
|
|
- 5432:5432
|
|
options: >-
|
|
--health-cmd pg_isready
|
|
--health-interval 10s
|
|
--health-timeout 5s
|
|
--health-retries 5
|
|
steps:
|
|
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
|
|
with:
|
|
bun-version: latest
|
|
- run: bun install
|
|
|
|
- name: Run heavy tests
|
|
env:
|
|
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/gbrain_test
|
|
run: bun run test:heavy
|
|
|
|
# The heavy runner writes per-script logs to ~/.gbrain/audit/ on every
|
|
# run. Upload those + the rss workload JSON on failure for triage
|
|
# without re-running locally.
|
|
#
|
|
# actions/upload-artifact runs as a node action — `~` is NOT expanded by
|
|
# the shell here. Stage logs into the workspace first, then upload from
|
|
# the stable workspace-relative path.
|
|
- name: Stage heavy-test logs into workspace
|
|
if: always()
|
|
run: |
|
|
mkdir -p heavy-artifacts
|
|
cp -r "$HOME/.gbrain/audit"/heavy-* heavy-artifacts/ 2>/dev/null || true
|
|
cp tests/heavy/rss-baseline.json heavy-artifacts/ 2>/dev/null || true
|
|
- name: Upload heavy-test artifacts
|
|
if: always()
|
|
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
|
|
with:
|
|
name: heavy-tests-${{ github.run_id }}-${{ github.run_attempt }}
|
|
path: heavy-artifacts/
|
|
retention-days: 14
|
|
if-no-files-found: ignore
|