mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
docs: post-release reference-doc sync for v0.42.59.0
Cross-referenced the v0.42.59.0 five-fix rollup (#2735-#2739) against the reference docs and updated every entry that no longer described current behavior: - KEY_FILES.md: migrate-engine.ts (source-catalog copy + target-aware resume manifest), pglite/postgres bootstrap probe set (timeline_entries.event_page_id), searchTakes/searchTakesVector source scope, think op scope threading through runGather via thinkSourceScopeOpts, new fence-shared.ts entry (escape-aware parseRowCells as escapeFenceCell's inverse). - TESTING.md: one-liners for the three new e2e suites (think-source-isolation-pglite, facts-fence-reconcile-postgres, migrate-engine-sources-postgres) + the new multi-source-bug-class case. - TODOS.md: new v0.42.59.0 follow-ups section (6 items); refreshed the two existing items the wave partially resolved (think gather scope plumbing, #2200 takes_search engine-layer scope). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
5008b287e4
commit
869223f3b3
@@ -1,5 +1,54 @@
|
||||
# TODOS
|
||||
|
||||
## v0.42.59.0 follow-ups (five-fix rollup #2735–#2739)
|
||||
|
||||
Filed as follow-ups from v0.42.59.0 (bootstrap probe for
|
||||
`timeline_entries.event_page_id`, migrate-engine source catalog + target-aware
|
||||
resume, entity-resolution quarantine, escape-aware fence cells, think gather
|
||||
source scope).
|
||||
|
||||
- [ ] **P2 — schema-bootstrap-coverage strip block never exercises `timeline_entries.event_page_id`.**
|
||||
The guard's pre-migration-brain simulation (the strip DDL in
|
||||
`test/schema-bootstrap-coverage.test.ts`) has no
|
||||
`ALTER TABLE timeline_entries DROP COLUMN IF EXISTS event_page_id` (or FK drop), so the
|
||||
coverage entry added for the v121 forward reference is vacuous — the probe never fires
|
||||
under that harness. The real regression guard lives in `test/bootstrap.test.ts` (which
|
||||
does drop → re-bootstrap → assert). Add the DROP statements to the strip block so the
|
||||
coverage test genuinely exercises its own entry.
|
||||
- [ ] **P2 — extract-facts reconcile still wipes-then-reinserts when the parse emitted MALFORMED warnings.**
|
||||
`runExtractFacts` (`src/core/cycle/extract-facts.ts`) deletes a page's facts and
|
||||
reinserts from the parsed fence even when `parseFactsFence` surfaced
|
||||
`FACTS_TABLE_MALFORMED` warnings — any future parse defect becomes a deletion vector
|
||||
(rows the parser failed to read get wiped with nothing to reinsert). Consider
|
||||
skip-wipe-on-warnings: treat a warning-bearing parse as non-authoritative for that page
|
||||
(skip the wipe, surface a warn), mirroring the empty-fence legacy-row guard's posture.
|
||||
- [ ] **P3 — bare-name resolution quarantines even on an exact unique match when prefix siblings exist.**
|
||||
With pages `companies/acme` + `companies/acme-labs`, a bare `"Acme"` yields two
|
||||
`findPrefixCandidates` rows, so `tryUnambiguousPrefixExpansion` declines — even though
|
||||
`companies/acme` is an exact `dir/token` slug match (and may be a unique exact title
|
||||
match). That's an unambiguity signal being wasted. Consider promoting an exact
|
||||
`dir/token` (or exact-title) hit above the sibling-count check in
|
||||
`src/core/entities/resolve.ts`.
|
||||
- [ ] **P2 — `scripts/run-verify-parallel.sh` no-gtimeout fallback reports the watchdog's exit code, not the check's.**
|
||||
In the fallback branch, `rc=$?` is captured after `wait "$cap_pid"` (the killed
|
||||
sleep-watchdog, rc=143) rather than after `wait "$pid"` (the actual check) — on a Mac
|
||||
without coreutils every check false-fails with rc=143. Capture `rc` from `wait "$pid"`
|
||||
first, then reap the watchdog.
|
||||
- [ ] **P3 — same-target migrate resume with `--force` still skips checkpointed pages after the wipe.**
|
||||
`gbrain migrate --to <engine> --force` wipes the target's pages, but the resume
|
||||
manifest's `completed_slugs` filter still applies, so previously-checkpointed pages are
|
||||
skipped against the now-empty target (pre-existing behavior; the v0.42.59.0 verification
|
||||
warns about it). `--force` should clear the manifest when it matches the same target.
|
||||
Where: `src/commands/migrate-engine.ts`.
|
||||
- [ ] **P2 — think residual scope gaps.** Two spots in `src/core/think/index.ts` don't yet
|
||||
inherit the caller's source scope the way the gather stage now does:
|
||||
`persistCitations` resolves citation slugs with an unscoped
|
||||
`SELECT id FROM pages WHERE slug = $1 LIMIT 1` (cross-source slug ambiguity can attach
|
||||
saved evidence to the wrong same-slug page), and the trajectory entity-resolution scalar
|
||||
is `opts.sourceId ?? 'default'` (a federated caller with `allowedSources` but no scalar
|
||||
resolves entities against `default` instead of its grant). Mirror the gather-stage
|
||||
precedence (federated array > scalar > default) at both sites.
|
||||
|
||||
## provider-agnostic follow-ups (filed v0.42.58.0)
|
||||
|
||||
Deferred from the provider-agnostic plumbing wave (#1249/#1250/#1292/#2271/#2209).
|
||||
@@ -170,7 +219,10 @@ job) and sync. See CLAUDE.md "Pace Mode".
|
||||
`sourceScopeOpts`) and `code_def` (`operations.ts:4155` — brain-wide raw SQL over
|
||||
`content_chunks`; confirm whether brain-wide is intentional before scoping). A remote
|
||||
federated client (grant set, dispatch-default `ctx.sourceId='default'`) reads these against
|
||||
`default` or unscoped, not its grant.
|
||||
`default` or unscoped, not its grant. *(Partially done by v0.42.59.0: the engine methods
|
||||
`searchTakes`/`searchTakesVector` now accept the source-scope predicates and the `think`
|
||||
gather path threads them; the standalone `takes_search` op handler still doesn't route
|
||||
through `sourceScopeOpts(ctx)`.)*
|
||||
- **Why:** same cross-source correctness/isolation class #2200 targets; a federated client
|
||||
can't read chunks/raw-data/versions for an authorized non-default source, `resolve_slugs`
|
||||
can fuzzy-resolve across all sources, and `takes_search`/`code_def` query without the grant.
|
||||
@@ -912,7 +964,7 @@ default-off; these are the gates and extensions before any default flip.
|
||||
|
||||
- [ ] **v0.42+: cross-surface ablation before flipping `search.adaptive_return` default.** The gate ships default-off. Before turning it on in any `MODE_BUNDLES` tier, run the recall ablation (adaptive off vs on, recall-preserving caps) across `gbrain eval longmemeval`, `gbrain eval whoknows`, `gbrain eval suspected-contradictions`, and the BrainBench-Real replay (sibling gbrain-evals repo). Confirm recall@k / answer quality does not regress; pick the safe caps; probably flip `tokenmax` first (broadest searchLimit, most noise). On-surface evidence (the PrecisionMemBench precision/recall frontier: off 0.076/0.99, e1/o2 0.40/0.91, e1/o1 0.58/0.82) is recorded in `gbrain-evals/docs/benchmarks/2026-05-29-precisionmembench.md`. Priority: P2.
|
||||
- [ ] **v0.42+: fold adaptive-return params into KNOBS_HASH so adaptive-on calls can cache.** v0.41.33.0 skips `hybridSearchCached` entirely when the gate is on (cache-safe but cache-cold). Fold `adaptive_return` enabled + caps + `minKeep` into `knobsHash()` (append-only, bump `KNOBS_HASH_VERSION`) so a gate-on write segregates from a gate-off row and adaptive calls cache correctly. Required before any default flip (else default-on means cache-cold everywhere). See `src/core/search/mode.ts` KNOBS_HASH parts + `return-policy.ts`. Priority: P2 (paired with the default-flip ablation above).
|
||||
- [ ] **v0.42+: gentle adaptive gate on `think`'s gather stage (A3).** The plan's A3 decision was a gentler return-gate on `runThink`'s gather candidates (cleaner context, fewer tokens per reasoning call). Deferred because the benefit is unvalidated without a longmemeval answer-quality run, and trimming the answer path (even default-off) carries regression risk. gather fuses 4 streams (page / takes-keyword / takes-vector / graph); the gate must operate on the fused output with a higher min-keep than search, validated on `gbrain eval longmemeval` answer quality (not retrieval precision). Also: `RunThinkOpts` has no `sourceId` today, so think's gather runs unscoped (codex finding) — scope-isolated think needs that plumbing first. Priority: P2.
|
||||
- [ ] **v0.42+: gentle adaptive gate on `think`'s gather stage (A3).** The plan's A3 decision was a gentler return-gate on `runThink`'s gather candidates (cleaner context, fewer tokens per reasoning call). Deferred because the benefit is unvalidated without a longmemeval answer-quality run, and trimming the answer path (even default-off) carries regression risk. gather fuses 4 streams (page / takes-keyword / takes-vector / graph); the gate must operate on the fused output with a higher min-keep than search, validated on `gbrain eval longmemeval` answer quality (not retrieval precision). *(The scope plumbing this was gated on landed in v0.42.59.0: `RunThinkOpts` carries `sourceId`/`allowedSources` and `runGather` threads the scope through every stream, so the gate work no longer blocks on it.)* Priority: P2.
|
||||
- [ ] **v0.42+: `--explain` human header for adaptive_return.** The decision is in `HybridSearchMeta.adaptive_return` and surfaces in `--json` today. The per-result `explain-formatter.ts` is result-scoped and can't render a per-query meta line; the human `gbrain search --explain` header needs the meta threaded through `cli.ts:formatResult` (it currently only receives `results`). Add a one-line gate-decision header (intent / cap / kept of total). Priority: P3.
|
||||
- [ ] **v0.42+: structured-alias / facts-mode fidelity for the PrecisionMemBench eval.** The gbrain-evals benchmark seeds beliefs as pages with aliases in the body (real FTS). A second fidelity that exercises gbrain's structured alias/entity-resolution layer (facts with `valid_until` + entity resolution) would measure gbrain's structured-belief path on the 23 alias cases. Lives in gbrain-evals (`eval/precisionmembench/seed.ts` throws on `fidelity:'structured'` today). Priority: P3.
|
||||
|
||||
|
||||
+4
-1
@@ -239,8 +239,11 @@ E2E tests live in `test/e2e/` and run against real Postgres+pgvector (require `D
|
||||
- `test/e2e/http-transport.test.ts` — `gbrain serve --http` end-to-end against real Postgres: bearer auth round-trip, `last_used_at` SQL-level debounce, `mcp_request_log` row insertion on success and auth_failed paths, `/health` DB-down → 503 (DB-probing health check), and the dispatch round-trip with a real operation. Skips without `DATABASE_URL`.
|
||||
- `test/e2e/serve-http-oauth.test.ts` — real-Postgres E2E against `gbrain serve --http` with full OAuth 2.1. Spawns a subprocess server, registers a client via the CLI, mints `client_credentials` tokens, exercises the `/mcp` JSON-RPC pipeline. Real DCR `/register` HTTP-level response-shape test (asserts `typeof body.client_id_issued_at === 'number'` over the wire, RFC 7591 §3.2.1); real CLI subprocess test for `revoke-client` (registers → mints token → revokes via `execSync` → asserts token rejected at `/mcp` → asserts re-run exits 1); server fixture flips on `--enable-dcr` so `/register` is reachable. **bun execSync env-inheritance contract:** bun's `execSync` does NOT inherit env mutations done via `process.env.X = ...`, only OS-level env from before bun started. helpers.ts loads `.env.testing` and sets `DATABASE_URL` via `process.env` mutation, which is invisible to subprocesses unless `env: { ...process.env }` is passed explicitly — every subprocess call in this file passes `env: { ...process.env }`. Reference fix for the same failure mode in sibling sync/cycle/dream/claw-test E2Es. `afterAll` cleanup is guarded on `clientId` (won't throw if `beforeAll` failed before registration); cleanup errors surface to stderr without throwing so real test failures aren't masked. Also covers the trust-boundary fix: an HTTP MCP `submit_job` for `name: "shell"` MUST reject with a permission error (request handler sets `remote: true` and `submit_job`'s protected-name guard fires), and the same guard rejects subagent submission. Skips without `DATABASE_URL`.
|
||||
- `test/e2e/sync-parallel.test.ts` — `DATABASE_URL`-gated. 60-file Postgres sync at concurrency=4 imports all + no connection leak (probes `pg_stat_activity` before/after to confirm worker engines disconnected). 120-file serial-vs-parallel benchmark prints `SYNC_PARALLEL_BENCH N files | serial=Xms | parallel(4)=Yms | speedup=Zx`. Asserts parallel ≤ serial × 1.5 (CI-noise tolerant; not a strict speedup gate).
|
||||
- `test/e2e/multi-source-bug-class.test.ts` — PGLite in-memory regression suite pinning every multi-source bug site: `listAllPageRefs` ordering by `(source_id, slug)`, `getPage` with sourceId picks the right `(source, slug)` row, `extract-takes` processes both overlapping `people/alice` rows independently, `listPages` filters correctly with `PageFilters.sourceId`, `addLinksBatch` with `from/to_source_id` targets the right rows, `validateSourceId` rejects path traversal, reverse-write disk layout uses `brainDir/.sources/<id>/<slug>.md` for non-default sources. No `DATABASE_URL` needed. Wired into `scripts/e2e-test-map.ts` so changes to extract-takes / patterns / synthesize / embed / extract / migrate-engine auto-trigger it.
|
||||
- `test/e2e/multi-source-bug-class.test.ts` — PGLite in-memory regression suite pinning every multi-source bug site: `listAllPageRefs` ordering by `(source_id, slug)`, `getPage` with sourceId picks the right `(source, slug)` row, `extract-takes` processes both overlapping `people/alice` rows independently, `listPages` filters correctly with `PageFilters.sourceId`, `addLinksBatch` with `from/to_source_id` targets the right rows, `validateSourceId` rejects path traversal, reverse-write disk layout uses `brainDir/.sources/<id>/<slug>.md` for non-default sources, `copyMigrationSources` lands source metadata before overlapping-slug pages. No `DATABASE_URL` needed. Wired into `scripts/e2e-test-map.ts` so changes to extract-takes / patterns / synthesize / embed / extract / migrate-engine auto-trigger it.
|
||||
- `test/e2e/migrate-engine-sources-postgres.test.ts` — `DATABASE_URL`-gated companion for `gbrain migrate --to`: migrates a PGLite brain carrying two non-default sources with overlapping slugs into real Postgres and asserts `copyMigrationSources` created every `sources` FK parent (config JSONB intact, not double-encoded) before any page write. Unit-level manifest identity (crash manifest resumes only against the SAME target; legacy engine-only manifests start fresh) is `test/migrate-engine-resume.test.ts`.
|
||||
- `test/e2e/facts-fence-reconcile-postgres.test.ts` — `DATABASE_URL`-gated round-trip for the escape-aware fence parser: renders a `## Facts` fence whose cells carry literal pipes, backslashes (Windows paths), and empty cells via `renderFactsTable`, runs the wipe-and-reinsert reconcile (`runExtractFacts`) on real Postgres, and asserts every cell survives byte-identically with no column shift.
|
||||
- `test/e2e/source-isolation-pglite.test.ts` — PGLite in-memory regression suite pinning the source-isolation seal at two layers. Engine layer: `searchKeyword` / `searchVector` / `searchKeywordChunks` / `listPages` / `getPage` / `traverseGraph` / `traversePaths` apply `sourceId` (scalar fast path) and `sourceIds` (array path) correctly across both engines. Op-handler layer: routes through `sourceScopeOpts(ctx)` so a `read+write`-scoped OAuth client bound to `--source dept-x` cannot see rows from neighboring sources via `search`, `query`, `list_pages`, `get_page`, or `find_experts`. Covers both `ctx.sourceId` (single-source clients) and `ctx.auth.allowedSources` (federated_read clients) precedence; federated array wins over scalar wins over nothing. No `DATABASE_URL` needed.
|
||||
- `test/e2e/think-source-isolation-pglite.test.ts` — PGLite in-memory suite pinning the `think` gather stage's source scope: seeds three sources with cross-source links and embedded takes, then asserts `runGather` under a federated `sourceIds` grant (and under a scalar `sourceId`) keeps every stream — hybrid retrieval, takes keyword + vector (`searchTakes`/`searchTakesVector`), and the `traversePaths` graph walk — inside the grant while still reaching authorized neighboring sources. No `DATABASE_URL` needed.
|
||||
- `test/e2e/skill-brain-first.test.ts` — doctor reports `skill_brain_first` check with structured issues; `--fix --dry-run` previews insertion without writing; `--fix` applies the canonical Convention callout idempotently; `brain_first: exempt` frontmatter resolves the warn; `brain_first_typo` surfaces a paste-ready hint; audit JSONL records `detected` / `resolved` / `fixed` transitions; stable brain emits 0 audit lines/run.
|
||||
- Tier 2 (`test/e2e/skills.test.ts`) requires OpenClaw + API keys, runs nightly in CI.
|
||||
- If `.env.testing` doesn't exist in this directory, check sibling worktrees: `find ../ -maxdepth 2 -name .env.testing -print -quit` and copy it here if found.
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user