mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
* fix: pass sourceId in cycle sync phase to prevent full reimport cycle.ts calls performSync without sourceId, so it always reads the global config.sync.last_commit key instead of the per-source sources.last_commit. When the global anchor gets garbage-collected (after a force push or rebase), sync falls back to a full reimport of all files — on a large brain this takes 30+ minutes and blocks the autopilot cycle. The fix resolves the source id from the brain directory by querying the sources table. When a matching source exists, sync reads the per-source anchor which is updated on every successful sync and stays in sync with the repo history. Falls back gracefully to the global config path for pre-v0.18 brains without a sources table. * v0.22.5: tests + version bump for sync-cycle-source-id fix Adds 6 regression tests in test/core/cycle.test.ts pinning the new resolveSourceForDir() helper added to src/core/cycle.ts in this PR: 1. Seeded sources row → performSync receives matching sourceId 2. No matching row → sourceId=undefined (falls through to global key) 3. Different brainDir than registered source → undefined (no cross-match) 4. sources table missing (very old brain) → catch returns undefined, sync still runs. Uses a fresh PGLiteEngine because initSchema() only re-runs PENDING migrations; DROP TABLE on the shared engine would leave it permanently degraded for every later test in the file. (Codex review caught this landmine.) 5. Multiple rows with same local_path → resolver returns one matching id (non-deterministic; SQL has no ORDER BY). Documents the contract for the v0.23 UNIQUE-constraint follow-up. 6. Empty-string id row → resolver propagates "" (defensive case Codex flagged: schema PK prevents NULL but '' can be inserted). Extends the performSync mock at line 51-65 to also capture sourceId. Bumps: - VERSION: 0.22.4 → 0.22.5 - package.json: 0.22.4 → 0.22.5 - CHANGELOG.md: new [0.22.5] entry following v0.22.4 voice (release summary + numbers table + behavior matrix + To-take-advantage block + itemized changes + for-contributors) - CLAUDE.md: annotates src/core/cycle.ts entry with v0.22.5 (#475) note - llms-full.txt: regenerated via bun run build:llms Test results: - Unit: 28 pass / 0 fail in test/core/cycle.test.ts (22 prior + 6 new) - Full unit suite: pass (exit 0) - E2E: 236 pass / 0 fail across 26 files Plan + codex outside-voice review at: ~/.claude/plans/whimsical-bubbling-goose.md Follow-up TODOs filed for v0.23: - Normalize brainDir + sources.local_path before SQL compare - Add UNIQUE index on sources.local_path - Narrow resolveSourceForDir's catch to PG 42P01 (undefined_table) - Add doctor check for config.sync.last_commit / sources divergence Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: typecheck error in cycle.test.ts test 5 (sourceId regression) CI typecheck failed because `toContain()` on `string[]` rejects the `string | undefined` produced by `syncCalls.at(-1)?.sourceId`'s optional chain. Tests 1, 4, and 6 use `toBe()` which accepts `string | undefined` through its overload, but `toContain()` is stricter. Fix: pull the value into a typed variable, assert it's defined, then check membership. Makes the contract explicit ("resolver returned a defined sourceId, and it was one of the matching ids") instead of relying on a silent undefined → no-match-in-array assertion. Locally: - bun run typecheck: clean - bun test test/core/cycle.test.ts: 28 pass / 0 fail (75 expect calls) - All CI gate scripts: OK (jsonb, progress-to-stdout, wasm-embedded) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * ci: add --timeout=60000 to E2E runner to prevent setupDB flake PR #475's Tier 1 (Mechanical) CI job hit a 5000.09ms beforeAll hook timeout in `E2E: Tags > (unnamed)`. Cause: scripts/run-e2e.sh invokes `bun test "$f"` without a --timeout flag, falling back to bun's 5s default. setupDB() does TRUNCATE CASCADE on ~30 tables, and on a CI runner under load that can exceed 5s. Match what the unit suite uses (--timeout=60000 in package.json's "test" script). Same 1m ceiling, no behavior change for healthy runs; just removes the artificial 5s floor on hooks. Verified locally: bun test --timeout=60000 test/e2e/mechanical.test.ts runs 78 pass / 0 fail in 27.99s against a fresh pgvector pg16 docker container. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: root <root@localhost> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
72 lines
2.4 KiB
Bash
Executable File
72 lines
2.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Run E2E tests ONE FILE AT A TIME.
|
|
#
|
|
# Bun's default is to run test files in parallel (each in its own worker).
|
|
# Our E2E suite shares one Postgres database across all 13 files, and
|
|
# `setupDB()` does TRUNCATE CASCADE + fixture import. When files run in
|
|
# parallel, file A's TRUNCATE can race with file B's fixture import,
|
|
# producing observed fails like "expected 16 pages, got 8", missing
|
|
# links, orphaned timeline entries, etc. The flakiness was visible on
|
|
# ~3 of every 5 runs pre-fix.
|
|
#
|
|
# Running files sequentially eliminates the race entirely. It also costs
|
|
# some startup overhead (each file spins up a fresh bun process) but for
|
|
# a suite this size that is measured in ~1-2s per file, amortized under
|
|
# the natural per-file test time of 5-10s.
|
|
#
|
|
# Exits non-zero on the first failing file so CI fails fast.
|
|
#
|
|
# `--timeout=60000` matches the unit test suite. Bun's default is 5s,
|
|
# which is too tight for setupDB's TRUNCATE CASCADE on ~30 tables on
|
|
# CI runners under load (one CI flake observed on PR #475 hitting
|
|
# exactly 5000.09ms in the Tags beforeAll).
|
|
|
|
set -euo pipefail
|
|
|
|
cd "$(dirname "$0")/.."
|
|
|
|
pass_files=0
|
|
fail_files=0
|
|
fail_list=()
|
|
total_pass=0
|
|
total_fail=0
|
|
|
|
for f in test/e2e/*.test.ts; do
|
|
name=$(basename "$f")
|
|
echo ""
|
|
echo "=== $name ==="
|
|
if output=$(bun test --timeout=60000 "$f" 2>&1); then
|
|
pass_files=$((pass_files + 1))
|
|
# Extract pass/fail counts from bun's summary (e.g., "123 pass")
|
|
p=$(echo "$output" | grep -oE '[0-9]+ pass' | tail -1 | grep -oE '[0-9]+' || echo 0)
|
|
total_pass=$((total_pass + p))
|
|
echo "$output" | tail -8
|
|
else
|
|
fail_files=$((fail_files + 1))
|
|
fail_list+=("$name")
|
|
p=$(echo "$output" | grep -oE '[0-9]+ pass' | tail -1 | grep -oE '[0-9]+' || echo 0)
|
|
fl=$(echo "$output" | grep -oE '[0-9]+ fail' | tail -1 | grep -oE '[0-9]+' || echo 0)
|
|
total_pass=$((total_pass + p))
|
|
total_fail=$((total_fail + fl))
|
|
echo "$output"
|
|
echo ""
|
|
echo "FAILED: $name"
|
|
# Continue so we see all failures; exit nonzero at the end.
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
echo "========================================"
|
|
echo "E2E SUMMARY (sequential execution)"
|
|
echo "========================================"
|
|
echo "Files: $((pass_files + fail_files)) total, $pass_files passed, $fail_files failed"
|
|
echo "Tests: $total_pass passed, $total_fail failed"
|
|
if [ ${#fail_list[@]} -gt 0 ]; then
|
|
echo ""
|
|
echo "Failing files:"
|
|
for f in "${fail_list[@]}"; do
|
|
echo " - $f"
|
|
done
|
|
exit 1
|
|
fi
|