Files
gbrain/package.json
T
1399e519c0 v0.30.0 feat: calibration scorecards (Slice A1 of v0.30 wave) (#731)
* feat(schema): migration v40 — takes_resolved_quality + drift_decisions

Slice A1 of the v0.30 wave. Bundles all wave schema in one migration so
A2/B1/C1 carry no schema of their own (codex F6 schema-first ordering).

- takes.resolved_quality TEXT with CHECK (correct/incorrect/partial).
- takes_resolution_consistency CHECK enforces (quality, outcome) tuple
  consistency at the DB layer. partial → outcome=NULL.
- One-shot backfill maps legacy resolved_outcome → resolved_quality so
  v0.28 brains keep working with no manual reclassification.
- idx_takes_scorecard partial index on (holder, kind, resolved_quality)
  WHERE resolved_quality IS NOT NULL — scorecard hot path.
- drift_decisions audit table (consumed by Slice C1 in v0.30.3).
- PGLite branch via sqlFor.pglite mirrors the same shape; RLS DO-block
  is Postgres-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(takes-fence): extend ParsedTake + parser + conditional renderer (codex F3)

A codex consult on the v0.30 plan caught a real bug: the v0.28 parser had
no concept of resolution columns, so every cmdUpdate after a cmdResolve
silently deleted resolution data on the next render. This commit kills
that data-loss path.

ParsedTake gains optional resolvedAt, resolvedQuality, resolvedOutcome,
resolvedEvidence, resolvedValue, resolvedUnit, resolvedBy. parseTakesFence
detects v0.30-shape headers and reads resolution cells when present;
v0.28 7-column fences round-trip byte-identical. renderTakesFence emits
the resolution columns ONLY when at least one row on the page has
resolvedQuality set — pages with no resolved rows keep the narrow shape
exactly as before.

11 new test cases including the round-trip preservation regression gate.
Without those tests, the silent-delete bug returns the moment the parser
shape drifts. Tests cover: parsing v0.30 + v0.28 shapes, conditional
rendering, partial quality round-trip, upsertTakeRow + supersedeRow
preservation when a page already has resolved rows.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(engine): getScorecard + getCalibrationCurve + 3-state TakeResolution

Adds the calibration aggregate methods on BrainEngine. Both engines
implement them with SQL-level allow-list filtering inside the GROUP BY
(D4 fail-closed): hidden-holder rows contribute zero to aggregates.

TakeResolution gains optional `quality` (correct|incorrect|partial). When
both quality and outcome are supplied AND inconsistent, the engine throws
TAKE_RESOLUTION_INVALID rather than silently overwriting. resolveTake
writes both columns: quality directly, outcome derived (correct→true,
incorrect→false, partial→NULL). Schema CHECK is the defense-in-depth
backstop.

Brier scope (D5 + D11): the SQL aggregation excludes partial rows from
the Brier denominator — partial isn't a binary outcome to compare a
probability against. partial_rate is reported alongside as a separate
counter so hedging behavior stays visible. The 20% threshold lives in
src/core/takes-resolution.ts and the CLI surfaces it in v0.30.0's
cmdScorecard.

New module src/core/takes-resolution.ts holds shared pure helpers
(deriveResolutionTuple, finalizeScorecard) consumed by both engines so
the math stays identical across backends. takeRowToTake (utils.ts) reads
resolved_quality through to the Take row shape.

23 new test cases: 16 for the helpers (Brier hand-calc against a 4-bet
reference at 0.205, n=0 no-divide, contradictory-input rejection,
partial-exclusion contract, threshold constant); 7 against PGLite for
the engine path (3-state quality writes, contradictory throws, scorecard
hand-calc, n=0, SQL-level allow-list privacy filter).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(cli): gbrain takes resolve --quality, takes scorecard, takes calibration

cmdResolve widened: --quality correct|incorrect|partial is the new primary
input. --outcome true|false stays as a back-compat alias auto-mapping to
quality, with a stderr deprecation warning on use. Mutually exclusive
with --quality. --evidence is a semantic alias for --source on the
resolve subcommand.

cmdResolve mirrors resolution metadata into the takes-fence on disk via
the page-lock-aware path. Round-trip preservation through parseTakesFence
+ renderTakesFence keeps resolution data intact across unrelated edits to
other rows on the same page. Removes the v0.28 deferred-rendering warning.

cmdScorecard prints `correct | incorrect | partial`, accuracy, Brier
(correct ∨ incorrect only; lower is better; 0.25 = always-50% baseline),
and partial_rate. When partial_rate > 20% the CLI prints
"[!] partial_rate is high — calibration may be optimistic" so hedging
behavior stays visible even though it doesn't enter the math (D11). Small-N
note when resolved < 100. JSON output via --json.

cmdCalibration bins resolved correct/incorrect bets by stated weight
(--bucket-size, default 0.1) and prints observed vs predicted vs delta
per bucket. Diagonal alignment = perfect calibration.

Both new subcommands wire allow-list as undefined for local CLI callers
(trusted); MCP path will thread it from access_tokens.permissions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(mcp): register takes_scorecard + takes_calibration ops

Both ops are read-scope, MCP-callable, allow-list-honoring. Handlers
thread ctx.takesHoldersAllowList into the engine method's required
allowList parameter, which applies WHERE holder = ANY at SQL aggregation
level (D4 fail-closed). Local CLI callers leave the allow-list
undefined and see all holders.

Updates the OperationContext.takesHoldersAllowList contract comment to
list the new aggregate ops alongside takes_list, takes_search, query.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* v0.30.0 release: calibration core (Slice A1 of v0.30 wave)

VERSION + package.json bump. CHANGELOG entry covers the release-summary
(headline + math table + privacy note + data-loss-bug-killed note),
"## To take advantage of v0.30.0" upgrade path, and itemized changes.

llms-full.txt regenerated to capture the v0.28.x annotations that had
been merged but not yet rolled into the docs bundle.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* test(e2e): scorecard + calibration parity on real Postgres + NUMERIC fix

Adds end-to-end coverage for v0.30.0 (Slice A1) against real Postgres:

- test/e2e/takes-scorecard-parity.test.ts (new): seeds the same 6-bet
  fixture (4 binary garry + 1 partial garry + 1 binary harj) into both
  Postgres and PGLite, asserts getScorecard + getCalibrationCurve return
  byte-identical results across engines, runs the 4-bet hand-calc Brier
  reference (0.205) on real PG, and verifies the SQL-level allow-list
  filter strictly subtracts hidden-holder rows on both engines.

- test/e2e/takes-postgres.test.ts: extended with 8 v0.30 cases — quality
  semantics (correct/partial/back-compat) writes the expected (quality,
  outcome) tuple on real PG; the takes_resolution_consistency CHECK
  constraint actually fires on a contradictory raw UPDATE; getScorecard
  + getCalibrationCurve coherent shape + ordered-bucket invariants;
  PRIVACY allow-list filter on real PG; MCP dispatch path for
  takes_scorecard + takes_calibration with allow-list threading.

While writing the parity test, the e2e harness caught a real bug PGLite
tolerated: postgres.js sends scalar `${bucketSize}` params as text by
default, so `FLOOR(weight / $N)` tried to coerce '0.1' to integer and
threw `invalid input syntax for type integer: "0.1"`. The NUMERIC fix
also kills a separate FP-precision divergence — `FLOOR(0.7 / 0.1)`
returns 6 on real PG (IEEE 754 rounds 0.7/0.1 to 6.9999...) and 7 on
PGLite. Both engines now bucket via `weight::numeric / $N::numeric`
which is exact decimal arithmetic and engine-agnostic.

This is the v0.30.0 wave's first cross-engine parity test. Same shape
will guard A2's getTrajectory + getAnnualReview when those land.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(changelog): correct v40→v43 reference and expand v0.30.0 test note

Two fixes to the v0.30.0 entry after the master merge renumbered the
migration:

- The "#### Added" bullet still said "Schema migration v40"; bumped to v43.
- The "#### Tests" section only enumerated unit tests. The PR also ships
  19 E2E cases (11 in takes-scorecard-parity, 8 extending takes-postgres)
  that exercise the calibration math against real Postgres and the
  PG↔PGLite engine parity. Added the count + a note about the two real
  bugs the parity test caught (postgres.js string-typed scalar params
  and IEEE 754 bucketing divergence) that PGLite tolerated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:07:00 -07:00

111 lines
5.1 KiB
JSON

{
"name": "gbrain",
"version": "0.30.0",
"description": "Postgres-native personal knowledge brain with hybrid RAG search",
"type": "module",
"main": "src/core/index.ts",
"bin": {
"gbrain": "src/cli.ts"
},
"exports": {
".": "./src/core/index.ts",
"./engine": "./src/core/engine.ts",
"./types": "./src/core/types.ts",
"./operations": "./src/core/operations.ts",
"./minions": "./src/core/minions/index.ts",
"./engine-factory": "./src/core/engine-factory.ts",
"./pglite-engine": "./src/core/pglite-engine.ts",
"./link-extraction": "./src/core/link-extraction.ts",
"./import-file": "./src/core/import-file.ts",
"./transcription": "./src/core/transcription.ts",
"./embedding": "./src/core/embedding.ts",
"./config": "./src/core/config.ts",
"./markdown": "./src/core/markdown.ts",
"./backoff": "./src/core/backoff.ts",
"./search/hybrid": "./src/core/search/hybrid.ts",
"./search/expansion": "./src/core/search/expansion.ts",
"./extract": "./src/commands/extract.ts"
},
"scripts": {
"dev": "bun run src/cli.ts",
"build": "bun build --compile --outfile bin/gbrain src/cli.ts",
"build:all": "bun build --compile --target=bun-darwin-arm64 --outfile bin/gbrain-darwin-arm64 src/cli.ts && bun build --compile --target=bun-linux-x64 --outfile bin/gbrain-linux-x64 src/cli.ts",
"build:admin": "cd admin && bun run build",
"build:schema": "bash scripts/build-schema.sh",
"build:llms": "bun run scripts/build-llms.ts",
"build:pglite-snapshot": "bun run scripts/build-pglite-snapshot.ts",
"test": "bash scripts/run-unit-parallel.sh",
"test:full": "bun run verify && bash scripts/run-unit-parallel.sh && bun run test:slow && ([ -n \"$DATABASE_URL\" ] && bash scripts/run-e2e.sh || echo '[test:full] skipped E2E (no DATABASE_URL); run docker-compose -f docker-compose.ci.yml up + bun run test:e2e to include' 1>&2)",
"verify": "bun run check:privacy && bun run check:jsonb && bun run check:progress && bun run check:test-isolation && bun run check:wasm && bun run check:admin-build && bun run check:admin-scope-drift && bun run check:cli-exec && bun run typecheck",
"check:admin-scope-drift": "scripts/check-admin-scope-drift.sh",
"check:cli-exec": "scripts/check-cli-executable.sh",
"check:all": "scripts/check-privacy.sh && scripts/check-jsonb-pattern.sh && scripts/check-progress-to-stdout.sh && scripts/check-no-legacy-getconnection.sh && scripts/check-test-isolation.sh && scripts/check-trailing-newline.sh && scripts/check-wasm-embedded.sh && scripts/check-exports-count.sh && scripts/check-admin-build.sh && scripts/check-admin-scope-drift.sh && scripts/check-cli-executable.sh",
"check:wasm": "scripts/check-wasm-embedded.sh",
"check:newlines": "scripts/check-trailing-newline.sh",
"test:e2e": "bash scripts/run-e2e.sh",
"test:slow": "bash scripts/run-slow-tests.sh",
"test:profile": "bash scripts/profile-tests.sh",
"test:serial": "bash scripts/run-serial-tests.sh",
"ci:local": "bash scripts/ci-local.sh",
"ci:local:diff": "bash scripts/ci-local.sh --diff",
"ci:select-e2e": "bun run scripts/select-e2e.ts",
"typecheck": "tsc --noEmit",
"check:jsonb": "scripts/check-jsonb-pattern.sh",
"check:privacy": "scripts/check-privacy.sh",
"check:progress": "scripts/check-progress-to-stdout.sh",
"check:exports-count": "scripts/check-exports-count.sh",
"check:admin-build": "scripts/check-admin-build.sh",
"check:test-isolation": "scripts/check-test-isolation.sh",
"postinstall": "command -v gbrain >/dev/null 2>&1 && gbrain apply-migrations --yes --non-interactive || echo '[gbrain] postinstall skipped. If installed via bun install -g github:...: run `gbrain doctor` and `gbrain apply-migrations --yes` manually. See https://github.com/garrytan/gbrain/issues/218' 1>&2",
"prepublish:clawhub": "bun run build:all",
"publish:clawhub": "clawhub package publish . --family bundle-plugin"
},
"openclaw": {
"compat": {
"pluginApi": ">=2026.4.0"
}
},
"dependencies": {
"@ai-sdk/anthropic": "^3.0.71",
"@ai-sdk/google": "^3.0.64",
"@ai-sdk/openai": "^3.0.53",
"@ai-sdk/openai-compatible": "^2.0.41",
"@anthropic-ai/sdk": "^0.30.0",
"@aws-sdk/client-s3": "^3.1028.0",
"@dqbd/tiktoken": "^1.0.22",
"@electric-sql/pglite": "0.4.3",
"@jsquash/avif": "^2.1.1",
"@modelcontextprotocol/sdk": "1.29.0",
"ai": "^6.0.168",
"cookie-parser": "^1.4.7",
"cors": "^2.8.5",
"eventsource-parser": "^3.0.8",
"exifr": "^7.1.3",
"express": "^5.1.0",
"express-rate-limit": "^7.5.0",
"gray-matter": "^4.0.3",
"marked": "^18.0.0",
"openai": "^4.0.0",
"pgvector": "^0.2.0",
"postgres": "^3.4.0",
"tree-sitter-wasms": "0.1.13",
"web-tree-sitter": "0.22.6",
"zod": "^4.3.6"
},
"devDependencies": {
"@types/bun": "latest",
"@types/cookie-parser": "^1.4.7",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.6",
"bun-types": "^1.3.13",
"typescript": "^5.6.0"
},
"trustedDependencies": [
"@electric-sql/pglite"
],
"engines": {
"bun": ">=1.3.10"
},
"license": "MIT"
}