mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-30 03:12:32 +00:00
* feat(doctor): add isSourceUnchangedSinceSync git-head primitive src/core/git-head.ts is a single-responsibility module: probe git HEAD + working-tree clean state for a local_path, compare against the last_commit SHA the DB stored at last sync completion. Designed for reuse (autopilot's per-source dispatch will want the same gate, filed as v0.41.27.1+ TODO). Shell-injection safe: uses execFileSync with array args. The superseded community PR #1564 used execSync through /bin/sh -c with JSON.stringify for shell-escape, which is unsafe — JSON.stringify escapes for JSON, not shell. Fail-open contract: every error path returns false, preserving the caller's prior time-based behavior. Two test seams (_setGitHeadProbeForTests, _setGitCleanProbeForTests) match the last-retrieved.ts precedent so unit tests stay parallel-eligible (no mock.module per CLAUDE.md R2). Companion test suite: 14 cases including a load-bearing shell-injection regression guard that runs real execFileSync against '/nonexistent/$(touch <sentinel>)/repo' and asserts the sentinel file is never created. * feat(doctor): git-aware sync_freshness check + 9 new test cases checkSyncFreshness gains opts.localOnly: boolean. When local CLI caller passes true, doctor short-circuits the staleness warning iff HEAD == sources.last_commit AND working tree is clean AND sources.chunker_version matches CURRENT (mirrors sync.ts:1057+1075's own "do work?" predicate, so doctor and sync agree). Inline SELECT widens to carry last_commit + chunker_version (columns already exist; no schema migration). Three-bucket count math (unchanged_count + synced_recently_count + stale_count === sources.length) populates Check.details for dashboards / JSON consumers. OK-message reshape: - all-unchanged → "All N up to date (no new commits since last sync)" - mixed → "N source(s): X synced recently, Y unchanged since last sync" - all-recent → "All N synced recently" (back-compat). Trust boundary preserved (Codex P0-1): runDoctor (local CLI, trusted) passes localOnly: true; doctorReportRemote (HTTP MCP, untrusted) keeps the default false. Default-false is fail-closed — a future caller that forgets the opt gets the safe no-probe behavior. checkCycleFreshness is INTENTIONALLY NOT touched (Codex P0-2): last_commit == HEAD answers "new commits to sync?" but cannot answer "did the full cycle complete?" — silencing cycle warns on git-clean sources would mask the case where sync ran but extract/embed/ consolidate/synthesize failed. Test coverage: 9 new cases in test/doctor.test.ts including - HEAD-match short-circuit + cold-path message - HEAD-mismatch warn - NULL last_commit (legacy data) → warn - non-git local_path (probe returns null) → warn (fail-open) - 3-source mixed bucket invariant (sum === length) - chunker-version mismatch warn (dirty-tree-clean still gates) - dirty-tree warn (HEAD-match still gates) - D4 regression guard: localOnly=false (default) NEVER calls probes All 87 tests across git-head + doctor + cycle-freshness suites pass. bun run verify clean (28/28 checks). Co-Authored-By: garrytan-agents <me@garrytan.com> * chore: bump version and changelog (v0.41.27.0) Supersedes community PR #1564. Co-Authored-By preserved. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(test): pin gateway to 1536d for query-cache-knobs-hash suite CI failed on the v0.41.27.0 ship after merging origin/master because test/query-cache-knobs-hash.test.ts predates the v0.36.2.0 flip of DEFAULT_EMBEDDING_DIMENSIONS from 1536 → 1280 (ZE Matryoshka). Without an explicit gateway pin, initSchema() sizes query_cache.embedding at halfvec(1280), but the test fixture (makeEmbedding at line 44) emits 1536-dim unit vectors. Result: 5 cases in the "SemanticQueryCache cross-mode isolation (CDX-4 hotfix)" describe crashed with "expected 1280 dimensions, not 1536". Fix mirrors test/consolidate-valid-until.test.ts (the canonical gateway-pin pattern that landed when the default flipped). resetGateway() + configureGateway({embedding_dimensions: 1536}) in beforeAll forces the schema to size at halfvec(1536) regardless of cross-file gateway state. resetGateway() in afterAll restores defaults so the next file in the shard isn't poisoned. Verified: 9/9 cases pass; bun run verify 29/29 clean. --------- Co-authored-by: garrytan-agents <me@garrytan.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
co-authored by
garrytan-agents
Claude Opus 4.7
parent
6ae94301a6
commit
cb1b5f91f7
@@ -19,6 +19,7 @@ import { PGLiteEngine } from '../src/core/pglite-engine.ts';
|
||||
import { SemanticQueryCache, cacheRowId } from '../src/core/search/query-cache.ts';
|
||||
import type { SearchResult } from '../src/core/types.ts';
|
||||
import { knobsHash, resolveSearchMode } from '../src/core/search/mode.ts';
|
||||
import { configureGateway, resetGateway } from '../src/core/ai/gateway.ts';
|
||||
|
||||
let engine: PGLiteEngine;
|
||||
|
||||
@@ -27,6 +28,19 @@ const balancedHash = knobsHash(resolveSearchMode({ mode: 'balanced' }));
|
||||
const tokenmaxHash = knobsHash(resolveSearchMode({ mode: 'tokenmax' }));
|
||||
|
||||
beforeAll(async () => {
|
||||
// v0.36.2.0: DEFAULT_EMBEDDING_DIMENSIONS flipped to 1280 (ZE Matryoshka).
|
||||
// The makeEmbedding fixture below emits 1536-dim unit vectors. If we let
|
||||
// initSchema() inherit the default, query_cache.embedding gets sized at
|
||||
// halfvec(1280) and the inserts throw "expected 1280 dimensions, not 1536".
|
||||
// Pin the gateway to 1536d so this file is hermetic regardless of
|
||||
// gateway state from other tests in the shard. Pattern matches
|
||||
// test/consolidate-valid-until.test.ts.
|
||||
resetGateway();
|
||||
configureGateway({
|
||||
embedding_model: 'openai:text-embedding-3-large',
|
||||
embedding_dimensions: 1536,
|
||||
env: { OPENAI_API_KEY: 'sk-fake' },
|
||||
});
|
||||
engine = new PGLiteEngine();
|
||||
await engine.connect({});
|
||||
await engine.initSchema();
|
||||
@@ -34,6 +48,7 @@ beforeAll(async () => {
|
||||
|
||||
afterAll(async () => {
|
||||
await engine.disconnect();
|
||||
resetGateway();
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
|
||||
Reference in New Issue
Block a user