From 6dcbb7ed9ba9437e7cb7ddc8d577f3128d4cca6c Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Wed, 27 May 2026 07:41:38 -0700 Subject: [PATCH] =?UTF-8?q?chore:=20bump=20version=20to=20v0.42.0.0=20(MIN?= =?UTF-8?q?OR=20=E2=80=94=20significant=20new=20feature)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 ++++---- CLAUDE.md | 2 +- VERSION | 2 +- llms-full.txt | 2 +- package.json | 2 +- src/commands/jobs.ts | 4 ++-- src/core/minions/protected-names.ts | 2 +- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a3f047118..3d427cd82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to GBrain will be documented in this file. -## [0.41.23.0] - 2026-05-27 +## [0.42.0.0] - 2026-05-27 **Your skills now improve themselves overnight.** @@ -10,7 +10,7 @@ GBrain ships 47 bundled skills that tell agents how to handle specific kinds of tasks. Until now, those skills only got better when a human rewrote them. A human can read three or four execution traces and spot a problem; nobody can read forty execution traces and spot which exact rule is hurting and -which is helping. v0.41.23.0 closes that loop. You write a benchmark of +which is helping. v0.42.0.0 closes that loop. You write a benchmark of realistic tasks, and `gbrain skillopt ` watches the agent run those tasks against your current skill text, proposes specific edits, re-tests, and only keeps changes that measurably improve the score. @@ -83,7 +83,7 @@ A typical 20-task benchmark with defaults costs ~$0.90 per run. `~/.gbrain/audit/skillopt-YYYY-Www.jsonl` (ISO-week rotated). `gbrain doctor` will surface failed runs (when the doctor check ships in v0.42). -### Cathedral fully ships in v0.41.23.0 +### Cathedral fully ships in v0.42.0.0 Every originally-deferred follow-up is included: @@ -130,7 +130,7 @@ Every originally-deferred follow-up is included: - Sweep all 47 bundled skills with their own `skillopt-benchmark.jsonl` fixtures (one PR per ~5 skills; manual benchmark authoring required) -## To take advantage of v0.41.23.0 +## To take advantage of v0.42.0.0 `gbrain upgrade` should do this automatically. To try the new command: diff --git a/CLAUDE.md b/CLAUDE.md index 5c2b9e319..fd72bbc8b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -247,7 +247,7 @@ strict behavior when unset. - `src/commands/whoknows.ts` (v0.33) — `gbrain whoknows [--explain] [--limit N] [--json]`: expertise + relationship-proximity routing. Mirrors v0.29 salience/anomalies shape (pure `rankCandidates()` + `findExperts()` orchestrator + `runWhoknows()` CLI dispatch + thin-client routing). MCP op = `find_experts` (scope: read, localOnly: false) per ENG-D5. Ranking formula (ENG-D1 locked): `score = log(1 + raw_match) × max(0.1, exp(-days/180)) × (0.5 + 0.5 × salience)` where `raw_match` is hybridSearch's RRF+source-boost score. Filters at SQL via the new `SearchOpts.types: ['person', 'company']` (no post-filter waste). hybridSearch's internal salience+recency boosts are intentionally disabled — the locked formula applies on a clean signal. Floors prevent multiplicative-zero edge cases (cold-start people stay visible); ties break alphabetically by slug for determinism. 16 unit tests in `test/whoknows.test.ts` pin the math. - `src/commands/eval-whoknows.ts` (v0.33, v0.33.1.3 thin-client wiring) — `gbrain eval whoknows [--json] [--skip-replay]`: two-layer eval gate (ENG-D2). Layer 1 quality (hand-labeled fixture, top-3 hit rate ≥ 0.8). Layer 2 regression (`eval_candidates` replay set-Jaccard@3 ≥ 0.4). Sparseness fallback: < 20 replay-eligible rows → Layer 2 auto-skips with stderr warning. Stable JSON envelope with `schema_version: 1`. Exit 0/1/2 for pass/fail/usage so CI can gate. Mirrors v0.27.x cross-modal + v0.28.1 longmemeval dispatch shape under `src/commands/eval.ts`. **v0.33.1.3:** `WhoknowsFn` callable abstraction lets the gates be impl-agnostic. `runEvalWhoknows(engine: BrainEngine | null, args)` picks the impl at entry — thin-client mode (`isThinClient(cfg)`) routes per-query through `callRemoteTool(cfg, 'find_experts', {topic, limit})` via the v0.31.1 seam; local mode calls `findExperts(engine, ...)` directly. cli.ts adds a thin-client bypass before `connectEngine` for `gbrain eval whoknows`, matching the longmemeval/cross-modal no-DB pattern. Regression gate auto-skips in thin-client mode (no DB access to `eval_candidates`). Public exports `jaccardAtK`, `topKHit`, `readFixture`, `WhoknowsFn`, threshold constants are pinned by `test/eval-whoknows.test.ts` (25 cases, +2 for the null-engine signature contract). - `test/fixtures/whoknows-eval.jsonl` (v0.33) — 10-row synthetic placeholder demonstrating the eval-fixture schema (`{query, expected_top_3_slugs, notes?}` JSONL). End users replace with their own real queries before shipping; the placeholder uses obviously-example slugs (`wiki/people/example-alice`) so production data isn't conflated with the test fixture. Drives `test/e2e/whoknows.test.ts` (which seeds a matching synthetic brain and asserts the >=80% gate) and the `whoknows_health` doctor check. -- `src/core/skillopt/` + `src/commands/skillopt.ts` + `skills/skill-optimizer/` (v0.41.23.0 SkillOpt wave, closes #1481) — self-evolving skill optimization grounded in the SkillOpt paper (arXiv 2605.23904, Microsoft Research, May 2026). Top-level CLI `gbrain skillopt ` treats `SKILL.md` as trainable parameters of a frozen agent; validation-gated (D12 median-of-3 + epsilon=0.05), budget-capped (D3 preflight estimator), per-skill DB-locked (D14 `tryAcquireDbLock('skillopt:', 60min)`), atomic-versioned (D8 history-intent-first 5-step commit), body-only mutations (D5 — frontmatter forbidden). Rollouts use `gateway.toolLoop` directly with no-op persistence callbacks (D2 — zero `subagent_messages` pollution) + a read-only tool allowlist derived from `BRAIN_TOOL_ALLOWLIST` minus `put_page`/`submit_job`/`file_upload` (D13). Two reflect calls per step (D7 paper-faithful). Rejected-edit buffer LRU-bounded to 100 entries. Bundled-skill gate (D16). Bootstrap workflow (D15 sentinel + `--bootstrap-reviewed`). D17 D_sel floor (>=5 with `--split` override). Audit JSONL via shared `audit-writer.ts`. Added to `ALL_PHASES` after `patterns` (default OFF; opt-in via `gbrain config set cycle.skillopt.enabled true`); cycle phase wrapper at `src/core/skillopt/cycle-phase.ts` walks stale skills with per-skill ($0.50) + brain-wide ($2.00) caps. Added to `PROTECTED_JOB_NAMES`. Full cathedral ships: F1 dream-cycle phase wrapper, F2 41-case adversarial test suite (6 files), F3 E2E PGLite serial test (3 cases), F4 `--all` batch mode (`src/core/skillopt/batch.ts:runBatchAll`), F5 `--target-models` fleet (`runFleet` parallel per-model receipts under `skillopt/fleet//`), F6 MCP op `run_skillopt` (admin scope + per-skill `skillopt.allowed_skills` allowlist, NOT localOnly), F7 Minion `skillopt` handler + `--background` CLI flag with `allowProtectedSubmit: true`, F8 reflect-prompt quality eval at `evals/skillopt-reflect/`, F9 judge LLM accuracy eval at `evals/skillopt-judge/`, F10 write-flavored optimization via `src/core/skillopt/write-capture.ts:buildWriteCaptureRegistry` (virtual `put_page`/`submit_job`/`file_upload` captured in-memory; `--write-capture` flag), F11 held-out real-user test set scaffold via `src/core/skillopt/held-out.ts` (capture infra at `~/.gbrain/skillopt-captures//.jsonl`, `--held-out ` flag, `runHeldOutGate` candidate >= baseline). Pinned by 152 tests across 18 files (88 foundation + 41 adversarial + 23 v2 surface + 3 E2E PGLite serial); hermetic via DI seams (`opts.chatFn` for optimizer + judge; `opts.toolLoopFn` for rollouts; no `mock.module`, R2-compliant). Plan + 17 review decisions + outside-voice codex absorption at `~/.claude/plans/system-instruction-you-are-working-drifting-falcon.md`. v0.42+ remaining: admin UI Calibration-style dashboard tab for optimizer history; sweep all 47 bundled skills with their own `skillopt-benchmark.jsonl` fixtures (manual benchmark authoring). +- `src/core/skillopt/` + `src/commands/skillopt.ts` + `skills/skill-optimizer/` (v0.42.0.0 SkillOpt wave, closes #1481) — self-evolving skill optimization grounded in the SkillOpt paper (arXiv 2605.23904, Microsoft Research, May 2026). Top-level CLI `gbrain skillopt ` treats `SKILL.md` as trainable parameters of a frozen agent; validation-gated (D12 median-of-3 + epsilon=0.05), budget-capped (D3 preflight estimator), per-skill DB-locked (D14 `tryAcquireDbLock('skillopt:', 60min)`), atomic-versioned (D8 history-intent-first 5-step commit), body-only mutations (D5 — frontmatter forbidden). Rollouts use `gateway.toolLoop` directly with no-op persistence callbacks (D2 — zero `subagent_messages` pollution) + a read-only tool allowlist derived from `BRAIN_TOOL_ALLOWLIST` minus `put_page`/`submit_job`/`file_upload` (D13). Two reflect calls per step (D7 paper-faithful). Rejected-edit buffer LRU-bounded to 100 entries. Bundled-skill gate (D16). Bootstrap workflow (D15 sentinel + `--bootstrap-reviewed`). D17 D_sel floor (>=5 with `--split` override). Audit JSONL via shared `audit-writer.ts`. Added to `ALL_PHASES` after `patterns` (default OFF; opt-in via `gbrain config set cycle.skillopt.enabled true`); cycle phase wrapper at `src/core/skillopt/cycle-phase.ts` walks stale skills with per-skill ($0.50) + brain-wide ($2.00) caps. Added to `PROTECTED_JOB_NAMES`. Full cathedral ships: F1 dream-cycle phase wrapper, F2 41-case adversarial test suite (6 files), F3 E2E PGLite serial test (3 cases), F4 `--all` batch mode (`src/core/skillopt/batch.ts:runBatchAll`), F5 `--target-models` fleet (`runFleet` parallel per-model receipts under `skillopt/fleet//`), F6 MCP op `run_skillopt` (admin scope + per-skill `skillopt.allowed_skills` allowlist, NOT localOnly), F7 Minion `skillopt` handler + `--background` CLI flag with `allowProtectedSubmit: true`, F8 reflect-prompt quality eval at `evals/skillopt-reflect/`, F9 judge LLM accuracy eval at `evals/skillopt-judge/`, F10 write-flavored optimization via `src/core/skillopt/write-capture.ts:buildWriteCaptureRegistry` (virtual `put_page`/`submit_job`/`file_upload` captured in-memory; `--write-capture` flag), F11 held-out real-user test set scaffold via `src/core/skillopt/held-out.ts` (capture infra at `~/.gbrain/skillopt-captures//.jsonl`, `--held-out ` flag, `runHeldOutGate` candidate >= baseline). Pinned by 152 tests across 18 files (88 foundation + 41 adversarial + 23 v2 surface + 3 E2E PGLite serial); hermetic via DI seams (`opts.chatFn` for optimizer + judge; `opts.toolLoopFn` for rollouts; no `mock.module`, R2-compliant). Plan + 17 review decisions + outside-voice codex absorption at `~/.claude/plans/system-instruction-you-are-working-drifting-falcon.md`. v0.42+ remaining: admin UI Calibration-style dashboard tab for optimizer history; sweep all 47 bundled skills with their own `skillopt-benchmark.jsonl` fixtures (manual benchmark authoring). - `src/core/brainstorm/{domain-bank,orchestrator,judges}.ts` + `src/commands/{brainstorm,lsd,eval-brainstorm}.ts` + `src/core/last-retrieved.ts` (v0.37.0 Open Collider wave) — bisociation-grounded idea generation pair: `gbrain brainstorm ` (defensible, cite-heavy, 4 close × 6 far, judge threshold 4.0/5, save by default) and `gbrain lsd ` (Lateral Synaptic Drift — inverted judge that rejects ideas with resistance >4.5 ("too obvious"), stale-page bias via `pages.last_retrieved_at`, 2 close × 12 far, axiomatic inversions required, ephemeral by default). The architecture corrects Open Collider's training-data-grounded approach: gbrain has the user's actual cross-domain knowledge already, so the "domain bank" is prefix-stratified sampling from the user's own brain (`SELECT DISTINCT substring(slug from '^[^/]+/[^/]+')` cached 1h-TTL in `config` table per source) tiebroken by `JOIN page_links` connection_count, with corpus-sampling fallback when fewer prefixes than M exist. Distance scores normalized to [0,1] via `1 - clamp(cosine_distance, 0, 2) / 2` (1=opposite, 0=identical). The judge is a single `judges.ts` with `runJudge(config, ideas)` + two exported configs (`BRAINSTORM_JUDGE_CONFIG` weighted originality/resistance/thesis_density/concrete_grounding/cognitive_load 0.25/0.20/0.20/0.20/0.15 vs `LSD_JUDGE_CONFIG` with cognitive_load 0.50 + inversion rule). Calibration cold-start fallback (D4 + codex #8): when `calibration_profiles.active_bias_tags` is empty, judge runs without anti-bias context AND stderr-warns. Op-layer write-back at `src/core/operations.ts` `search`/`query`/`get_page` handlers fires `bumpLastRetrievedAt(engine, pageIds)` (fire-and-forget, 5-min throttled via SQL clause, default-on with `search.track_retrieval` config escape hatch per D13) — internal callers (sync, migrations, dream cycle) bypass the op layer so the LSD stale signal stays clean. **v0.41.8.0 (#1247/#1269/#1290):** the IIFE is now tracked in a module-scoped `Set>` (mirrors the v0.36.1.x `awaitPendingSearchCacheWrites` precedent for #1090). New exported `awaitPendingLastRetrievedWrites(timeoutMs?: number): Promise<{outcome, pending}>` resolves once all tracked promises settle, bounded by a 5s `Promise.race` timeout that stderr-warns with the pending count if it fires. `src/cli.ts` awaits the drain unconditionally for every op in the op-dispatch finally block BEFORE `engine.disconnect()`, then narrows a fallback `process.exit(0)` to fire ONLY when `outcome === 'timeout'` AND `shouldForceExitAfterMain(argv)` (excludes `serve` so daemons stay alive). Closes the PGLite CLI search/query/get-hang class: pre-fix, the IIFE raced disconnect, PGLite's WASM kept Bun's event loop alive, CLI hung at ~95-98% CPU until SIGKILL. Three community-validated reports; PR #1259 (jehoon) supplied the structural drain pattern; PR #1337 (matt-dean-git) supplied the snapshot+early-null disconnect pattern AND the force-exit guard we narrowed to fire only on the timeout path. Pinned by `test/last-retrieved.test.ts` (6 unit cases: empty/single/multi-pending settle, throw-in-IIFE still settles, permanently-pending hits timeout, empty pageIds untracked), `test/e2e/pglite-cli-exit.serial.test.ts` (IRON-RULE behavioral regression: real `bun src/cli.ts` subprocess against a hermetic PGLite tempdir, asserts search/get/query exit 0 in <15s + daemon-survival case), `test/fix-wave-structural.test.ts` (behavioral-positioning assertion that the drain `await` appears textually BEFORE `engine.disconnect` in the local-engine path — survives variable-rename refactors). Migration v79 adds `pages.last_retrieved_at TIMESTAMPTZ NULL` + full B-tree index (NOT partial — covers both NULL and range branches per codex r2 #6); full forward-reference bootstrap probe on both engines. Frontmatter `mode: lsd` makes the dream-cycle synthesize phase skip LSD output (noise-by-design — `isLsdOutput()` check in `src/core/cycle/transcript-discovery.ts` short-circuits `isDreamOutput()`). `gbrain eval brainstorm ` is a three-axis evaluation gate (distance + usefulness + grounding, conjunctive) per codex r2 #11 — distance alone is gameable. `gbrain doctor` gains `brainstorm_health` check surfacing (a) migration v79 applied, (b) `search.track_retrieval` setting, (c) calibration cold-start status. 38 unit tests across `test/brainstorm/{distance,lsd-mode-skip,eval-brainstorm}.test.ts`. Plan: `~/.claude/plans/system-instruction-you-are-working-staged-coral.md`. Open Collider source: `github.com/CL-ML/open-collider`. **v0.41.21.0:** judges.ts replaces `maxTokens: 4000` with `computeJudgeMaxTokens(ideaCount, modelId)`. Named constants at top of file: `TOKEN_BUDGET_PER_IDEA`, `TOKEN_BUDGET_ENVELOPE`, `LEGACY_MIN_MAX_TOKENS`, `MAX_OUTPUT_TOKENS_CEIL`. New `ANTHROPIC_OUTPUT_CAPS` map (Opus 4.7 = 32K, Sonnet 4.6 / Haiku 4.5 = 64K, legacy Claude 3.5 = 8K) so legacy 8K-cap models bind at 8K instead of failing mid-judge. When the caller passes no `modelOverride`, the cap routes through the gateway's actual configured chat model via `getChatModel()` so the formula matches what `chat()` will use (not whatever a stale override hints at). Closes the headline v0.41.21.0 bug: pre-fix, a 72-idea brainstorm chunked the judge into ~3 calls of ~24 ideas each; each call needed ~7.2K output tokens; the hard-coded 4K cap truncated every call mid-JSON; the parser threw; the whole run came back `judge_failed: true` with 0/72 scored. Post-fix: same fixture returns ~39/72 passing. Pinned by 16 cases in `test/brainstorm/judges-maxtokens.test.ts`. - `src/core/model-id.ts` (v0.41.21.0, NEW) — `splitProviderModelId(input: string | null | undefined): {provider: string | null, model: string}` shared parser for the pricing side. Splits on `:` first, then `/`. Defensive contract: null/undefined/empty/whitespace returns `{provider: null, model: ''}`. Five sites consume it (`src/core/anthropic-pricing.ts:estimateMaxCostUsd`, `src/core/budget/budget-tracker.ts:lookupPricing`, `src/core/eval-contradictions/cost-tracker.ts:pricingFor`, `src/core/minions/batch-projection.ts` at two call sites, `src/core/model-config.ts:isAnthropicProvider`) so the pricing + classification surface no longer has 5 parallel re-implementations of `provider:model` splitting. Closes the bug class where slash-form ids (`anthropic/claude-sonnet-4-6` — the form CLI flags accept and OpenRouter recipes emit) silently fell through to "unknown model" at every site. Distinct from the existing gateway-side `parseModelId` in `src/core/ai/model-resolver.ts`: that one throws on bare names because routing needs an explicit provider; this one returns `{provider: null, model: 'bare'}` because pricing lookups happen against bare model ids. Pinned by 16 cases in `test/model-id.test.ts`. - `src/core/ai/model-resolver.ts:parseModelId` extension (v0.41.21.0) — gateway-side resolver extended to accept slash form alongside colon. Pre-fix the colon-only check threw `AIConfigError: model id must be in format provider:model` at every gateway entry point (chat / embed / rerank) the moment a slash-form id was passed. So even with the v0.41.21.0 pricing fix, a `--judge-model anthropic/claude-sonnet-4-6` invocation would clear BudgetTracker but then fail mid-judge inside `gateway.chat()`. Now both shapes resolve to the same recipe. Bare names without ANY separator still throw — gateway routing always needs an explicit provider. Pinned by 10 cases in `test/ai/model-resolver-slash.test.ts` including a `resolveRecipe` round-trip asserting slash form resolves to the same recipe object as colon form. diff --git a/VERSION b/VERSION index 48db4409d..d2e1b4cbb 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.41.23.0 \ No newline at end of file +0.42.0.0 \ No newline at end of file diff --git a/llms-full.txt b/llms-full.txt index b8f9ba52d..74fbc210b 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -389,7 +389,7 @@ strict behavior when unset. - `src/commands/whoknows.ts` (v0.33) — `gbrain whoknows [--explain] [--limit N] [--json]`: expertise + relationship-proximity routing. Mirrors v0.29 salience/anomalies shape (pure `rankCandidates()` + `findExperts()` orchestrator + `runWhoknows()` CLI dispatch + thin-client routing). MCP op = `find_experts` (scope: read, localOnly: false) per ENG-D5. Ranking formula (ENG-D1 locked): `score = log(1 + raw_match) × max(0.1, exp(-days/180)) × (0.5 + 0.5 × salience)` where `raw_match` is hybridSearch's RRF+source-boost score. Filters at SQL via the new `SearchOpts.types: ['person', 'company']` (no post-filter waste). hybridSearch's internal salience+recency boosts are intentionally disabled — the locked formula applies on a clean signal. Floors prevent multiplicative-zero edge cases (cold-start people stay visible); ties break alphabetically by slug for determinism. 16 unit tests in `test/whoknows.test.ts` pin the math. - `src/commands/eval-whoknows.ts` (v0.33, v0.33.1.3 thin-client wiring) — `gbrain eval whoknows [--json] [--skip-replay]`: two-layer eval gate (ENG-D2). Layer 1 quality (hand-labeled fixture, top-3 hit rate ≥ 0.8). Layer 2 regression (`eval_candidates` replay set-Jaccard@3 ≥ 0.4). Sparseness fallback: < 20 replay-eligible rows → Layer 2 auto-skips with stderr warning. Stable JSON envelope with `schema_version: 1`. Exit 0/1/2 for pass/fail/usage so CI can gate. Mirrors v0.27.x cross-modal + v0.28.1 longmemeval dispatch shape under `src/commands/eval.ts`. **v0.33.1.3:** `WhoknowsFn` callable abstraction lets the gates be impl-agnostic. `runEvalWhoknows(engine: BrainEngine | null, args)` picks the impl at entry — thin-client mode (`isThinClient(cfg)`) routes per-query through `callRemoteTool(cfg, 'find_experts', {topic, limit})` via the v0.31.1 seam; local mode calls `findExperts(engine, ...)` directly. cli.ts adds a thin-client bypass before `connectEngine` for `gbrain eval whoknows`, matching the longmemeval/cross-modal no-DB pattern. Regression gate auto-skips in thin-client mode (no DB access to `eval_candidates`). Public exports `jaccardAtK`, `topKHit`, `readFixture`, `WhoknowsFn`, threshold constants are pinned by `test/eval-whoknows.test.ts` (25 cases, +2 for the null-engine signature contract). - `test/fixtures/whoknows-eval.jsonl` (v0.33) — 10-row synthetic placeholder demonstrating the eval-fixture schema (`{query, expected_top_3_slugs, notes?}` JSONL). End users replace with their own real queries before shipping; the placeholder uses obviously-example slugs (`wiki/people/example-alice`) so production data isn't conflated with the test fixture. Drives `test/e2e/whoknows.test.ts` (which seeds a matching synthetic brain and asserts the >=80% gate) and the `whoknows_health` doctor check. -- `src/core/skillopt/` + `src/commands/skillopt.ts` + `skills/skill-optimizer/` (v0.41.23.0 SkillOpt wave, closes #1481) — self-evolving skill optimization grounded in the SkillOpt paper (arXiv 2605.23904, Microsoft Research, May 2026). Top-level CLI `gbrain skillopt ` treats `SKILL.md` as trainable parameters of a frozen agent; validation-gated (D12 median-of-3 + epsilon=0.05), budget-capped (D3 preflight estimator), per-skill DB-locked (D14 `tryAcquireDbLock('skillopt:', 60min)`), atomic-versioned (D8 history-intent-first 5-step commit), body-only mutations (D5 — frontmatter forbidden). Rollouts use `gateway.toolLoop` directly with no-op persistence callbacks (D2 — zero `subagent_messages` pollution) + a read-only tool allowlist derived from `BRAIN_TOOL_ALLOWLIST` minus `put_page`/`submit_job`/`file_upload` (D13). Two reflect calls per step (D7 paper-faithful). Rejected-edit buffer LRU-bounded to 100 entries. Bundled-skill gate (D16). Bootstrap workflow (D15 sentinel + `--bootstrap-reviewed`). D17 D_sel floor (>=5 with `--split` override). Audit JSONL via shared `audit-writer.ts`. Added to `ALL_PHASES` after `patterns` (default OFF; opt-in via `gbrain config set cycle.skillopt.enabled true`); cycle phase wrapper at `src/core/skillopt/cycle-phase.ts` walks stale skills with per-skill ($0.50) + brain-wide ($2.00) caps. Added to `PROTECTED_JOB_NAMES`. Full cathedral ships: F1 dream-cycle phase wrapper, F2 41-case adversarial test suite (6 files), F3 E2E PGLite serial test (3 cases), F4 `--all` batch mode (`src/core/skillopt/batch.ts:runBatchAll`), F5 `--target-models` fleet (`runFleet` parallel per-model receipts under `skillopt/fleet//`), F6 MCP op `run_skillopt` (admin scope + per-skill `skillopt.allowed_skills` allowlist, NOT localOnly), F7 Minion `skillopt` handler + `--background` CLI flag with `allowProtectedSubmit: true`, F8 reflect-prompt quality eval at `evals/skillopt-reflect/`, F9 judge LLM accuracy eval at `evals/skillopt-judge/`, F10 write-flavored optimization via `src/core/skillopt/write-capture.ts:buildWriteCaptureRegistry` (virtual `put_page`/`submit_job`/`file_upload` captured in-memory; `--write-capture` flag), F11 held-out real-user test set scaffold via `src/core/skillopt/held-out.ts` (capture infra at `~/.gbrain/skillopt-captures//.jsonl`, `--held-out ` flag, `runHeldOutGate` candidate >= baseline). Pinned by 152 tests across 18 files (88 foundation + 41 adversarial + 23 v2 surface + 3 E2E PGLite serial); hermetic via DI seams (`opts.chatFn` for optimizer + judge; `opts.toolLoopFn` for rollouts; no `mock.module`, R2-compliant). Plan + 17 review decisions + outside-voice codex absorption at `~/.claude/plans/system-instruction-you-are-working-drifting-falcon.md`. v0.42+ remaining: admin UI Calibration-style dashboard tab for optimizer history; sweep all 47 bundled skills with their own `skillopt-benchmark.jsonl` fixtures (manual benchmark authoring). +- `src/core/skillopt/` + `src/commands/skillopt.ts` + `skills/skill-optimizer/` (v0.42.0.0 SkillOpt wave, closes #1481) — self-evolving skill optimization grounded in the SkillOpt paper (arXiv 2605.23904, Microsoft Research, May 2026). Top-level CLI `gbrain skillopt ` treats `SKILL.md` as trainable parameters of a frozen agent; validation-gated (D12 median-of-3 + epsilon=0.05), budget-capped (D3 preflight estimator), per-skill DB-locked (D14 `tryAcquireDbLock('skillopt:', 60min)`), atomic-versioned (D8 history-intent-first 5-step commit), body-only mutations (D5 — frontmatter forbidden). Rollouts use `gateway.toolLoop` directly with no-op persistence callbacks (D2 — zero `subagent_messages` pollution) + a read-only tool allowlist derived from `BRAIN_TOOL_ALLOWLIST` minus `put_page`/`submit_job`/`file_upload` (D13). Two reflect calls per step (D7 paper-faithful). Rejected-edit buffer LRU-bounded to 100 entries. Bundled-skill gate (D16). Bootstrap workflow (D15 sentinel + `--bootstrap-reviewed`). D17 D_sel floor (>=5 with `--split` override). Audit JSONL via shared `audit-writer.ts`. Added to `ALL_PHASES` after `patterns` (default OFF; opt-in via `gbrain config set cycle.skillopt.enabled true`); cycle phase wrapper at `src/core/skillopt/cycle-phase.ts` walks stale skills with per-skill ($0.50) + brain-wide ($2.00) caps. Added to `PROTECTED_JOB_NAMES`. Full cathedral ships: F1 dream-cycle phase wrapper, F2 41-case adversarial test suite (6 files), F3 E2E PGLite serial test (3 cases), F4 `--all` batch mode (`src/core/skillopt/batch.ts:runBatchAll`), F5 `--target-models` fleet (`runFleet` parallel per-model receipts under `skillopt/fleet//`), F6 MCP op `run_skillopt` (admin scope + per-skill `skillopt.allowed_skills` allowlist, NOT localOnly), F7 Minion `skillopt` handler + `--background` CLI flag with `allowProtectedSubmit: true`, F8 reflect-prompt quality eval at `evals/skillopt-reflect/`, F9 judge LLM accuracy eval at `evals/skillopt-judge/`, F10 write-flavored optimization via `src/core/skillopt/write-capture.ts:buildWriteCaptureRegistry` (virtual `put_page`/`submit_job`/`file_upload` captured in-memory; `--write-capture` flag), F11 held-out real-user test set scaffold via `src/core/skillopt/held-out.ts` (capture infra at `~/.gbrain/skillopt-captures//.jsonl`, `--held-out ` flag, `runHeldOutGate` candidate >= baseline). Pinned by 152 tests across 18 files (88 foundation + 41 adversarial + 23 v2 surface + 3 E2E PGLite serial); hermetic via DI seams (`opts.chatFn` for optimizer + judge; `opts.toolLoopFn` for rollouts; no `mock.module`, R2-compliant). Plan + 17 review decisions + outside-voice codex absorption at `~/.claude/plans/system-instruction-you-are-working-drifting-falcon.md`. v0.42+ remaining: admin UI Calibration-style dashboard tab for optimizer history; sweep all 47 bundled skills with their own `skillopt-benchmark.jsonl` fixtures (manual benchmark authoring). - `src/core/brainstorm/{domain-bank,orchestrator,judges}.ts` + `src/commands/{brainstorm,lsd,eval-brainstorm}.ts` + `src/core/last-retrieved.ts` (v0.37.0 Open Collider wave) — bisociation-grounded idea generation pair: `gbrain brainstorm ` (defensible, cite-heavy, 4 close × 6 far, judge threshold 4.0/5, save by default) and `gbrain lsd ` (Lateral Synaptic Drift — inverted judge that rejects ideas with resistance >4.5 ("too obvious"), stale-page bias via `pages.last_retrieved_at`, 2 close × 12 far, axiomatic inversions required, ephemeral by default). The architecture corrects Open Collider's training-data-grounded approach: gbrain has the user's actual cross-domain knowledge already, so the "domain bank" is prefix-stratified sampling from the user's own brain (`SELECT DISTINCT substring(slug from '^[^/]+/[^/]+')` cached 1h-TTL in `config` table per source) tiebroken by `JOIN page_links` connection_count, with corpus-sampling fallback when fewer prefixes than M exist. Distance scores normalized to [0,1] via `1 - clamp(cosine_distance, 0, 2) / 2` (1=opposite, 0=identical). The judge is a single `judges.ts` with `runJudge(config, ideas)` + two exported configs (`BRAINSTORM_JUDGE_CONFIG` weighted originality/resistance/thesis_density/concrete_grounding/cognitive_load 0.25/0.20/0.20/0.20/0.15 vs `LSD_JUDGE_CONFIG` with cognitive_load 0.50 + inversion rule). Calibration cold-start fallback (D4 + codex #8): when `calibration_profiles.active_bias_tags` is empty, judge runs without anti-bias context AND stderr-warns. Op-layer write-back at `src/core/operations.ts` `search`/`query`/`get_page` handlers fires `bumpLastRetrievedAt(engine, pageIds)` (fire-and-forget, 5-min throttled via SQL clause, default-on with `search.track_retrieval` config escape hatch per D13) — internal callers (sync, migrations, dream cycle) bypass the op layer so the LSD stale signal stays clean. **v0.41.8.0 (#1247/#1269/#1290):** the IIFE is now tracked in a module-scoped `Set>` (mirrors the v0.36.1.x `awaitPendingSearchCacheWrites` precedent for #1090). New exported `awaitPendingLastRetrievedWrites(timeoutMs?: number): Promise<{outcome, pending}>` resolves once all tracked promises settle, bounded by a 5s `Promise.race` timeout that stderr-warns with the pending count if it fires. `src/cli.ts` awaits the drain unconditionally for every op in the op-dispatch finally block BEFORE `engine.disconnect()`, then narrows a fallback `process.exit(0)` to fire ONLY when `outcome === 'timeout'` AND `shouldForceExitAfterMain(argv)` (excludes `serve` so daemons stay alive). Closes the PGLite CLI search/query/get-hang class: pre-fix, the IIFE raced disconnect, PGLite's WASM kept Bun's event loop alive, CLI hung at ~95-98% CPU until SIGKILL. Three community-validated reports; PR #1259 (jehoon) supplied the structural drain pattern; PR #1337 (matt-dean-git) supplied the snapshot+early-null disconnect pattern AND the force-exit guard we narrowed to fire only on the timeout path. Pinned by `test/last-retrieved.test.ts` (6 unit cases: empty/single/multi-pending settle, throw-in-IIFE still settles, permanently-pending hits timeout, empty pageIds untracked), `test/e2e/pglite-cli-exit.serial.test.ts` (IRON-RULE behavioral regression: real `bun src/cli.ts` subprocess against a hermetic PGLite tempdir, asserts search/get/query exit 0 in <15s + daemon-survival case), `test/fix-wave-structural.test.ts` (behavioral-positioning assertion that the drain `await` appears textually BEFORE `engine.disconnect` in the local-engine path — survives variable-rename refactors). Migration v79 adds `pages.last_retrieved_at TIMESTAMPTZ NULL` + full B-tree index (NOT partial — covers both NULL and range branches per codex r2 #6); full forward-reference bootstrap probe on both engines. Frontmatter `mode: lsd` makes the dream-cycle synthesize phase skip LSD output (noise-by-design — `isLsdOutput()` check in `src/core/cycle/transcript-discovery.ts` short-circuits `isDreamOutput()`). `gbrain eval brainstorm ` is a three-axis evaluation gate (distance + usefulness + grounding, conjunctive) per codex r2 #11 — distance alone is gameable. `gbrain doctor` gains `brainstorm_health` check surfacing (a) migration v79 applied, (b) `search.track_retrieval` setting, (c) calibration cold-start status. 38 unit tests across `test/brainstorm/{distance,lsd-mode-skip,eval-brainstorm}.test.ts`. Plan: `~/.claude/plans/system-instruction-you-are-working-staged-coral.md`. Open Collider source: `github.com/CL-ML/open-collider`. **v0.41.21.0:** judges.ts replaces `maxTokens: 4000` with `computeJudgeMaxTokens(ideaCount, modelId)`. Named constants at top of file: `TOKEN_BUDGET_PER_IDEA`, `TOKEN_BUDGET_ENVELOPE`, `LEGACY_MIN_MAX_TOKENS`, `MAX_OUTPUT_TOKENS_CEIL`. New `ANTHROPIC_OUTPUT_CAPS` map (Opus 4.7 = 32K, Sonnet 4.6 / Haiku 4.5 = 64K, legacy Claude 3.5 = 8K) so legacy 8K-cap models bind at 8K instead of failing mid-judge. When the caller passes no `modelOverride`, the cap routes through the gateway's actual configured chat model via `getChatModel()` so the formula matches what `chat()` will use (not whatever a stale override hints at). Closes the headline v0.41.21.0 bug: pre-fix, a 72-idea brainstorm chunked the judge into ~3 calls of ~24 ideas each; each call needed ~7.2K output tokens; the hard-coded 4K cap truncated every call mid-JSON; the parser threw; the whole run came back `judge_failed: true` with 0/72 scored. Post-fix: same fixture returns ~39/72 passing. Pinned by 16 cases in `test/brainstorm/judges-maxtokens.test.ts`. - `src/core/model-id.ts` (v0.41.21.0, NEW) — `splitProviderModelId(input: string | null | undefined): {provider: string | null, model: string}` shared parser for the pricing side. Splits on `:` first, then `/`. Defensive contract: null/undefined/empty/whitespace returns `{provider: null, model: ''}`. Five sites consume it (`src/core/anthropic-pricing.ts:estimateMaxCostUsd`, `src/core/budget/budget-tracker.ts:lookupPricing`, `src/core/eval-contradictions/cost-tracker.ts:pricingFor`, `src/core/minions/batch-projection.ts` at two call sites, `src/core/model-config.ts:isAnthropicProvider`) so the pricing + classification surface no longer has 5 parallel re-implementations of `provider:model` splitting. Closes the bug class where slash-form ids (`anthropic/claude-sonnet-4-6` — the form CLI flags accept and OpenRouter recipes emit) silently fell through to "unknown model" at every site. Distinct from the existing gateway-side `parseModelId` in `src/core/ai/model-resolver.ts`: that one throws on bare names because routing needs an explicit provider; this one returns `{provider: null, model: 'bare'}` because pricing lookups happen against bare model ids. Pinned by 16 cases in `test/model-id.test.ts`. - `src/core/ai/model-resolver.ts:parseModelId` extension (v0.41.21.0) — gateway-side resolver extended to accept slash form alongside colon. Pre-fix the colon-only check threw `AIConfigError: model id must be in format provider:model` at every gateway entry point (chat / embed / rerank) the moment a slash-form id was passed. So even with the v0.41.21.0 pricing fix, a `--judge-model anthropic/claude-sonnet-4-6` invocation would clear BudgetTracker but then fail mid-judge inside `gateway.chat()`. Now both shapes resolve to the same recipe. Bare names without ANY separator still throw — gateway routing always needs an explicit provider. Pinned by 10 cases in `test/ai/model-resolver-slash.test.ts` including a `resolveRecipe` round-trip asserting slash form resolves to the same recipe object as colon form. diff --git a/package.json b/package.json index 1a50806ef..cf04a4904 100644 --- a/package.json +++ b/package.json @@ -140,5 +140,5 @@ "bun": ">=1.3.10" }, "license": "MIT", - "version": "0.41.23.0" + "version": "0.42.0.0" } diff --git a/src/commands/jobs.ts b/src/commands/jobs.ts index 31206e9c2..a523a1bd2 100644 --- a/src/commands/jobs.ts +++ b/src/commands/jobs.ts @@ -1646,7 +1646,7 @@ export async function registerBuiltinHandlers(worker: MinionWorker, engine: Brai }); }); - // v0.41.23.0 SkillOpt Minion handler — for --background CLI invocations. + // v0.42.0.0 SkillOpt Minion handler — for --background CLI invocations. // PROTECTED by name so MCP submission rejects (only trusted CLI can // submit). Threaded SkillOptOpts JSON in job.data. worker.register('skillopt', async (job) => { @@ -1689,7 +1689,7 @@ export async function registerBuiltinHandlers(worker: MinionWorker, engine: Brai }; }); - process.stderr.write('[minion worker] brain-health-100 handlers registered (12 ops, 4 protected) + embed-backfill (v0.40) + embed-catch-up (v0.42) + unify-types (v0.42) + skillopt (v0.41.23.0, protected)\n'); + process.stderr.write('[minion worker] brain-health-100 handlers registered (12 ops, 4 protected) + embed-backfill (v0.40) + embed-catch-up (v0.42) + unify-types (v0.42) + skillopt (v0.42.0.0, protected)\n'); // Plugin discovery — one line per discovered plugin (mirrors the // openclaw-seam startup line convention from v0.11+). Loaded diff --git a/src/core/minions/protected-names.ts b/src/core/minions/protected-names.ts index 762dc3f08..52efa8f0d 100644 --- a/src/core/minions/protected-names.ts +++ b/src/core/minions/protected-names.ts @@ -51,7 +51,7 @@ export const PROTECTED_JOB_NAMES: ReadonlySet = new Set([ // can't auto-apply; user must run `gbrain onboard --auto-with-prompt` // or submit explicitly via `gbrain jobs submit unify-types --allow-protected`. 'unify-types', - // v0.41.23.0 — SkillOpt: optimizer Sonnet/Opus loops over a benchmark. + // v0.42.0.0 — SkillOpt: optimizer Sonnet/Opus loops over a benchmark. // Preemptive register entry (v1 is CLI-only foreground; future Minion // handler must reject MCP submission). Costs user money (optimizer + // judge + rollouts) so PROTECTED is the right posture.