mirror of
https://github.com/garrytan/gbrain.git
synced 2026-08-14 00:48:18 +00:00
master
17
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
3f22f51e5d |
v0.45.6.0 feat(skills): giftable-skills import wave — 17 new production skills + 8 upgrades (#4033)
* feat(skills): check-skill-refs gate + per-commit skills gate runner Three integrity checks over skills/ markdown: dangling refs (backtick paths, composes: frontmatter, RESOLVER dispatcher slugs), donor-remnant paths behind a ratchet allowlist, and warn-only CLI-reference drift against the live tool surface. Wired as check:skill-refs in verify and bundled into scripts/skills-commit-gate.sh (conformance+resolver tests, check-resolvable --strict, lock regen+freshness, refs, optional per-file privacy lint) for any commit touching the skills pack. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skillpack): machine-readable plugin curation record + membership assertions skills/plugin-exclusions.json records why each manifest skill is not bundled into openclaw.plugin.json (Tier B host-only decisions, seeded from the pre-existing split). test/openclaw-plugin-manifest.test.ts now asserts manifest = bundled + exclusions with no overlap, no orphans, no stale exclusions, and a sorted skills array (two pre-existing sort inversions fixed). Bundling decisions are now review-visible: moving a skill between tiers requires touching both files in one commit. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): skillify reconciled with the evolved upstream line (v2.0.0) Adopts eval contracts, the NO-REGRESSION LAW, idempotency guidance, and the 14-item checklist from the upstream skillify line while preserving this repo's divergent content. bulk-ingestion (later in this wave) delegates its codify phase to this checklist. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): book-mirror 0.5.0 backport Table-misalignment root-cause fix, anti-repetition hard constraints, and the resonant-stance rewrite from the upstream line, generalized onto native gbrain surfaces (no external storage libs). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(conventions): test-before-bulk gains the progressive ramp + output-existence checks 10 -> 100 -> 500 -> full ramp with per-round stop gates, the count-before/count-after output-existence check (catches silent zero-row writes), the <2% error-rate gate, the copy-paste verification checklist, cost estimation, and pointers to native pace mode + progress flags so nobody rebuilds throttling in bash. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(conventions): regex-discipline — judgment vs heuristic epistemics The one-question test (deterministic-and-rote vs judgment), the earned- regex sequence, red flags/green lights, never-regex-what-an-attacker-can- imitate, and two genericized cautionary tales. Pairs with test-before-bulk: look before you compress, compress only the rote. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(conventions): path-discipline — display strings are not path strings Never pass a display-formatted link/URL to a file tool; a "successful" write to a poisoned path lies. Poisoned-path tells, verify-before-done, retry discipline, junk-tree recovery. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(conventions): exec-output — buffer to file, read bounded slices Empty exec results usually mean truncation, not a broken shell. The buffer-then-slice rule, shell patterns, and the diagnostic ladder, generalized to any harness. Conventions half of the durable-execution doctrine (the minion-orchestrator half lands separately). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): concept-synthesis 0.2.0 — curation cull phase Adds the keep/delete/merge muscle the synthesis loop lacked: minimum substance gates (style cannot rescue hollow ideas), weighted verdict bands with hard delete triggers, grounding labels wired to the citation conventions, a reputational-risk gate, cluster budgets, and reversible merge-with-backlinks with merge-count as an emergent-salience signal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): measure-before-you-fix — measure-first ops triage Stopwatch-verify before raising timeouts; act-line vs alert-line. Trigger vocabulary maps onto the shipped doctor/autopilot/sync alert classes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): data-loss-gate — confirmation gate for irreversible operations Recoverability checklist + alternatives + explicit-yes before any bulk delete, forget sweep, source/mount removal, or history rewrite. No category-level exception classes: disposability is a property of the inspected target. Routing-convention honesty: the native operation- boundary confirm remains a filed follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): fact-check — pre-publication claim verification Breadth gate: extract every verifiable claim, verify each against live sources with a confidence scale. Data-derived claims section carries the two laws: producer is never verifier (independent re-derivation via a different query path) and affiliation is not authorship (typed edges, not co-occurrence). Hard-block on unsupported claims. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): resolve-before-asking — exhaust the brain before interrupting the human Query, timeline, and every mounted source before asking; when asking is justified, ask WITH a hypothesis (pairs with ask-user). Includes the no-placeholders-at-ingest rule. Owns WHETHER asking is justified; query owns the lookup verb, brain-ops the read-write cycle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): brain-ingest-gate — ingest entry gate (no raw copies, entity resolution, dedup) No-raw-copies entry rule; the Named-Entity Resolution Gate (registry- first + alias expansion — a vector score is a floor for prose, never a gate for named things); the qualitative dedup decision tree (open and read the top hit before writing). The gate keeps full dedup responsibility: native import skips only matching frontmatter IDs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): correction-pipeline — trace corrections to the contamination source When the user corrects a fact: root-cause it (7-class taxonomy), fix the source surface (facts table via recall/forget/remember; pages via edit + re-sync; identity files via bootstrap templates), then run the propagation check. Never just note it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): company-brainify — personal-to-team brain sanitization Strip/keep tables, triage grep pipelines, verification greps, and the history-purge procedure for publishing a sanitized team brain from a personal one. Scan scope covers meetings, dailies, facts, and takes, not just people pages. History rewrite is gated through data-loss-gate with a mirror-clone backup. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): citation-graph-ingest — typed inter-document citation edges Extract every inter-document reference from an ingested corpus and classify the edge type (overrules/distinguishes/relies-on/extends...), written via native link ops and queryable via graph-query. States plainly that natural-language relational retrieval walks a fixed edge- type set today; wiring these types in is a filed follow-up. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): two-tier-extraction — triage/deep-read model routing for archives Cheap-model triage pass, gate, then strong-model deep read for archive ingestion, expressed through the model-routing conventions. Deterministic privacy wall: named-entity and sensitive-pattern classes are stripped before any model call; ambiguous content fails closed to human review. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): brain-link-discipline — verified links in every deliverable Composite: same-message link rule, path derivation via git ls-files, push-before-link ordering, subagent-relay path rewrite, bulk-list formatting. Fallback chain: verified hosted-remote URL, then repo- relative path with a scope note, then publish output offered as an attachable artifact (never promised as a URL). Extends _output-rules.md with the verified-deliverable-link canon and the in-page (relative) vs in-message (absolute) scope split. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): draft-in-voice — memory-grounded ghostwriting from validated profiles Load a validated voice profile, obey its hard rules, produce 2-3 drafts, run the voice-fidelity self-check, never auto-post. Ships the build-a- profile appendix (corpus threshold, fingerprint schema, profile page schema with provenance/consent/versioning) so users without a donor profile aren't dead-ended. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): bulk-ingestion — the disciplined bulk pipeline lifecycle + manifest substrate Composite: the schema-trial-evaluate-codify-bulk-monitor lifecycle spine plus the manifest.json durable-state substrate (stable source-derived ids, derived-not-asserted status, idempotent workers, per-worker progress-file merge, never trust a subagent's 'done' — verify on disk). Codify delegates to skillify; execution to jobs/minions; ramping to test-before-bulk. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(scripts): check-skill-refs reads cliHints from operations source --tools-json does not serialize every op's cliHints, so real commands (get, timeline, backlinks, graph, link) warned as unknown. The checker now also derives the known-command set from operations.ts cliHints names + aliases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): meeting-ingestion 2.0.0 — recorder-agnostic pipeline backport Normalized transcript record as the any-recorder contract, multi-meeting split detection, cross-recorder dedup, evidence-based speaker resolution (never guess; ASR-variant search-before-create), required page sections with explicit-reason-for-empty, claim-verification table, and the brain- contradiction consistency check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): meeting-ingestion 2.1.0 — verify-before-done phase Hard gate before reporting ingested: required sections have substance, every people/companies slug has a page + timeline backlink, speaker map resolved, every quote grounded verbatim in the transcript (deterministic sidecar checks where transcripts are retained), fabricated-attendee sanity checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): meeting-ingestion 2.2.0 — sequence verify (chronology checks) Deterministic order lint before a meeting page ships: phase-inversion and impossible-transit checks, day-timeline gaps corroborated against `gbrain day`, with a pass/block/explicit-waive contract (waives logged as acknowledged, not resolved). Adds routing-eval fixtures for the upgraded skill. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): reports 1.1.0 — Actionability Gate Four link failure modes (Broken/Dead/Indirect/Missing) with the rule "a missing link is honest, an indirect link is a broken promise", the blocked-vs-warning table, retry loop as agent-run checks, and the prompt gate snippet. Canon lives in _output-rules.md; this section carries the taxonomy delta. Routing fixtures added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): briefing 1.3.0 — pre-briefing context pulls Salience, anomalies, personal recall, and hot-memory pulse pulls before composing the briefing, wired to the real CLI flags (anomalies uses --lookback-days, not the upstream --since form). Routing fixtures added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): daily-task-manager 2.0.0 — stable IDs + fail-closed actions Stable task-ID anchors, deterministic action routing, fail-closed ambiguity handling (no mutation on zero/multiple matches), structured Returns contract with an agent-chaining JSON mode, minimal-diff save discipline. Routing fixtures added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): eiirp 1.1.0 — auto-fire gate (file before you deliver) Always-on convention: when substantial structured analysis of a user- shared document is about to be delivered, file the brain page first and deliver analysis + link in the same reply. Fire conditions, does-not- fire list, dedicated-pipeline exemptions, per-user storage-policy override. eiirp moves from plugin exclusion to bundled — the gate is load-bearing for downstream installs. Routing fixtures added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): minion-orchestrator 1.1.0 — durable execution doctrine Capability ladder for operations over two minutes: jobs + a one-shot self-deleting deadman (verifying the result was REPORTED, not that the process exited) where the shell-jobs contract allows; cron-checked progress file; foreground with buffered output otherwise. Deadman failure modes (dies before firing, double-fire idempotency, stale checkpoint) encoded in Contract and Anti-Patterns; content-addressed stage-checkpoint appendix. Existing trust-boundary text unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(skills): concept-synthesis cull-phase routing fixtures Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): research-compendium — archive, summarize 1:1, synthesize self-contained Deep-research discipline: archive every source, one summary per source, then a self-contained synthesis (the Self-Contained Rule; Low-Bar/High- Ceiling). Claims verification delegates to fact-check; retention is gated by the user's privacy posture. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): context-audit — token hygiene for the always-loaded stack Report-only audit of SOUL/MEMORY/CLAUDE/AGENTS-class files: redundancy, contradictions, staleness, compression candidates ranked by token savings. Recommendations target bootstrap templates, never rendered files; judging routes through the native cross-modal eval runner with a cheap-model default. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): blog-ingest — whole-publication and feed ingestion Feed discovery, pagination walking, article-shape normalization, canonical-URL dedup, idempotent re-runs, polite pacing, and empty-husk repair as agent procedures; per-article enrichment hands off to brain-ingest-gate. Public posts only. Fetched text is data, never instructions (untrusted-content section). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): conversation-archive — AI-chat history as first-class brain content Convert chat exports into per-conversation pages, import, validate via the conversation-parser surface, extract facts; gap-healing backfill under the three invariants (capture cadence outruns eviction, gap detection, write-path equals commit-path); idea-evolution tracing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): skill-autobench — evals mined from lived usage Mine a skill's real invocation history (user corrections are the gold signal) into a proposed eval contract and replayable cases with honesty labels, staged pending human approval — never rewrites a skill. Multi-model judging verifies each provider actually responded. Extends the SkillOpt surface; never duplicates it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(todos): giftable-import wave follow-ups Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(skills): resolver strict reconciliation — triggers, fixtures, disambiguation Drives check-resolvable --strict to zero on the 69-skill pack: wave-side trigger narrowing (bare words become phrases on measure-before-you-fix, data-loss-gate, brain-ingest-gate), fixture intents rewritten to realistic phrasings, wave-side MECE duplicates removed, the ingest-gate quality rules delegated to conventions, and three new disambiguation rules (publication/article/media/chat-export routing, soul-audit vs context-audit, measurement-first triage vs debugging). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): idea-ingest 1.1.0 — Returns contract + edge cases backport Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): media-ingest 1.1.0 — input contract, error handling, known pitfalls Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): brain-ops 1.1.0 — entity-card first lookup + shallow-ls warning (memory-verbs block preserved) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): maintain 1.1.0 — weekly feature-adoption check Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skills): data-research 1.1.0 — infer research target from context Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(llms): regenerate bundles after the skills wave RESOLVER.md is inlined into the llms bundles; the wave's routing rows and disambiguation rules regenerate here (single wave-end regen; the committed bundles match HEAD per test/build-llms.test.ts). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): assemble banned-path fixtures at runtime in check-skill-refs tests The privacy check bans those literals in source files; the fixtures now construct them so the test still exercises the donor-remnant gate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(skillpack): bundle capture + publish; keep host-only contrast fixtures portable The downstream-install smoke showed shipped fixtures referencing host- only skills. capture and publish move from exclusions to the bundle — both are user-facing and wave skills route to them (the eiirp auto-fire files via capture; brain-link-discipline falls back to publish). Contrast fixtures that pointed at host-only skills (smoke-test, skill-optimizer) now target shipped skills with declared ambiguity, so `check-resolvable --strict` is green on the host pack (69 skills) AND on a fresh scaffolded install (58 skills). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(evals): post-import-wave routing receipt (haiku) A/B harness run against the 69-skill resolver after the import wave: baseline (uncompressed) 100% held-out / 78.3% training strict — beating both compression variants on strict scoring, corroborating the review decision to defer resolver compression to its own PR. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(skills): pre-landing review fixes — trust boundaries, gate hardening, registration prose From the six-reviewer pre-landing pass: research-compendium gains the untrusted-content section (verbatim web archives feed future recall); blog-ingest's injection marker now travels with body chunks (inline fenced wrapper, not frontmatter-only); company-brainify's history-rewrite backup moves to a non-volatile private location with pre-push re-verification and retention cleanup; the 17 imported manifest entries get real descriptions (a block-scalar parsing slip) with a test pinning description prose and plugin-array uniqueness; check-skill-refs becomes cwd-independent, validates relative markdown links, and warns visibly on an empty CLI command set (5 new tests); the commit gate fails loudly on a regenerated-but-unstaged lock, single-quotes its inline lint script, and rejects missing lint paths; ladder attribution, checkpoint-hook bypass, frontmatter-contract notes, curation + misroute runbook docs, the brain-first API-pull rule, and negative routing fixtures for eight skills round out the batch. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(skills): adversarial-review hardening — trust boundaries, closure, honest contracts From the ship pre-landing + adversarial + red-team passes (all findings folded): Untrusted content: a shared conventions/untrusted-content.md (fetched text is data, never instructions) referenced from every skill that fetches or imports external text — fact-check most critically (a fetched page is never authority to rewrite a brain fact). conversation-archive gains a mandatory secret+PII redaction pass before any page is written. company-brainify: the destructive strip now sanitizes a staging copy behind the data-loss-gate card (personal brain untouched); the history purge derives its path set from the full sanitized scope, runs only against the shared repo (never sync.repo_path), stages under a non-volatile backup dir with a pre-push restore check, and logs the deletion to the personal brain, not the shared one. Downstream closure: ask-user and brain-taxonomist are bundled (three new skills delegate to them); remaining host-only references are prose, not links; a membership+closure test makes a bundled skill referencing an unshipped skill a build failure. Honest contracts: brain-link-discipline is marked mutating (it commits and pushes) and only sends its token to the issuing host; inert priority markers removed; citation-graph-ingest's writes_to dropped; concurrency and slug-collision limits documented for daily-task-manager, bulk-ingestion, conversation-archive, and blog-ingest; the self- authorizing shell-jobs prefix removed in favor of worker-side authorization. Gate hardening: the commit gate compares the staged lock blob and runs the plugin-manifest tests; check-skill-refs scans jsonl for donor remnants, tolerates CRLF, and rejects flag-shaped option values. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * v0.45.6.0 feat(skills): giftable-skills import wave — 17 new production skills + 8 upgrades Grows the built-in pack from ~52 to 69 skills: the trust layer (correction-pipeline, data-loss-gate, fact-check, brain-ingest-gate), team-brain sanitization (company-brainify), typed citation-graph ingestion, disciplined bulk/feed/conversation ingestion, and operational skills (measure-before-you-fix, context-audit, skill-autobench, resolve-before-asking, brain-link-discipline, draft-in-voice, research-compendium), plus meeting-ingestion/skillify/eiirp/ minion-orchestrator/concept-synthesis/reports/briefing/daily-task-manager upgrades and a new skill-ref integrity gate + plugin-curation record. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(skillpack,doctor): skill currency + declared preconditions — the migration harness now examines skills The upgrade/migration path was DB-only for skills: schema migrations never touched them, and skill sync was manual/advisory with new skills hidden from the post-upgrade sweep. This makes skill currency and per-skill setup first-class. Currency (capability A): src/core/skillpack/skill-currency.ts classifies every bundled skill against the install as new / drifted / current, by each skill's OWN files (shared conventions on disk no longer misclassify a new skill as drifted). `gbrain skillpack status` reports it; `gbrain skillpack sync` scaffolds only the new ones and never overwrites local edits; the post-upgrade sweep surfaces new skills with the sync command; `gbrain doctor` gains a `skill_currency` check (WARN when new skills are available, drift stays advisory). Preconditions (capability B): a `requires:` frontmatter field (source / dir:<path> / config:<key> / pages:<n>), a pure DI-seam checker in src/core/skillpack/preconditions.ts, `gbrain skillpack setup <skill>` for the static list + hints, and a `skill_preconditions` doctor check that verifies them live against the connected brain. Annotated only the two skills with genuine preconditions (citation-graph-ingest needs a corpus; skill-autobench needs the conversations/ archive). Semantic skill search (capability C) is deliberately deferred as its own subsystem (tenancy + source isolation + embedding backfill) — filed in TODOS, not crammed in unreviewed. Tests: skill-currency, skill-preconditions, skillpack-status (31 new assertions). doctor + skillpack stay engine-safe (currency is filesystem- only; live precondition checks skip cleanly without a brain). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(doctor,skillpack): categorize new skill checks, refresh flag registry, sweep test + noise gate CI on the pushed feature surfaced three real in-branch failures: - doctor-categories: register skill_currency + skill_preconditions under SKILL_CHECK_NAMES (every doctor check must be categorized). - flag registry: doctor's import of findGbrainRoot pulls bundle.ts (which runs git rev-parse --verify) into its flag scan; regenerated the known-flags allowlist to match (harmless over-inclusion, per the generator's design). - upgrade sweep: header renamed to 'Skillpack sweep (post-upgrade)'; new-skill surfacing gated on the host having scaffolded at least one skill, so a zero-skill (opted-out) host stays silent instead of getting 'N new skills' on every upgrade. Tests updated + a case added locking the surfacing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d35c9c9e44 |
v0.45.0.0 feat(bootstrap): paste-in personal-agent install for Codex + Claude Code (#3975)
* docs(designs): agent-bootstrap plan + design docs (normative, review-absorbed) The scrubbed, in-repo sources of truth for the gbrain bootstrap wave: AGENT_BOOTSTRAP_DESIGN.md (product scope/sequencing) and AGENT_BOOTSTRAP_PLAN.md (implementation; all review-finding IDs inlined). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(bootstrap): format spec, question bank, identity templates, bundled assets agent.json manifest (format_version 1, initialized sentinel) + machine-local install receipt [CX2-1, CX2-12]; 12-question/6-required interview bank with consent keys and a persist:false sink for the optional provider key [CX2-13]; ten {{TOKEN}} identity templates (generic, adapted to gbrain ops — gates call recall/query/put_page, write-through-ops rule, keyless agent-authored facts, silence contract); assets embedded compiled-binary-safe via file-type imports [ENG-6]. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(bootstrap): runbook, README paste block, bootstrap guide, TODOS entries BOOTSTRAP_FOR_AGENTS.md (agent-driven install runbook: CLI phase list is the source of truth, never-invent rules, Codex approvals preflight, keyless posture, failure-modes table, version stamp for the skew check); README gains the full-agent paste block pinned to latest-stable inside the Claude Code/Codex quick start (memory-only tier stays); docs/guides/bootstrap.md carries the full install/security/consent/degradation/uninstall contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(designs): spike instrument for the bootstrap wave (build order 0) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(bootstrap): interview + render engines Interview gate with read-back confirm-hash (any later answer change clears the confirmation — the hostile single-batch case is structurally impossible), per-answer provenance, caps + escaping at set time, config-sink routing for the provider key; renderer with hard-fail token sweep, subordinate fencing of principal input, never-clobber + backups, deterministic minimal mode for the template repo, scaled byte floors. 58 unit tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(bootstrap): private-repo lifecycle — repo create, attach, uninstall, run lock gh-gated private repo creation with API-verified privacy (rate-limit distinct from public), refuse-foreign-origin with attach as the sanctioned path, atomic bootstrap mutex (pid liveness + age + token), receipt-keyed uninstall that never wholesale-deletes the gbrain home and only offers --delete-brain for a brain it created; read-only PGLite lock probe (never opens the engine). 54 unit tests, injectable exec seam throughout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(release): latest-stable ref, template-repo publish job, bootstrap CI guards release.yml advances the latest-stable tag only after assets publish (the paste block's permanent ref — copies in the wild never rot) and gains a PAT-gated publish-template job verified against the vendored tree; two skip-graceful guards (sanctioned-ref + runbook stamp; template/token bijection + placeholder assertion + generator byte-diff) wired into verify; README + runbook re-admitted to the CI cache hash; vendored deterministic template tree generated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(context): IPC v2 turn_context + 8KB assembly + visibility resolver + session identity Discriminated-union IPC with handler map, protocol echo (stale-serve detection), shared-secret gate, server-side source binding, per-kind budgets; turn-context assembly (reflex pointers + volunteered pages + world-only hot facts) under a data-not-instructions envelope trimmed to the harness's 10KB hook-output cap; facts.default_visibility resolved through one helper at all four sites (explicit caller wins, typos fail closed); typed sessionId threads _meta.session_id into the hot-memory cache key. 50 new tests; 180 adjacent tests confirmed green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(persistence): secret-scan, gbrain sources push, durability unification Pattern secret scanner (own runtime allowlist, redacted previews, corpus-write redaction mode); sources push runs the whole scan→stage→commit→pull→push sequence under one cross-platform lock (mkdir-atomic, pid+age+token) with a deny-glob backstop, commit-first divergence-safe pull, refuse-unverifiable visibility, and push-status telemetry; gbrain-home choke point unifies GBRAIN_HOME semantics with config (0700); durability is parent-repo-aware and rotates its push log at 0600. 35 new tests; 200 existing green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(sources): harden/pull gates accept sources inside a parent git repo The bootstrap workspace registers brain/ (a subdirectory) as the source; the durability core already resolves the repo root, so the command gates now check inside-a-repo rather than .git-right-here [CX2-3]. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(serve): resident maintenance sweep + keyless capability probe The lock-owning serve process now closes the persistence loop: startup (3s post-connect, best-effort, unref'd) and idle (10-min quiet intervals through the injectable timer seam) sweeps run facts-fence reconciliation, deterministic link/timeline extraction over recent workspace pages, and spend-gated corpus ingest (skipped keyless — agent-authored fences cover it). gbrain sweep --once is the trusted CLI seam bootstrap verify uses. Capability probe renders the honest keyless/keyed report. Full reuse of the cycle extractor + extract cores; 26 new tests, neighbors green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(hooks): engine-free gbrain hook command, settings writers, transcript parser Four hook events (session-start digest + crashed-session recovery push, user-prompt turn-context injection under an 800ms deadline and the 10KB cap, stop buffers, session-end corpus write with redaction/retention/dedup + best-effort push); structural JSON settings merger keyed by a _gbrain marker (foreign hooks and permissions survive); dated host-spec registry; Claude Code .jsonl parser as a spec-target with a scrubbed 7-shape fixture. Heartbeat is counters-only by construction. 59 tests; zero engine modules in the import graph. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(bootstrap): cross-link the full-agent path from the connection docs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(bootstrap): dispatcher, verify, status — the command assembled gbrain bootstrap {status,interview,render,repo,hooks,verify,uninstall,attach}: engine-free except verify (owns its engine, in-process sweep — no live-serve conflict); phase list is the TS source of truth with install.jsonl telemetry and the support blob; verify's fail-soft check suite covers the real write path (put_page → write-through file → sweep → graph floor → recall), passes keyless, persists snapshots, and ends with the first-run tour. cli.ts wired per the three-touchpoint rule; doctor gains the bootstrap check group (silent on machines with no bootstrap state). 28 new tests; 353 adjacent green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: KEY_FILES bootstrap cluster + CLAUDE.md dispatcher row (+ build:llms) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(bootstrap): e2e pins — hook-under-live-serve, attach, degraded modes, compiled binary, Docker harness The permanent pins: a real serve holds the PGLite lock while the engine-free hook completes (and a direct engine open provably throws LiveServeLockError); stale-socket fail-open; machine-2 attach with marker-keyed hook repair; decline-everything installs verify green with every degradation named; the compiled binary renders bundled templates in an empty cwd. Offline Docker harness (networkless, read-only) gated into heavy-tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(bootstrap): register doctor check categories + system-of-record allow comments The six bootstrap doctor checks join OPS_CHECK_NAMES; the sweep's batch link/ timeline inserts carry the explicit extract-path allow comments (the sweep IS the extraction path for workspace pages). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): shard wedge cap tracks suite growth (1500s -> 1800s) At ~9000 tests a healthy shard finished at 1466s and two progressing shards were false-killed at the old cap; 1800s restores ~25% headroom over the slowest observed healthy shard. Real hangs still hit it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(ci): cache-hash policy — README + runbook edits must invalidate [C2] The old deny-list assertion predates the paste block; README.md and BOOTSTRAP_FOR_AGENTS.md are policy-doc re-admissions now, so their edits must change the hash (a paste-block edit shipping under a cached green was the C2 hole). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): classify post-suite exit-hangs as warn-pass; file the leak forensics A shard killed by the wedge watchdog with every assigned file started and zero fail markers did all its work and leaked a handle at exit — pre-existing and master-reproducible (P1 TODO carries the full bisect forensics). Bun's per-test timeout turns a hung test into a (fail), so the classifier cannot mask one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): shard cap 2400s — the count-balanced heavy shard needs it under contention Observed: the heavy shard still progressing 22s before an 1800s kill while siblings finish at 1150-1550s (split balances file count, not weight). Filed the load-sensitive WAL-repair flake (pre-existing, master's v0.42.75.0 wave). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(bootstrap): quarantine env-mutating suites to the serial lane check-test-isolation R1: six new files mutate GBRAIN_HOME/env at module scope — the serial lane (one process per file) is the guard's prescribed home for them. All 114 tests pass post-rename. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(readme): per-harness install sections — Codex, Claude Code, then OpenClaw/Hermes Each harness gets its own complete paste-block section (desktop app first, terminal noted — Claude Code CLI is the identical harness; Codex CLI works pull-based today); the OpenClaw/Hermes platform path keeps equal weight with its one-click deploys and INSTALL_FOR_AGENTS block intact; memory-only and remote-connect tiers consolidated under 'Lighter ways in'. Supersedes the review's D5 ordering by user direction; stale heading references updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(readme): Codex as the recommended first step; OpenClaw/Hermes framed as-intended, high-cost The install section now routes newcomers explicitly: Codex first (subscription-priced, nothing to deploy), OpenClaw/Hermes as GBrain used the way it was designed — always on, at real server + API cost. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: doc-audit code chasers — broken recovery hints, stale op description, auto_link key Four small code fixes surfaced by the markdown accuracy audit: - doctor's auto-RLS recovery hint pointed at `apply-migrations --force-retry 35`, which cannot work (--force-retry targets the vX.Y.Z orchestrator registry, not the numeric schema MIGRATIONS array). Hint now points at the recreate SQL in docs/guides/rls-and-you.md; test pins against regression. - v0_11_0 migration printed the same broken-mechanism class of hint (`config set minion_mode` writes DB config nothing reads); now names `apply-migrations --mode` + preferences.json, the real setter. - submit_job's op description hardcoded a stale handler list; now points at registerBuiltinHandlers as the source plus the --follow discovery trick. - `auto_link` added to KNOWN_CONFIG_KEYS: read by link-extraction, reconcile-links, and sweep, and documented as the off-switch in brain-ops/maintain, but the allowlist rejected `config set auto_link false`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: repo-wide accuracy + MECE reform from the 9-bucket markdown audit A code-grounded audit of every markdown file (root, architecture, guides, mcp, tutorials, docs-root, operations/eval/designs, skills, recipes) followed by a fix wave with per-bucket ownership. Four classes of change: Accuracy — every documented command/flag verified against src/ before writing: dead commands replaced with working ones (pages purge-deleted, jobs watch --follow, gbrain restore, import-based Obsidian flow, space-separated --scopes, real thin-client recipes, working isolation verification, real supervisor restart procedure, curl-based ngrok health check, real minion_mode setter); count drift fixed with rot-proof phrasing (100+ ops, 50+ bundled skills via skills/manifest.json, 140+ engine methods, KNOBS_HASH_VERSION pointer instead of hardcoded versions); stale claims corrected (search-mode defaults, RETRIEVAL pipeline order incl. autocut, sentinel rules, refusal-list mechanism, engine snapshot, shard cap 2400s + EXIT-HANG classifier in TESTING.md, latest-stable + publish-template documented in RELEASING.md as release.yml promises). MECE — one home per concept, pointers elsewhere: test isolation → TESTING.md; OAuth registration + --bind/--public-url lore → DEPLOY.md; mode bundles → guides/search-modes.md (the home the CLAUDE.md dispatcher always promised); merge contract → schema-packs.md; WAL ladder → ENGINES.md; quiet-hours → quiet-hours.md; capture taxonomy → entity-detection.md; person-page taxonomy → compiled-truth.md; brain-first protocol → brain-first-lookup.md; refresh semantics → refresh-algorithm.md; KEY_FILES.md deduplicated (58 extension entries merged, one entry per file); infra-layer.md rewritten as a pointer page. Privacy — placeholder sweep across guides, docs, skills, and recipes per the iron rule; per-release narration stripped from reference docs (current-state prose only). Bootstrap coverage — AGENTS.md pointer, RESOLVER routing row, INSTALL.md path, tutorial cross-links, keyless-mode sections in spend-controls/headless-install. skills.lock.json regenerated; llms.txt/llms-full.txt rebuilt. Gates: verify 36/36, typecheck clean, doctor 96/96, skills-integrity + resolver + build-llms + config-set + migrations all green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(readme): refresh production-brain stats to current brain-repo counts 155,795 pages / 24,589 people / 5,340 companies, counted from the brain repo's current HEAD; the "100K-page brain" framing moves to 150K to match. Cron-fleet count unchanged (its store lives on the deployment host, not in the repos available for verification). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(scan,push): modern OpenAI/Voyage key patterns, scan staged blobs not disk - secret-scan matches sk-proj-/sk-svcacct-/sk-None- and pa- Voyage keys (the bare sk- pattern missed every current OpenAI key format). - workspacePush stages first, then scans the staged index blobs via git cat-file, closing the scan-then-stage TOCTOU where a file changed between snapshot and commit shipped unscanned. - shared binary-sniff helper, memoized glob regexes, atomic push-status write, and tests for pull_conflict + gitignored deny-match paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ci): regenerate flag registry for new commands, harden shard classifier + release token - cli-flag-registry.generated.ts regenerated: bootstrap/hook/sweep and sources push --message/--allow-unverified-remote were missing, so the strict #2185 validator rejected real invocations and skipped the new commands entirely. - EXIT-HANG shard classifier now requires every assigned file to have started before warn-passing a watchdog kill (was fail-open). - release.yml passes TEMPLATE_REPO_PAT via http.extraheader, off the argv. - compiled-binary e2e fails loud in CI instead of a silent permanent skip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(hook,sweep,ipc): non-blocking hook pushes, bounded sweep + cache, source-bound resolve - session-start/session-end no longer run synchronous git + inline push inside their self-deadline; a detached child does the push and the hook returns immediately (blocked Claude Code startup for minutes on a dirty tree before). - serve sweep drops the unbounded listAllPageRefs, resolves only candidate targets, claims corpus files atomically (no double-LLM-spend race), and caps the fence LIKE scan; heartbeat writes are O_APPEND with rare compaction. - hot-memory cache evicts expired entries and bounds entry count (the key is caller-controlled via _meta.session_id). - v1 resolve IPC honors boundSourceId like turn_context; turn-context runs its arms concurrently. doctor reads push/heartbeat thresholds from hook.ts. - new tests: doctor bootstrap checks, hook push-gate + deadline, concurrent sweep claims, cache eviction, bound-source resolve. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(bootstrap): origin-ownership gate, world visibility, collision-safe source id, consent + templates - repo adoption requires an exact receipt repo_url match or authed-owner check (undefined repo_url was a wildcard); create verifies privacy BEFORE the first push. - verify sets facts.default_visibility=world if unset, so agent-authored facts surface in per-turn context (they defaulted private before). - source_id derives a path-hash suffix when 'workspace' is taken by another checkout; every consumer reads manifest.source_id. - skipped HOOKS_CONSENT now declines (was falling through to default yes); --minimal refuses on an initialized manifest; tilde fences escaped. - MCP registration pins --surface full; status hard-fails a public origin (template door); receipt writers guard against newer/corrupt receipts; uninstall only claims brain-deleted after a real rm. - templates ship jobs disabled + provider-consent + support-relay lines; soul-audit re-runs over the shared interview bank. TODOS: 11 follow-ups. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(security): close adversarial-review findings — scan fails closed, whole-PEM redaction, bound repo push Cross-model adversarial pass (Claude + Codex) on the bootstrap wave: - secret scan fails CLOSED: an unreadable, oversized, or binary staged blob now blocks the push (blocked_unscannable, exit 5) instead of committing unscanned; only a confirmed staged deletion is skipped. This was the headline "block secrets before they leave the machine" property failing open. - private-key redaction spans the whole PEM block (header+body+footer), not just the header line — the base64 body no longer survives into the corpus the sweep sends to an extraction provider. - bootstrap repo commits the workspace (secret-scan-gated) before the first push and verifies the remote actually received it, so a push-fail retry can't adopt an empty remote as success. - privacy verify is re-bound to origin immediately before push (a concurrent origin rewrite between verify and push is refused). - session-end corpus write is atomic and clears the stale ingested/in-progress sidecars so a resumed session's appended transcript is re-ingested. - public-origin refusal enforced at render (not only status); MCP "already registered" is verified to target this workspace, not blessed blindly; verify probe cleanup scopes deletes to its own slugs, not a token substring; allowlist fingerprint floor raised 8→16 hex. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * v0.45.0.0 feat(bootstrap): paste-in personal-agent install for Codex + Claude Code Turns a Codex or Claude Code session into a persistent personal agent: interview-rendered identity files, a local PGLite brain, per-turn context via serve IPC (Claude Code hooks / Codex pull protocol), session-triggered persistence, and a private GitHub repo as the agent's portable body. Keyless- first (the harness model is the LLM; one optional key adds embeddings + extraction). New `gbrain bootstrap` command family + `gbrain hook` + `gbrain sweep`; doctor bootstrap health checks; latest-stable distribution ref + template-repo publish job. Opt-in, additive — existing installs untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix: regenerate flag registry for security-fix flags; drop fabricated gbrain capabilities doc ref CI caught two real failures under the merged state: - the flag registry lagged the blocked_unscannable/exit-5 flags the security round added, tripping the #2185 freshness guard. - headless-install.md described the keyless capability report as a `gbrain capabilities` command, which the #3502 doc-command resolver rejects — reworded to prose (the real surface is bootstrap verify's report). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: sync KEY_FILES + bootstrap plan to security-fix behavior Cross-referenced the security-fix round against the reference docs and corrected the drift those commits introduced: - workspace-push.ts entry: stage-FIRST-then-scan order (the TOCTOU fix), fail-closed blocked_unscannable, and the sources-push status -> exit-code map. - hooks.ts entry: MCP registration pins `serve --surface full`. - hook.ts entry: session-start/session-end pushes run in a detached child (non-blocking); atomic corpus write clears stale sidecars. - bootstrap.ts entry: render hard-refuses a public origin (template door). - verify.ts entry: source_id collision resolution (workspace-<path-hash>). - AGENT_BOOTSTRAP_PLAN as-shipped delta note for the scan/stage reorder. llms bundle unchanged (KEY_FILES is link-only); build:llms and test/build-llms.test.ts green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ci): silence SC2016 on the intentional askpass literal in release.yml The one-shot GIT_ASKPASS script must contain literal $1 and $TEMPLATE_REPO_PAT so they expand when /bin/sh runs it at git's credential prompt, not when the outer shell writes the file — single quotes are correct. Add a scoped shellcheck disable so actionlint passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(skills): declare 'bootstrap my data' trigger in cold-start frontmatter The doc reform added 'bootstrap my data' to cold-start's RESOLVER.md row (to disambiguate data-bootstrap from agent-bootstrap) but not to the skill's own frontmatter triggers, tripping the RESOLVER↔frontmatter round-trip contract (resolver.test.ts). Declare it; regenerate skills.lock.json. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(bootstrap): default per-turn hooks + search mode ON without a prompt Installing gbrain for your coding agent IS the consent for the behaviors that make it work, so stop re-litigating them with install-time questions whose "no" defeats the product: - Per-turn hooks (Claude Code) install ON by default — no prompt. Off-ramps: `--no-hooks` at install, `GBRAIN_HOOKS=0` at runtime, `bootstrap uninstall`. The "hooks installed" line now surfaces the kill switch so default-on is never silent. A persisted HOOKS_CONSENT=no (interview --skip) still declines. - Search mode defaults to `balanced` silently (nobody knows the modes at install; `gbrain search modes` changes it any time). - MCP scope stays the ONE deliberate prompt — project vs user is a real cross-repo privacy choice, not friction. Marks the two consents `silent: true` in the question bank (new QuestionSpec field), rewrites the runbook phases so the agent no longer asks them, adds the `--no-hooks` flag (+ registry regen), and adds default-on / opt-out tests. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(bootstrap): real end-to-end coverage — cross-session recall, per-turn content, Codex door, realistic corpus Closes the seven e2e gaps a coverage audit surfaced: the plumbing was well-unit-tested but the product claims ("Codex works, context shows up every turn with real content, it remembers across restarts, machine two recovers, Postgres works") were unproven end to end. Test-only wave — zero src changes. - Hermetic synthetic corpus (test/fixtures/bootstrap-corpus/ + a loader helper): 12 interlinked pages (52 edges, timelines), 12 world/private beliefs, 8 gold queries — curated from the gbrain-evals synthetic corpora, 100% placeholder names, so recall is asserted on a real multi-entity brain instead of a 2-node self-planted probe. - GAP1 magic moment: author a fact via the real write path, disconnect the engine, reopen against the same DB, recall it — a real session boundary, not verify.ts's same-connection SQL read-back. Plus a source-isolation assertion. - GAP2 per-turn content: hook-under-serve Pin 1 now seeds a known fact and asserts its text lands in the injected block AND private beliefs never do (was: empty brain, empty_block accepted as a pass). - GAP3 Codex door: assert the rendered AGENTS.md carries the Gate-3 brain-first pull protocol; make the fake codex shim implement `mcp get` so the [FIX7] target-verification can actually fail; the Docker cold-machine harness now exercises the hooks/MCP registration step instead of skipping it. - GAP4 corpus recall: turn-context + verify graph-floor/qrels run on the real multi-entity brain with real edges. - GAP5 attach: machine-two now re-ingests the cloned brain/ into a fresh DB and recalls a fact authored only on machine one — the multi-device payoff. - GAP6 keyed + Postgres (env-gated): real embeddings prove semantic recall a paraphrase query can reach but keyless BM25 cannot; bootstrap verify drives a real Postgres engine (skipIf DATABASE_URL/keys absent). - GAP7 persistence: session-end runs the REAL push (not the mocked seam) to a local bare remote and the remote receives the content; a planted secret is blocked at the gate; the 15-min cron installs and fires a scan-gated push. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(bootstrap): real-agent e2e — drive the actual claude + codex binaries end to end Closes the audit's biggest gap ("no real harness ever drives a turn"). Adapts gstack's PTY/headless agent harness to prove the bootstrap install + smoke work against the REAL binaries, not PATH shims. Test/CI/docs only — zero src changes. - test/helpers/agent-harness.ts: hermetic clean-room child env (ported from gstack; drops CONDUCTOR_/CLAUDE_/GSTACK_/MCP_/GBRAIN_, promotes GSTACK_ANTHROPIC_API_KEY→ANTHROPIC_API_KEY), real-binary resolvers + auth probes, headless `claude -p --output-format stream-json` and `codex exec --json` turn runners, a gbrain stdio MCP-config writer, and a keyless brain seeder. + a fixture-parse unit test (no binary needed). - test/e2e/bootstrap-real-claude.serial.test.ts: real `gbrain bootstrap` install → REAL `claude mcp add` (verified via `claude mcp get`) → verify exit 0 → a real `claude -p --mcp-config --strict-mcp-config` turn that invokes mcp__gbrain__search and answers from the brain (proven: toolCalls include mcp__gbrain__search, final text carries the seeded fact). - test/e2e/bootstrap-real-codex.serial.test.ts: same install with REAL `codex mcp add` into a real ~/.codex/config.toml + Gate-3 pull-protocol assertion, then a real `codex exec --json` turn surfacing the fact (MCP or the pull- protocol shell path). Bounded retry absorbs codex's occasional MCP-call cancellation without softening the fact-requiring assertion. - Everything hermetic (temp HOME/CLAUDE_CONFIG_DIR/CODEX_HOME/GBRAIN_HOME; real ~/.codex auth copied read-only) and skipIf-gated so it self-skips cleanly where the binaries/auth are absent. - heavy-tests.yml: gated `real-agent-e2e` job (nightly/label, never the PR shard; no-op on a runner without authed binaries). - TODOS: compiled `gbrain` binary can't serve a PGLite brain (bun compile omits the WASM/extension payloads); harness falls back to `bun run` serve. Verified against live claude 4.6 + codex 0.147.0: 15 pass / 0 fail; verify 36/36; typecheck clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(ci): real-agent-e2e job — bash array + --timeout (actionlint SC2086 + bun-test-timeout guard) The real-agent-e2e job's file loop used an unquoted $FILES (SC2086) and ran `bun test` without --timeout (check-bun-test-timeout guard). Switch to a bash array and add --timeout=600000 (real-agent turns are slow; the tests self-skip without authed binaries so it's a no-op elsewhere). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(pglite): embed WASM + extension assets so the compiled binary can serve A `bun build --compile` gbrain binary could not `serve` a PGLite brain: the compile bundles JS but not PGLite's runtime payload (pglite.wasm, initdb.wasm, pglite.data, vector/pg_trgm tarballs), so `serve` on PGLite died with a bunfs/ENOENT. Now the assets ride inside the binary. - src/core/pglite-embedded-assets.ts: embeds the five assets via `import … with { type: 'file' }` (the ENG-6 idiom) and exposes getEmbeddedPgliteOptions() → { pgliteWasmModule, initdbWasmModule, fsBundle, extensions:{vector,pg_trgm} }. WASM/fsBundle are consumed as bytes; the two extension tarballs are materialized to a content-addressed temp file (atomic, size-verified reuse) because PGLite reads them via fs.createReadStream, which cannot read a /$bunfs path. Unconditional (works in bun-run and compiled), so no fragile mode branch. - src/core/pglite-engine.ts: static-import getEmbeddedPgliteOptions (engine path stays static per the engine-dynamic-import invariant); spread into both PGlite.create sites (initial + WAL-repair retry). The bunfs classifier stays as a backstop but no longer fires for a correct binary. - scripts/check-pglite-embedded.sh (+ smoketest): compiles a focused binary and asserts it boots PGLite, CREATE EXTENSION vector/pg_trgm, and round-trips a page — wired into `bun run verify` (now 37 checks), check:all, and check:pglite-embedded. Fail-soft only when compile is unavailable. - agent-harness.ts probeCompiledPglite now passes → the real-agent e2e uses the fast compiled MCP server. TODOS: the P2 "can't serve PGLite" item is closed. Verified: fresh compiled binary ran `search`/`query` against a PGLite brain and returned the seeded row (no bunfs/ENOENT); verify 37/37; pglite-engine 120/0 source-mode; typecheck clean; engine-dynamic-import + parity guards pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
130d321d23 |
v0.42.76.0 fix(upgrade,security,cli): strict flag validation, bootstrap-wedge class kill, federated chunk scope (#3902)
* fix(schema): bootstrap timeline_entries.event_page_id forward reference — un-wedge pre-v121 upgrades (#2626 #2594 #2579 #2537 #2536) v0.42.56.0 (Chronicle, migration v121) added timeline_entries.event_page_id and two partial indexes in the embedded schema blobs without extending applyForwardReferenceBootstrap — any brain whose timeline_entries predates v121 wedged initSchema at blob replay ("column event_page_id does not exist") before runMigrations could apply v121, with no in-band recovery. - Add the timeline_entries.event_page_id probe + column-only ALTER to applyForwardReferenceBootstrap in BOTH engines; FK + partial indexes land via the idempotent v121 / blob replay afterwards. Stays in the always-run bootstrap (never a migration hook — those skip oddly-stamped brains). - REQUIRED_BOOTSTRAP_COVERAGE entry + strip blocks in both runtime tests. - e2e: pre-v121 rewind → full initSchema converges (indexes re-created); wedged-brain recovery — a brain that already FAILED the upgrade attempt converges on retry with full final shape (column + FK + both partial indexes) and no ledger residue. Absorbs PR #2548 (@chetan-guevara) and the e2e test from PR #2623 (@colinagent) — thank you both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(schema): coverage guard cross-references migration-added columns — close the scan hole that shipped the v121 wedge The A2 static check treated a column as covered when the current CREATE TABLE body declared it. But a column that is BOTH in the blob's CREATE TABLE AND added by a migration is a forward reference by definition — on pre-existing tables CREATE TABLE IF NOT EXISTS no-ops and the blob's CREATE INDEX crashes initSchema before runMigrations can help. That mask is exactly how timeline_entries.event_page_id passed the guard while wedging every pre-v121 brain. - buildIndexRefCoveragePredicate: migration-added columns (from extractAddedColumnsFromMigrations over the MIGRATIONS array) require a bootstrap ALTER; CREATE TABLE presence no longer counts for them. - Unit test pins the v121 regression shape red/green with synthetic inputs; the A2 test pins the incident triple directly (migration-added + blob-indexed + bootstrap-covered). - The strengthened predicate immediately surfaced two more latent wedges of the same class: minion_jobs.timeout_at + minion_jobs.idempotency_key (migration v7, blob-indexed, unprobed). Added probes in both engines + coverage entries + runtime strip blocks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(security): serve --http hides the generated admin token from non-TTY output by default (#2624) Generated admin bootstrap tokens printed into container/log-aggregator stdout on every headless start. shouldSuppressBootstrapPrint now defaults to hidden unless stderr is an interactive TTY; env-sourced tokens are never printed; --print-admin-token is the explicit escape hatch for capturing the value on a trusted non-TTY start; --suppress-bootstrap-token still overrides everything. Unit-tested across all five postures. Absorbs PR #2625 (@irresi) — thank you. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(security): legacy bearer tokens honor permissions.takes_holders over serve --http (#2529) GBrainOAuthProvider.verifyAccessToken never returned takesHoldersAllowList, so the serve --http dispatch site always fell back to ['world'] — remote MCP callers with an operator-configured takes_holders grant saw only public takes. The legacy branch now extracts permissions.takes_holders exactly like src/mcp/http-transport.ts (fail-safe ['world'] default, non-string entries dropped, malformed permissions JSON fails closed without throwing), and AuthInfo carries the field as a typed contract. OAuth-registered clients have no takes_holders storage on oauth_clients; that lane is design work tracked in TODOS (column migration + DCR/ registration surface), not part of this hotfix. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(security): get_chunks honors the federated source grant + stops shipping embedding vectors (#2555, getChunks half of #2544) The get_chunks op still used the pre-#2200 scalar pattern (ctx.sourceId ? {sourceId} : {}) and engine.getChunks had no sourceIds[] support — a federated client that could read a page via get_page got [] from get_chunks. The op now routes through sourceScopeOpts (canonical ladder: federated array > scalar floor > nothing) and both engines gain the getPage-style sourceIds[] precedence branch; the unset-opts 'default' floor is preserved for local callers (importCodeFile contract). While in the function: SELECT cc.* pulled every embedding vector over the wire per chunk only for rowToChunk to discard them — replaced with the explicit non-vector column list in both engines (the getChunks half of #2544; the per-put_page getAllSlugs half is tracked separately). getChunksWithEmbeddings stays scalar-only by design (engine-internal, zero remote-reachable callers — documented at the interface). Tests: op-level federated repro + isolation + default-floor bleed guard (PGLite), engine precedence + Chunk-shape pin, and a DATABASE_URL-gated engine-parity test covering all three scope shapes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(auth): /admin/api/register-client accepts source + federatedRead bindings (#2143 enabler) The HTTP register endpoint hardcoded source_id='default' and federated_read=undefined — only the CLI could mint a client bound to a non-default source, so HTTP-registered MCP clients wrote into 'default' regardless of intent. The endpoint now accepts optional source / federatedRead body fields, validated via assertValidSourceId with a structured 400 on bad input; omitting both preserves the historical default. The admin-UI form layer is a tracked follow-up. Absorbs PR #2016 — thank you. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(scope,calibration): think reads over MCP; source-scoped takes reads; calibration CLI reachability + model resolution (#2078-class #2451) - think op → scope:'read' for OAuth/MCP clients: the handler already forces save/take off for remote callers before persistence, so a read-scoped token can think without a write grant; local CLI persistence unchanged. Scope-annotation test carries an explicit remote-gated allowlist. - takes_list / takes_search / takes_scorecard / takes_calibration route through sourceScopeOpts (the #2200 class on the takes read lane) with engine support in BOTH engines + tests. - 'calibration' added to CLI_ONLY (the command was registered but unreachable — dispatch-gap class) and calibration_profile/voice-gate resolve models through the canonical gateway tier resolver instead of bare ids that parseModelId rejects. - BigInt-safe local-op output normalization (bigintToStringReplacer, postgres.js wire parity) — first half of the #2450 fix; the formatResult default case lands with the cli-output commit. Absorbs PR #2598 (@colinagent) and PR #2452 (@spinsirr) — thank you both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(cli): output correctness — BigInt-safe rendering, search --json, files bigint, and 5 unreachable commands (#2450 #2527 #2042 #2035-class) - normalizeLocalResult wraps the local-op output round-trip with the bigint→string replacer (postgres.js wire parity; a bare stringify THROWS on BIGSERIAL keys); formatResult's default renderer gets the same replacer so nothing upstream can crash it. - search/query --json: CLI-local formatter flag threaded through the shared formatter — stdout is a parseable result array, never human text on the --json path (the #2042 residual). - file_list normalizes size_bytes (Postgres BIGINT → Number) so MCP serialization and the CLI KB math survive; null preserved. - NEW dispatch-gap guard: every handleCliOnly top-level case label must be reachable via CLI_ONLY. It immediately caught FIVE live unreachable commands: pages, backfill, reconcile-links, notability-eval (added to CLI_ONLY), and the documented 'gbrain search modes|stats|tune' dashboards (pre-fix, 'search modes' silently keyword-searched the word "modes") — now routed via a pre-dispatch subcommand gate. 'whoknows' stays on its op-alias route (collision guard); tracked with PR #2509. Absorbs PR #2494 and PR #2531 (@javieraldape) and adapts PR #472 (@vinsew) — thank you. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(db): updateSourceConfig survives mixed-array config rows + repair/doctor cover the subagent jsonb columns (#2251) The array-coercion branch called jsonb_each(elem) bare — a mixed array (e.g. '["x", {"last_full_cycle_at": ...}]') threw 'cannot call jsonb_each on a non-object' DURING row production, permanently failing every subsequent updateSourceConfig (last_full_cycle_at could never be written again). Non-object elements are now neutralized inline via a CASE-guarded jsonb_each; the row self-heals to a flat object on the next write, object elements' keys recovered. Pinned ungated on PGLite (real Postgres semantics) and via a DATABASE_URL-gated e2e on the real engine. repair-jsonb + doctor's jsonb_integrity check extend from 5 to 8 columns (subagent_messages.content_blocks, subagent_tool_executions.input/output — historical damage rows from the pre-v0.42.53.0 positional double-encode; the write paths themselves were fixed in #2375) with a to_regclass skip for brains predating those tables. Adapts the repair/doctor extension from PR #597 (@vinsew) — thank you. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(cli): dry-run honesty — strict unknown-flag rejection CLI-wide + unify-types worker defaults to dry-run (#2185 #1575) #2185: 'gbrain init --migrate-only --dry-run' applied REAL migrations — flags are read ad hoc (args.includes) so anything a handler doesn't look for was silently ignored, including intent-bearing safety flags. The CLI now validates every flag pre-dispatch and pre-engine: - Op commands validate against the operation contract (op.params + CLI-local --json/--explain), mirroring parseOpArgs so flag values that begin with '--' are never misread. parseOpArgs also gains the --key=value inline form (previously parsed as a junk key that consumed the NEXT token). - CLI_ONLY commands validate against a GENERATED per-command registry (scripts/generate-flag-registry.ts scans each command's case block + imported modules + one level of relative imports; deliberately over-inclusive so a missed flag can't break a working invocation). Committed as src/core/cli-flag-registry.generated.ts; 'bun run build:flag-registry' regenerates. - Passthrough by construction: everything after '--', plus call / config / 'jobs submit' payloads (handler-defined params are their contract). - Guards: sweep test (every command × nonsense flag → error), acceptance tests (real flags, --no- negation, = form, -- passthrough), drift guard (every CLI_ONLY member has an entry), freshness guard (committed registry == fresh generator run), subprocess smokes incl. the literal #2185 repro failing loud with zero engine work. BREAKING: scripts passing stray flags now fail loud with "Unknown flag --x for 'gbrain <cmd>'" — that is the point. #1575: the unify-types worker registration passed apply ?? true while the handler documents 'Default false (dry-run)' — the canonical operator invocation destructively retyped 25K+ pages by default. Now ?? false with a structural test; explicit --params '{"apply":true}' is the only way to mutate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs(todos): file fix-wave 1 follow-ups (OAuth takes_holders design, parseFlags end-state, whoknows routing, #2544 half, #1558 UI, #2536 diagnostics) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): memory-safe unit runner — adaptive concurrency + serial OOM rescue pass A default run (4 shards × 4 intra-shard files) holds up to 16 concurrent PGLite WASM instances (~1.5GB each). With sibling Conductor workspaces running their own suites, PGLite connect failed with 'Out of memory' across every shard at once — 369 phantom test failures on a healthy branch, indistinguishable from real breakage at a glance. Two default-on layers in scripts/run-unit-parallel.sh: 1. Memory-aware sizing: total concurrency is capped to available memory (vm_stat on macOS, MemAvailable on Linux) at GBRAIN_TEST_MEM_PER_FILE_MB (default 1536) per concurrent file, shedding shards before intra-shard width. Quiet machines are unaffected (banner: mem-ok); pressured ones degrade instead of OOMing (banner: mem-adapted AxB→CxD). 2. Serial OOM rescue: failures whose shard log carries the WASM out-of-memory signature are re-run at --max-concurrency 1 after the fan-out drains. Phantoms pass serially → run goes green with an oom_rescued note and the failure blocks marked superseded; real failures fail again and stay red. Plain assertion failures never match the signature and never enter the rescue lane (existing exit-code and failure-log contract tests unchanged). Escape hatches: GBRAIN_TEST_NO_MEM_ADAPT=1, GBRAIN_TEST_NO_OOM_FALLBACK=1. Tests: OOM-once fixture rescued to exit 0; kill-switch stays red; banner advertises the sizing verdict. Documented in docs/TESTING.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test,cli): merge-seam repairs — shard timeout for the tripled suite, init flag-error contract, think scope exemption Three post-merge repairs surfaced by the first full-suite run: - Shard timeout 1500s -> 3000s: the suite roughly tripled since the cap was sized (~3900 -> 11k+ tests; PGLite inits replay 120 migrations, was 92). Two shards were killed mid-progress at 1500s. - The #2185 pre-dispatch validator now emits the same error contract as init.ts's in-handler check it preempts: lowercase 'unknown flag' on stderr + structured {status:'error', reason:'invalid_flag'} on stdout for --json callers (pinned by test/init-migrate-only.test.ts). - test/operations-trust-boundary.test.ts gets the same documented remote-gated allowlist for think's read scope (#2598) that test/oauth.test.ts already carries. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): rescue lane also covers externally-killed shards (sibling-workspace pkill / memory jetsam) Second phantom class observed on a multi-workspace Conductor machine: 3 shards SIGTERM'd + 1 SIGKILL'd at ~700s under a 3000s cap, all mid-progress — an external killer, not a wedge. The dead shards then poisoned the serial pass (lock/state residue → 18 more phantoms), and every one of the 18 passed standalone. The runner now stamps per-shard start/end epochs; a shard dying on 143/137 before 80% of SHARD_TIMEOUT is classified externally-killed and its file list joins the serial rescue queue (real wedges die AT the cap and stay red). Serial-pass failures that occur while any shard was externally killed are treated as suspect residue and rescued too. Structural tests pin the detector, threshold, and routing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(auth): keep tokenEndpointAuthMethod terminal in the register-client destructure (PKCE structural contract) The #2016 absorb appended source/federatedRead after tokenEndpointAuthMethod; test/fix-wave-structural.test.ts pins tokenEndpointAuthMethod as the final destructured field (v0.36.1.x #1077 PKCE regression contract). The added fields move into the regex's optional-middle slot. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): re-apply the #2598 remote-gated scope exemption to master's oauth scope-annotation test Taking master's v0.42.74.0 oauth.test.ts (its #2529 implementation) dropped the think read-scope allowlist that PR #2598 carries; re-applied to match test/operations-trust-boundary.test.ts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(review): pre-landing review batch — CLI-local flag acceptance, json= coherence, re-landed getChunks trim, payload-aware jsonb repair, rescue-lane tightening Ship Step 9 findings (checklist pass + 4 specialists), all verified before fixing: - CRITICAL: the #2185 validator rejected --source/--dry-run on op commands (makeContext CLI-locals consumed outside the op contract) — 'gbrain search "x" --source y' exited 1. Exempted with parser-mirroring value consumption + unit/subprocess tests incl. global-flag acceptance. - CRITICAL: --json=<v> diverged between validator (accepted) and parseOpArgs (junk-key path consumed the NEXT token, corrupting positionals). Parser now handles --json=true|false; =-forms of bare-only CLI-locals reject loud. parseOpArgs inline-= suite added (regression rule). - CRITICAL: the master merge silently restored SELECT cc.* in both engines' getChunks while docs claimed the #2544 trim. Re-landed the explicit non-vector column list + a source-level structural pin so a merge can't silently undo it again. - repair-jsonb/doctor: the subagent columns legitimately hold jsonb string scalars (persistToolExec binds pre-serialized strings) — unconditional unwrap would abort the repair run or corrupt legit values. jsonPayloadOnly predicate (JSON-container content only) on those 3 targets, mirrored in doctor + parameterized to_regclass + behavioral test (damage flagged, legit string ignored, absent table skipped). - runner rescue-lane tightening: serial failures rescue-eligible only with their own OOM signature or after an external shard kill (residue), never because a sibling shard OOM'd — flaky serial tests stay red. Rescue passes no longer double-count into TOTAL_PASS; shard timeout scales when mem-adaptation sheds shards; negative-path tests (mixed run stays red, deterministic OOM-signature failure stays red). - fail-closed remote spelling at 2 forward sites (ctx.remote !== false per the CLAUDE.md invariant); registry generator drops template-literal flag prefixes; real-PG e2es for the v121 + minion_jobs wedge classes; stale comments corrected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: regenerate flag registry after master merge (#3864 added extract help flags) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(review): red-team batch — dispatch-order validation, real --dry-run boolean, rescue-lane timeout/isolation/cap, parseable-payload repair gate Red-team pass (post-specialist) findings, all verified before fixing: - CRITICAL: validateCommandFlags checked the op lane before CLI_ONLY while dispatch runs CLI_ONLY first — dual-lane commands (think/salience/ anomalies) were validated against the WRONG contract, rejecting documented invocations ('salience --kind entity'). Lane order now mirrors dispatch. - CRITICAL: --dry-run was blessed as legal on op commands but parseOpArgs never SET it (trailing → nothing → ctx.dryRun false → the REAL destructive action ran; leading → consumed the next token). Now a CLI-local boolean exactly like --json, with --dry-run=false support and regression tests. - CRITICAL: the rescue lane ran bun test WITHOUT --timeout=60000 (bun default 5s) — PGLite phantoms re-failed on timeout and were mislabeled 'confirmed real'. Both rescue invocations now mirror the shard flags; serial files re-run one process per file (run-serial-tests.sh isolation contract); rescue wallclock capped at 2x the shard timeout. - CRITICAL: the jsonPayloadOnly probe matched container-LOOKING invalid JSON ('[INFO] fetch complete') whose repair cast would throw and abort the run mid-loop. Predicate now gates on pg_input_is_valid (PG16+, same floor as the existing IS JSON usage) + per-target catch records and continues; doctor mirrors; behavioral test covers the lookalike row. - Registry generator bounded at handleCliOnly's closing brace (the LAST case block absorbed ~100 junk flags from the rest of cli.ts, neutering strict validation for it); uppercase flag typos reject loudly in both lanes (handlers are lowercase-sensitive); --json=true spelling gets the structured invalid_flag envelope; get_chunks __all__ narrowing filed as a Wave 3 TODO. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(engines): getChunks trimmed SELECT must carry modality (codex P1-B) The #2544 egress trim replaced SELECT cc.* with an explicit column list but omitted cc.modality — every rowToChunk field except the vector must survive the trim, or the embed round-trip (getChunks -> upsertChunks) rewrites image chunks as text. Both engines; the structural pin now iterates the full rowToChunk field list instead of spot-checking. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(cli): safety flags require consumption evidence in the flag registry (codex P1-A) upgrade.ts prints a help hint naming another command's --dry-run; that literal is depth-0 text for post-upgrade, so the generator allowlisted --dry-run there — recreating the exact #2185 repro this wave kills (post-upgrade --dry-run accepted, ignored, migrations run for real). Safety flags now need a tight-quoted standalone literal (an args read like has('--dry-run')) before the registry grants them; prose bleed embeds the flag inside a longer string and never qualifies. Regenerated registry drops --dry-run from post-upgrade, keeps genuine consumers. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * v0.42.76.0 fix(upgrade,security,cli): strict flag validation, bootstrap-wedge class kill, federated chunk scope Version bump + CHANGELOG for the fix wave: CLI-wide unknown-flag rejection with a generated per-command registry (#2185, #1575 class), minion_jobs bootstrap probes + migration-aware coverage guard (v121 wedge class), get_chunks federated scope + egress trim (#2555, half of #2544), think read-scope over MCP (#2598), register-client source bindings (#2016, #2143 enabler), repair-jsonb/doctor subagent columns with a parse-validated damage predicate, memory-safe unit-test runner. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: update project documentation for v0.42.76.0 CONTRIBUTING.md: test-runner claims match the memory-safe 4-shard default (was 8-shard) and the CLI-only command recipe now includes the build:flag-registry regen step. KEY_FILES.md: repair-jsonb entry updated to the 8-column parse-gated current state; new entries for the strict flag-validation subsystem and src/core/source-id.ts; operations/engine/ serve-http entries updated for get_chunks scope ladder + trimmed SELECT and the register-client HTTP source bindings. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: apply doc-review fixes for v0.42.76.0 Cross-model doc review caught stragglers: docs/TESTING.md still said 8-shard in the file taxonomy, carried a two-generations-stale shard timeout default (600s -> 3000s), and didn't name the new run-unit-parallel regression test or the remaining runner knobs; CONTRIBUTING.md's fast-loop file count predated the tripled suite (92+ -> 1000+); test-count claims unified at 3700+; the CLIENT_FENCED_WRITE_OPS comment in operations.ts still described think as scope write; KEY_FILES names the exported findUnknownFlag. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): rescue lane survives CI — strip ::group:: prefixes, satisfy the bun-test-timeout guard Two CI-only breaks from the master merge: (1) under GITHUB_ACTIONS the shard wraps file sections as ::group::path.test.ts, so the rescue pass extracted literal ::group:: non-paths that matched zero test files — failing_files_in_log now strips the prefix; (2) master's new check-bun-test-timeout guard greps for bare 'bun test' and tripped on run_rescue's comment text (the invocations themselves carry --timeout=60000) — comment reworded. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(test): shard-mechanics tests disable mem-adaptation — CI's 7GB runner collapsed explicit 2 shards to 1 The runner deliberately adapts even explicit --shards to available memory (GBRAIN_TEST_NO_MEM_ADAPT=1 is the escape hatch); on GitHub's ~7GB runners that collapsed the tests' 2-shard sandbox runs to 1 shard, breaking every 'shard 1/2:' expectation while passing locally. The tests pin shard MECHANICS with tiny synthetic files, so they now set the escape hatch; the one test that checks the mem banner overrides it back on. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
e3806cf46f |
fix(test): kill timeout-resistant unit shards (#3631)
Co-Authored-By: Vyacheslav Zakharov <vyacheslav.zakharov@avers.kz> |
||
|
|
945fed6105 |
fix(engine): enforce static engine-live import boundaries (#3596)
* docs: design engine dynamic-import reconciliation Co-Authored-By: Claude <noreply@anthropic.com> * fix(engine): reconcile dynamic import hardening Co-Authored-By: Claude <noreply@anthropic.com> * test(engine): guard dynamic import policy * docs: plan engine dynamic-import reconciliation Record the approved TDD sequence for selective engine-path hardening, repository guard wiring, documentation, and local verification. Preserve the no-version-bump and no-publication boundaries for the remaining work. Co-Authored-By: Claude <noreply@anthropic.com> * docs(engine): record static import invariant * fix(engine): parse block comments in import guard Co-Authored-By: Claude <noreply@anthropic.com> * fix(engine): parse dynamic imports with TypeScript Co-Authored-By: Claude <noreply@anthropic.com> * fix(engine): close import guard bypasses Co-Authored-By: Claude <noreply@anthropic.com> * fix(engine): close parser guard edge cases Co-Authored-By: Claude <noreply@anthropic.com> * fix(engine): aggregate parser diagnostics Co-Authored-By: Claude <noreply@anthropic.com> * fix(engine): bound dynamic import marker directive Require the line-level opt-out marker to be standalone inside real comment trivia so negated or incidental longer tokens cannot authorize an import. Preserve the existing general marked-line contract and pin it with focused regression coverage. Co-Authored-By: Claude <noreply@anthropic.com> * fix(engine): close Unicode marker boundary bypasses Treat Unicode identifier continuations as marker-token characters and inspect adjacent text by code point so supplementary-plane characters cannot turn longer comment tokens into approvals.\n\nCo-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
1f319e6d5a |
fix(scripts): capture check/shard rc before watchdog teardown in no-timeout fallback (#2864) (#3340)
On machines with neither gtimeout nor timeout on PATH, run-verify-parallel.sh and run-unit-parallel.sh fall back to a bg-pid + sleep-watchdog cap. Both read $? only after tearing the watchdog down (kill + wait on cap_pid), so the sentinel .exit files recorded the killed watchdog's status — 143 — instead of the check/shard's own exit code. Every run reported total failure (verify: pass=0 fail=31; unit: rc=143 per shard) while every per-check/shard log showed success. Capture rc immediately after `wait $pid` in both scripts, and reap the watchdog's sleep child (pkill -P, children-first — the same orphan quirk the heartbeat cleanup documents) so the fallback stops leaking one sleep per check/shard. Regression tests force the fallback branch hermetically on any host via a curated PATH with no timeout binaries: the verify dispatcher runs from a tempdir copy with a stubbed `bun`, pinning exit 0 + all-zero sentinels when checks pass and the check's own rc (not 143) when one fails; the unit wrapper runs real two-shard fixture passes, pinning rc=0 sentinels and a real failure's rc=1. Co-authored-by: paul-0320 <paul@ymyd.co.kr> Co-authored-by: YMYD <53603073+OJ-OnJourney@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
35edd0e2d5 |
Revert "fix(scripts): capture check/shard rc before watchdog teardown in no-timeout fallback (#2864)"
This reverts commit
|
||
|
|
e9a4fee97f |
fix(scripts): capture check/shard rc before watchdog teardown in no-timeout fallback (#2864)
On machines with neither gtimeout nor timeout on PATH, run-verify-parallel.sh and run-unit-parallel.sh fall back to a bg-pid + sleep-watchdog cap. Both read $? only after tearing the watchdog down (kill + wait on cap_pid), so the sentinel .exit files recorded the killed watchdog's status — 143 — instead of the check/shard's own exit code. Every run reported total failure (verify: pass=0 fail=31; unit: rc=143 per shard) while every per-check/shard log showed success. Capture rc immediately after `wait $pid` in both scripts, and reap the watchdog's sleep child (pkill -P, children-first — the same orphan quirk the heartbeat cleanup documents) so the fallback stops leaking one sleep per check/shard. Regression tests force the fallback branch hermetically on any host via a curated PATH with no timeout binaries: the verify dispatcher runs from a tempdir copy with a stubbed `bun`, pinning exit 0 + all-zero sentinels when checks pass and the check's own rc (not 143) when one fails; the unit wrapper runs real two-shard fixture passes, pinning rc=0 sentinels and a real failure's rc=1. Co-authored-by: YMYD <53603073+OJ-OnJourney@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
d4211f4176 |
v0.42.11.0 feat(skillopt): held-out eval gate, honest receipts, ENFORCE + ablation opts (#1759)
* feat(skillopt): wire held-out gate, honest receipts, ENFORCE + ablation opts Wire the F11 held-out gate into the orchestrator at checkpoint acceptance (runHeldOutGate was dead code); parse + thread --held-out through CLI, batch, fleet, background job, and the run_skillopt MCP op. Populate the real receipt.baseline_sel_score (was hardcoded 0) and add a final-test eval (test_score + baseline_test_score) via a shared scoreSkillOnTasks primitive. Fix the --no-mutate proposed.md write (was a stub) and enforce maxRuntimeMin. D16 ENFORCE in core mutation policy (assertBundledMutationHeldOut): mutating a bundled skill in place requires a non-empty (>=5), benchmark-disjoint held-out set or hard-refuses. Add three eval-internal ablation opts (reflectMode, disableValidationGate, optimizerMode='one-shot-rewrite') recorded in the receipt + audit; ROLLOUT_SUCCESS_THRESHOLD named constant. Security: run_skillopt MCP op validates skill_name (kebab-only) and confines caller-supplied benchmark/held-out paths to the skills dir for remote callers. * test(skillopt): held-out gate, ENFORCE, one-shot rewrite, runtime + receipt honesty New test/skillopt/rollout.test.ts (rollout had zero coverage). Held-out ENFORCE unit cases + one-shot-rewrite fence handling (whole-response unwrap, embedded-fence preserved, error path). E2E: F11 held-out BLOCKS/ALLOWS, bundled no-mutate write, reflectMode/disableValidationGate/optimizerMode, maxRuntimeMin abort, receipt baseline/test-score honesty, held-out/benchmark disjointness, D2 no-DB-pollution. * chore: bump version and changelog (v0.42.9.0) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: document skillopt held-out gate + bundled mutation requirement for v0.42.9.0 Wire --held-out into the skill-optimizer SKILL.md, guide flags/safety tables, and the tutorial's bundled-skill step: mutating a bundled skill in place now requires --allow-mutate-bundled AND --held-out (>=5 benchmark-disjoint tasks) or it hard-refuses. Add the --held-out flag row + F11 held-out gate to the guide; update the receipt contract to the honest baseline/test-score fields. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(gateway): AI SDK v6 toolLoop compat — multi-turn tool calls work again The ai@6.x bump tightened ModelMessage + tool-schema validation, which silently broke every multi-turn tool loop. Both `gbrain skillopt` rollouts and production background `subagent` jobs route through `chat()`/`toolLoop` and crashed the moment the model called a tool ("messages do not match the ModelMessage[] schema" / "schema is not a function"). Surfaced end-to-end by the SkillOpt real-LLM eval. Three fixes: - chat(): wrap tool defs with the SDK's `jsonSchema()` helper instead of a bare `{jsonSchema}` object (v6 asSchema() treated the bare object as a thunk and threw). - chat(): new exported pure `toModelMessages()` converts gbrain's provider-neutral ChatMessage[] into v6 ModelMessage[] — tool results ride a dedicated `role:'tool'` message with structured `{type,value}` output; null output preserved as json null. Load-bearing for the production subagent path, not just skillopt. - rollout.ts: replace the inline params→schema mapper (dropped `items` on array params) with the shared `paramDefToSchema` single source of truth. Pinned by test/gateway-model-messages.test.ts (8 cases). Folds into the open v0.42.9.0 PR (#1759) — these complete the eval-readiness wave by making skillopt actually run against a live model. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(skillopt): budget no-pricing for Haiku silently scored every rollout 0 Surfaced by the SkillOpt real-LLM eval (Track B). Two coupled bugs that made a budget-capped Haiku run report a vacuous "0/N" measurement in ~2ms with zero LLM calls — indistinguishable from a real deficient-skill score: 1. Claude Haiku 4.5's canonical dateless id (`claude-haiku-4-5`) was missing from anthropic-pricing.ts (only the dated `-20251001` was present). With `--max-cost` set, BudgetTracker.reserve() threw no_pricing on the FIRST chat() of every rollout. Added the dateless entry (sonnet already had its dateless form). 2. runValidationGate swallowed that BUDGET_EXHAUSTED error — runWithLimit settled it as {ok:false}, which the gate turned into median:0. A pricing/cap crash became a fake score. The gate now scans settled results for isMustAbortError() and re-throws so the caller aborts loudly; ordinary (non-abort) rollout errors still fail-open to 0 (judge-hiccup posture kept). Pinned by test/skillopt/validate-gate-abort.test.ts (3 cases). Folds into the open v0.42.9.0 PR (#1759). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ci): llms-full.txt over size budget — drop what-schemas-unlock from full bundle The toolLoop + budget bug-fix annotations grew CLAUDE.md, pushing llms-full.txt to 756KB over the 750KB FULL_SIZE_BUDGET (the `build-llms > size budget` test failed, failing the `test` CI job). CLAUDE.md stays inlined by design (it's the point of the one-fetch bundle), so per the budget comment's own guidance ("ship with includeInFull=false exclusions") this excludes docs/what-schemas-unlock.md (15.4KB value-explainer, not load-bearing operational reference) from llms-full.txt; it stays linked in llms.txt. Bundle now 740KB with ~9KB headroom. No budget bump — 750KB is near the ~190k-token-context fit ceiling. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(ci): re-admit policy docs into ci-cache-hash before doc relocation docs/**/*.md is deny-listed from the CI cache hash (test-irrelevant). The CLAUDE.md restructure moves test/release POLICY into docs/TESTING.md + docs/RELEASING.md, which DO carry contracts the test suite reads. Without re-admitting them, a policy-only edit would produce the same cache hash and skip the test shard that runs the build-llms + doc-history guards (false-pass). Adds an ALLOW_PATTERNS re-admit step after the deny, scoped to the named policy docs (not a blanket docs un-deny). Lands FIRST, before any doc moves. Pinned by 3 new cases in test/scripts/ci-cache-hash.test.ts: TESTING.md + RELEASING.md edits MUST change the hash; docs/guide.md still must not. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(docs): relocate Key files / thin-client / Testing out of CLAUDE.md (verbatim) CLAUDE.md had grown to 592KB / ~147k tokens auto-loaded every session (~77% of the llms-full.txt single-fetch bundle). The per-file index was append-only by mandate. This is the exact thin-dispatcher-vs-fat-blob anti-pattern gbrain exists to fix, so CLAUDE.md becomes a thin orientation + resolver that points at on-demand docs. This commit is the VERBATIM move (content-preserving — the next commit compresses): - docs/architecture/KEY_FILES.md <- ## Key files + the calibration key-files cluster + Schema Cathedral v3 impl detail - docs/architecture/thin-client.md <- ## Thin-client routing - docs/TESTING.md <- ## Testing - ## Commands DROPPED (18 'added in vX.Y' history blocks; current surface is gbrain 0.41.38.0 -- personal knowledge brain USAGE gbrain <command> [options] SETUP init [--pglite|--supabase|--url] Create brain (PGLite default, no server) migrate --to <supabase|pglite> Transfer brain between engines upgrade Self-update check-update [--json] Check for new versions doctor [--json] [--fast] Health check (resolver, skills, pgvector, RLS, embeddings) integrations [subcommand] Manage integration recipes (senses + reflexes) PAGES get <slug> Read a page put <slug> [< file.md] Write/update a page delete <slug> Delete a page list [--type T] [--tag T] [-n N] List pages SEARCH search <query> Keyword search (tsvector) query <question> [--no-expand] Hybrid search (RRF + expansion) ask <question> [--no-expand] Alias for query IMPORT/EXPORT import <dir> [--no-embed] Import markdown directory sync [--repo <path>] [flags] Git-to-brain incremental sync sync --watch [--interval N] Continuous sync (loops until stopped) sync --install-cron Install persistent sync daemon export [--dir ./out/] Export to markdown export --restore-only [--repo <p>] Restore missing supabase-only files [--type T] [--slug-prefix S] With optional filters FILES files list [slug] List stored files files upload <file> --page <slug> Upload file to storage files upload-raw <file> --page <s> Smart upload (size routing + .redirect.yaml) files signed-url <path> Generate signed URL (1-hour) files sync <dir> Bulk upload directory files verify Verify all uploads EMBEDDINGS embed [<slug>|--all|--stale] Generate/refresh embeddings LINKS link <from> <to> [--type T] Create typed link unlink <from> <to> Remove link backlinks <slug> Incoming links graph <slug> [--depth N] Traverse link graph (returns nodes) graph-query <slug> [--type T] Edge-based traversal with type/direction filters [--depth N] [--direction in|out|both] TAGS tags <slug> List tags tag <slug> <tag> Add tag untag <slug> <tag> Remove tag TIMELINE timeline [<slug>] View timeline timeline-add <slug> <date> <text> Add timeline entry TOOLS extract <links|timeline|all> Extract links/timeline (idempotent) [--source fs|db] fs (default) walks .md files; db iterates engine pages [--dir <brain>] brain dir for fs source [--type T] [--since DATE] filters (db source) [--dry-run] [--json] publish <page.md> [--password] Shareable HTML (strips private data, optional AES-256) check-backlinks <check|fix> [dir] Find/fix missing back-links across brain lint <dir|file> [--fix] Catch LLM artifacts, placeholder dates, bad frontmatter orphans [--json] [--count] Find pages with no inbound wikilinks salience [--days N] [--kind P] v0.29: pages ranked by emotional + activity salience anomalies [--since D] [--sigma N] v0.29: cohort-based statistical anomalies (tag, type) transcripts recent [--days N] v0.29: recent raw .txt transcripts (local-only) dream [--dry-run] [--json] Run the overnight maintenance cycle once (cron-friendly). See also: autopilot --install (continuous daemon). check-resolvable [--json] [--fix] Validate skill tree (reachability/MECE/DRY) report --type <name> --content ... Save timestamped report to brain/reports/ BRAIN (capture / ideate / explore — v0.37/v0.38) capture [content] [--file PATH] Single entrypoint for getting content into the brain [--stdin] [--slug s] [--type t] Inline content / file / stdin; writes to inbox/ by default [--source ID] [--quiet|--json] Multi-source brains: route to a non-default source brainstorm <question> [--json] Bisociation idea generator (hybrid search + far-set + judge) [--save|--no-save] [--limit N] lsd <question> [--json] Lateral Synaptic Drift: inverted-judge brainstorm [--save|--no-save] [--limit N] rewarding far-from-obvious + axiomatic inversions SOURCES (multi-repo / multi-brain) sources list Show registered sources sources add <id> --path <p> Register a source (id = short name, e.g. 'wiki') sources remove <id> Remove a source + its pages sync --all Sync all sources with a local_path sync --source <id> Sync one specific source repos ... DEPRECATED alias for 'sources' (v0.19.0) CODE INDEXING (v0.19.0 / v0.20.0 Cathedral II) code-def <symbol> [--lang l] Find the definition of a symbol across code pages code-refs <symbol> [--lang l] Find all references to a symbol (JSON-first) code-callers <symbol> Who calls this symbol? (v0.20.0 A1) code-callees <symbol> What does this symbol call? (v0.20.0 A1) query <q> --lang <l> Filter hybrid search to one language (v0.20.0) query <q> --symbol-kind <k> Filter to symbol type (function|class|method|...) (v0.20.0) reconcile-links [--dry-run] Batch-recompute doc↔impl edges (v0.20.0) reindex-code [--source id] [--yes] Explicit code-page reindex (v0.20.0) sync --strategy code Sync code files into the brain JOBS (Minions) jobs submit <name> [--params JSON] Submit background job [--follow] [--dry-run] jobs list [--status S] [--limit N] List jobs jobs get <id> Job details + history jobs cancel <id> Cancel job jobs retry <id> Re-queue failed/dead job jobs prune [--older-than 30d] Clean old jobs jobs stats Job health dashboard jobs work [--queue Q] Start worker daemon (Postgres only) ADMIN stats Brain statistics health Brain health dashboard history <slug> Page version history revert <slug> <version-id> Revert to version features [--json] [--auto-fix] Scan usage + recommend unused features autopilot [--repo] [--interval N] Self-maintaining brain daemon config [show|get|set] <key> [val] Brain config storage status [--repo <path>] Storage tier status and health [--json] (git-tracked vs supabase-only) serve MCP server (stdio) serve --http [--port N] HTTP MCP server with OAuth 2.1 --token-ttl N Access token TTL in seconds (default: 3600) --enable-dcr Enable Dynamic Client Registration --public-url URL Public issuer URL (required behind proxy/tunnel) call <tool> '<json>' Raw tool invocation version Version info --tools-json Tool discovery (JSON) Run gbrain <command> --help for command-specific help. + the per-command KEY_FILES entries; content stays in git) CLAUDE.md gains: a Reference map (resolver), a Maintaining section (the anti-disease rule), and a Cross-cutting invariants subsection under Architecture so the must-never-violate rules (trust fail-closed, sourceScopeOpts isolation, JSONB trap, engine parity, contract-first, migrations, multi-source) still auto-load after the index moved out. Result: CLAUDE.md 592KB -> 61KB; llms-full.txt 740KB -> 210KB (new docs link-only until compressed). build-llms drift + budget test green; verify 29/29 green. The pre-move content is recoverable at git show <this^>:CLAUDE.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(docs): compress relocated docs to current-state + add recurrence guard Compresses the verbatim-relocated reference docs from append-only release-history to current-state-only (the disease cure), then makes recurrence structurally impossible via a CI guard. Compression (fan-out subagents + adversarial verify, audited mechanically): - KEY_FILES.md 453KB -> 356KB; TESTING.md 42KB -> 38KB; thin-client.md already clean. - 393/393 entries preserved; every src/test/scripts path from the verbatim original survives (mechanical comm-check); zero bolded **v0. markers remain. - Conservative ratio (~22%) because the content is invariant-dense — correctness over brevity. Dropped: **vX.Y.Z (#NNN):** clauses, codex/review tags, contributor credits, PR-numbers-as-ids, pre-fix/then/was-now history deltas. Kept: every exported symbol, invariant, and Pinned-by reference. Verbatim original recoverable at git show <relocation-commit>:docs/architecture/KEY_FILES.md. Recurrence guard (scripts/check-key-files-current-state.sh, wired into verify + check:all): - HARD: bans the bolded **v0.<digit> marker in the reference docs (scoped — plain 'as of pgvector 0.7' prose is fine, no false positives). - HARD: CLAUDE.md size cap (90KB; currently 61KB) — the structural backstop. - Pinned by test/scripts/check-key-files-current-state.test.ts (7 cases). Content contracts (test/build-llms.test.ts, +5 cases per codex outside-voice): CLAUDE.md keeps inline ship IRON RULES (version format, document-release, never-hand-roll); AGENTS.md keeps its boot order; llms indexes the new docs; KEY_FILES stays link-only (not inlined). Privacy: scrubbed the relocated 'wintermute/chat/' source-boost examples + the literal harvest-lint regex to generic placeholders (legitimate in allowlisted CLAUDE.md; genericized for the new public docs per the privacy rule). Reverts the |
||
|
|
6ae94301a6 |
v0.41.26.1 fix: lock-renewal cathedral — closes ~39 worker crashes/day (supersedes #1567) (#1572)
* v0.41.26.1 fix: lock-renewal cathedral — closes ~39 worker crashes/day (supersedes #1567)
Production worker daemons against Supabase / PgBouncer were crashing
~39 times/day with `unhandledRejection at renewLock`. PR #1567
proposed the right try/catch shape; this wave incorporates it and
closes the entire bug class (4 inside-review + 8 outside-voice
findings absorbed via 9 locked design decisions).
What's fixed:
- `setInterval(async () => await renewLock(...))` replaced with a
sync wrapper around the new pure `runLockRenewalTick` function.
No more unhandled rejections escaping the timer callback.
- Second crash vector closed: `.catch()` on the stored
`executeJob(...).finally(...)` promise so failJob/completeJob
throws during the same outage can't propagate to
`process.on('unhandledRejection')`.
- Per-call `Promise.race` timeout (default `lockDuration/3`) bounds
hung renewLock calls so the re-entrancy guard can't wedge
indefinitely.
- Time-based abort (NOT count-based) so the worker releases its
lock BEFORE another worker can reclaim. With the prior 3-strike
count + 30s lockDuration, a 15s window let other workers race.
- Infrastructure aborts (`lock-renewal-failed`, `lock-lost`) don't
burn job attempts — `executeJob`'s catch consults the exported
`INFRASTRUCTURE_ABORT_REASONS` set and skips `failJob` so the
stall detector reclaims cleanly.
- Universal grace-eviction: 30s force-evict safety net now fires
for ANY abort reason, not just `job.timeout_ms`.
What's added:
- `src/core/minions/lock-renewal-tick.ts` (NEW): pure extracted
state-machine function + env-knob resolver. Three operator-tunable
knobs via env (max-failures-for-audit, call-timeout-ms,
safety-margin-ms) with stderr-warn-once on bad input + default
fallback.
- `src/core/audit/lock-renewal-audit.ts` (NEW): sibling of
`batch-retry-audit.ts`. Four outcomes: failure /
success_after_failure / gave_up / executeJob_rejected. JSONL at
`~/.gbrain/audit/lock-renewal-YYYY-Www.jsonl`.
- `src/core/audit/redact-connection-info.ts` (NEW): shared privacy
helper. Strips Postgres URLs, host=, user=, password=, IPv4 from
error messages before they hit audit JSONL. Wired into BOTH the
new lock-renewal audit AND the existing batch-retry audit
(privacy backfill — same risk class).
- `scripts/check-worker-lock-renewal-shape.sh` (NEW): CI guard
wired into `bun run verify`. Asserts the v0.41.22.1 bug pattern
(`lockTimer = setInterval(async ...)`) stays absent AND the pure
function call site survives refactors. Bug-pattern-specific so it
doesn't fight legitimate refactors (codex C12).
Tests: 64 new cases across 5 new test files. 182 existing minion +
worker tests still pass. All hermetic — no PGLite, no real network,
no `mock.module`.
Plan + 9 decisions + codex outside-voice review at
~/.claude/plans/system-instruction-you-are-working-humming-nygaard.md
Closes #1567 (incorporates the contributor's try/catch shape; closes
the bug class structurally).
Co-Authored-By: @garrytan-agents <noreply@github.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* test: fill A-H gaps for v0.41.26.1 lock-renewal cathedral
The original v0.41.26.1 wave shipped 64 hermetic unit tests on the
pure tick function, audit primitives, and redactor. Post-ship audit
flagged 8 wiring gaps the pure tests can't see — A (launchJob
wiring), B (executeJob skip-failJob), C (.catch on stored promise),
D (INFRASTRUCTURE_ABORT_REASONS export), E (universal grace-evict),
F (executeJob_rejected end-to-end), G (re-entrancy guard at worker
layer), H (gold-standard E2E regression).
Now closed:
- **test/worker-lock-renewal-e2e.serial.test.ts** (1 test, gap H):
the headline gold-standard regression. Real PGLite + real
MinionWorker + executeRaw wrap that injects renewLock failures on
demand. Pins that the worker process DOES NOT crash via
unhandledRejection under sustained renewLock throws, the handler
observes abort.signal.aborted = true with reason
'lock-renewal-failed', and the audit JSONL contains both `failure`
and `gave_up` events. The exact v0.41.22.1 production bug class.
Quarantined to its own file because bun:test serial + PGLite has an
unresolved interaction with multiple MinionWorker-driven tests in
the same file (second test's queue.add hangs indefinitely).
- **test/worker-lock-renewal-shape.test.ts** (18 tests, gaps A-G):
source-shape behavioral pins. Greps worker.ts function bodies for
the patterns the locked decisions promised: launchJob calls
runLockRenewalTick + resolveLockRenewalKnobs + uses
lockRenewalAudit; tickInFlight declared and gated correctly; stored
executeJob promise has .catch with logExecuteJobRejected + console
stderr; abort.signal.addEventListener fires for any abort (not just
timeout_ms); INFRASTRUCTURE_ABORT_REASONS used inside executeJob's
catch with return-early shape. Bug-pattern-specific so a refactor
that genuinely improves the shape passes; a refactor that
accidentally strips a guarantee fails loud.
All 83 lock-renewal wave tests pass in 5.2s. 205 existing minion +
worker tests still green. No production code changes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix: typecheck errors in worker-lock-renewal-e2e.serial.test.ts
CI verify failed on the new E2E gap-fill test (commit
|
||
|
|
8ab733471b |
v0.41.17.0 feat: --workers N on every bulk command + facts dim doctor parity (#1519)
* feat(worker-pool): shared sliding pool + bounded semaphore + PGLite-clamp wrapper T1 + T2 of the v0.41.16.0 workers cathedral. New src/core/worker-pool.ts is the canonical primitive every --workers N bulk command in this wave (and future bulk commands) builds on. Atomic-claim invariant enforced by scripts/check-worker-pool-atomicity.sh (wired into bun run verify). BudgetExhausted bypass + AbortSignal composition baked into the helper so budget caps are a structural ceiling under concurrency, not a per-caller convention. The new resolveWorkersWithClamp wrapper composes existing autoConcurrency with PGLite-clamp + per-(command, requested) stderr dedup. Deliberately NOT a modification to shared autoConcurrency (silent today, used by sync + import); embed.ts keeps GBRAIN_EMBED_CONCURRENCY || 20 default per codex #13. 23 + 12 + 9 = 44 hermetic tests pin every contract. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: structural + dim-check regression suites for v0.41.16.0 wave - test/embed-helper-migration.test.ts (T3): asserts embed.ts's two sliding-pool sites are migrated to runSlidingPool, pre-migration shapes (let nextIdx = 0, Promise.all(Array.from(...))) are gone, GBRAIN_EMBED_CONCURRENCY || 20 default preserved, failureLabel threads page.slug. Per codex #16/#17 these are invariant assertions, not byte-equality on progress event ORDERING. - test/embedding-dim-check-facts.test.ts (T6): readFactsEmbeddingDim covers vector(N) + halfvec(N), halfvec-before-vector regex ordering pinned (codex #19), buildFactsAlterRecipe emits DROP INDEX + ALTER USING + CREATE INDEX (codex #18, not bare REINDEX), FactsEmbeddingDimMismatchError tagged class shape, assertFactsEmbeddingDimMatchesConfig PGLite skip + Postgres absent- column skip, doctor check + insert-cast wiring assertions. - test/extract-conversation-facts-workers.test.ts (T5): helper exports (extractConversationFactsLockId, PER_PAGE_LOCK_TTL_MINUTES), structural wiring (runSlidingPool, resolveWorkersWithClamp, withRefreshingLock, LockUnavailableError, delete-orphans-first before segment loop, preflight before pool, exit 3 when lock_skipped > 0), Minion handler round-trip. - test/extract-workers.test.ts (T7): --workers wiring on all 3 inner fs-walk loops (extractForSlugs, extractLinksFromDir, extractTimelineFromDir) + CLI parse + opts threading through runExtractCore. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: rebump v0.41.16.0 → v0.41.17.0 (queue collision with PR #1510) PR #1510 (garrytan/dynamic-regex-conversation-formats) claimed v0.41.16.0 on master in parallel. Advancing this wave to v0.41.17.0 so both can land cleanly. Pure mechanical version bump: - VERSION + package.json → 0.41.17.0 - CHANGELOG.md header + "To take advantage of v0.41.17.0" block - TODOS.md section header + v0.41.18+ forward references - CLAUDE.md inline version tags - Regenerated llms-full.txt / llms.txt No code changes. The actual workers cathedral feature set is unchanged from the two prior commits in this branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): search-image-column probes column dim at runtime CI shard 5 failed on `searchVector column routing (v0.27.1)` with: error: expected 1280 dimensions, not 1536 The test had a hardcoded `fakeText1536` helper that seeded chunks at 1536-d vectors. Master's default embedding model switched from OpenAI text-embedding-3-large (1536) to ZeroEntropy zembed-1 (1280) so a fresh PGLite brain on CI now sizes content_chunks.embedding at 1280; the test's 1536-d INSERT trips pgvector's CheckExpectedDim. Fix: probe `content_chunks.embedding` width via `readContentChunksEmbeddingDim(engine)` in `beforeAll`, store in `TEXT_DIM`, and build `fakeTextDefault(seed)` at that width. The test now passes regardless of which default ships (the model has flipped twice and may flip again). Local dev (1536 from older config) and CI fresh-install (1280 from new default) both pass. Image-side vectors stay at 1024 (matches Voyage multimodal-3 + the column's fixed width on the image side). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): bump PGLite hook timeout for shard-4 deep-process files facts-anti-loop.test.ts and ingest-capture.test.ts were timing out in CI shard 4 with "beforeEach/afterEach hook timed out" after the v0.41.16.0 master merge brought migration count to 99. When these files run deep in a shard process that has already created ~20 PGLite engines, the WASM cold-start + 95-migration replay legitimately exceeds bun's 5s default hook timeout (observed 5.6s and 7.3s locally when reproducing). Bun's --timeout=60000 from scripts/test-shard.sh covers TEST timeouts but NOT hook timeouts; those default to 5s and must be set per-hook via the optional 2nd arg to beforeAll/afterAll. Reproduced locally by running the first 21 shard-4 files via head -21 /tmp/shard4-list.txt | xargs bun test → 179 pass, 2 fail (both with hook-timeout error) After fix: → 198 pass, 0 fail (the 4 anti-loop + 15 ingest-capture tests recover) Full shard 4 with fix: 955 pass, 0 fail. Full shard 5 with fix: 1261 pass, 0 fail. Also added a defensive diagnostic to the two put_page tests: if facts_backstop is missing in the response payload, throw with the full payload + isError so future failures surface the actual handler error instead of a bare "expected {...} got undefined" assertion. No-op when the test passes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
3a2605e9a0 |
v0.41.6.0 feat(ci): CI test speedup — 23min → ~9min via matrix 4→6 + weight-aware sharding + auto SHA cache + parallel verify (#1444)
* feat(ci): scripts/run-verify-parallel.sh — parallel verify dispatcher Fans out the 21 pre-test grep guards via & + wait, captures per-check exit codes in a tempdir, aggregates failures with named check + log tail to stderr on miss. Wallclock 27s sequential → 13s parallel locally (2x). Bigger CI win is shard 1 deload (workflow restructure in a later commit). Pinned by test/scripts/run-verify-parallel.test.ts (6 cases: CLI contract + synthetic dispatcher failure-surfacing). * feat(ci): weight-aware LPT bin-packer + auto SHA cache hash scripts/sharding.ts (NEW) — pure TypeScript LPT bin-packer. Sort weights desc, assign each file to the shard with current minimum total. Worst-case makespan within 4/3 of optimal, O(n log n). Missing weights fall back to corpus median (not 0). New test file → ships immediately without regenerating weights. Pinned by test/scripts/sharding.test.ts (23 cases). scripts/mine-shard-weights.ts (NEW) — scrapes per-file timing from gh run view --log via timestamp delta between ##[group]test/foo.test.ts: headers within a shard. Three input modes: --run <ID>, --from-file <PATH>, stdin. Stable JSON output (sorted keys). Initial weights mined from run 26398061007. Pinned by test/scripts/mine-shard-weights.test.ts (15 cases). scripts/ci-cache-hash.sh (NEW) — deterministic 16-char sha256 over git ls-files -s minus deny-list (CHANGELOG/TODOS/README/LICENSE/ docs/**/*.md). CLAUDE.md, AGENTS.md, skills/**/* deliberately INCLUDED (8+ test files read them; deny-listing would create false-pass holes). ~40ms on 1891 files. Pinned by test/scripts/ci-cache-hash.test.ts (24 cases: 8 CRITICAL false-pass guards + 7 SAFE deny-list invariants + 9 edge cases). scripts/test-weights.json (NEW) — 712 weights. Total 3306s observed runtime; median 30ms; max 6 min outlier. * chore: bump version and changelog (v0.41.6.0) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
ee6b11e563 |
v0.40.9.0 feat(chunker): .sql indexing via tree-sitter + code-def on SQL DDL (#1173) (#1350)
* feat(chunker): vendor tree-sitter-sql.wasm + Step 0 grammar inspection tool Vendored from DerekStride/tree-sitter-sql @ c2e1e08db1ea20dc23bdb8d228a81a8756e9c450, built with tree-sitter-cli@v0.26.3 + --abi 14 (matches web-tree-sitter 0.22.6's ABI 13-14 range; default --abi 15 was incompatible). 11 MB binary — substantially larger than the plan's 400KB-1.4MB estimate (DerekStride's multi-dialect grammar generates 40MB of parser.c). tools/inspect-sql-grammar.ts is a one-shot Step 0 script that parsed 9 representative SQL fixtures and surfaced three load-bearing facts: 1. Top-level node type is `program > statement > <kind>`. Every top-level node is `statement`, with the actual statement type as its single named child. TOP_LEVEL_TYPES['sql'] = new Set(['statement']) catch-all. 2. The generic extractSymbolName returns null for EVERY SQL node — needs a SQL-specific branch that dives into statement.namedChild(0). 3. DML emits one statement-chunk per statement (NOT one fat recursive- fallback chunk). $$ body parses cleanly. Even invalid SQL ("SELECT FROM WHERE") still produces a select-shaped statement, not a parse error. Wave plan: ~/.claude/plans/system-instruction-you-are-working-tender-haven.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(chunker): wire SQL into language manifest + sync walker Five additive edits to src/core/chunkers/code.ts: 1. Import G_SQL grammar (DerekStride SHA in inline comment). 2. Extend SupportedCodeLanguage union with 'sql'. 3. Register sql entry in LANGUAGE_MANIFEST. 4. Add .sql case to detectCodeLanguage. 5. TOP_LEVEL_TYPES['sql'] = Set(['statement']) catch-all per Step 0 finding that DerekStride wraps every top-level node in `statement`. Two SQL-aware additions to existing helpers: - extractSymbolName: dives into `statement.namedChild(0)` and routes to extractSqlSymbolName. DDL kinds (create_table/function/view/index/ procedure/type/schema/database/trigger + alter_table/view) extract target identifier via `name` field with fallback to identifier-shaped children. DML kinds (select/insert/update/delete/merge/with) return null so chunks emit unnamed. - normalizeSymbolType: adds 'table', 'view', 'index', 'procedure', 'type', 'schema', 'database', 'trigger' branches so chunk headers say "table users" instead of "statement users". - emit-path passes inner-child type to normalizeSymbolType when the outer node is `statement` (SQL only condition). sync.ts: add '.sql' to CODE_EXTENSIONS so isCodeFilePath routes it to importCodeFile with page_kind='code'. Manual verification (bun /tmp/test-sql-chunker2.ts) confirms CREATE TABLE, CREATE FUNCTION (with $$ body), CREATE INDEX all produce chunks with correct symbolName + symbolType. Small-sibling merging collapses short-statement runs into single merged chunks (existing behavior, not SQL-specific). Wave plan: ~/.claude/plans/system-instruction-you-are-working-tender-haven.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(sql): unit + e2e + extend findCodeDef DEF_TYPES to cover SQL DDL Unit tests (test/chunkers/code.test.ts, 8 new cases): - detectCodeLanguage now covers all 30 extensions (.sql added) - is-case-insensitive extended to .SQL - CREATE TABLE / FUNCTION / INDEX / VIEW / ALTER TABLE each extract target name into symbolName + map to correct symbolType - CREATE FUNCTION with $$ body parses without crashing - DML statements (INSERT) emit chunks but with symbolName=null - Mixed DDL+DML: per-statement emission, only DDL gets symbolName - Header includes "[SQL]" language tag - Invalid SQL ("SELECT FROM WHERE") doesn't crash the parser Sync classifier (test/sync-classifier-widening.test.ts, 1 new case): - isCodeFilePath('migrations/001_init.sql') true, case-insensitive E2E (test/e2e/code-indexing.test.ts, 7 new cases): - SQL import produces pages.type='code' + page_kind='code' - CREATE TABLE / FUNCTION chunks have correct symbol_name + symbol_type - findCodeDef returns CREATE TABLE / FUNCTION / INDEX / VIEW sites by name (load-bearing D2 canary — proves SQL is code intelligence, not just searchable text) - beforeAll timeout bumped to 30s (92-migration replay + 11MB SQL grammar load pushes past default 5s) Source change to make E2E pass (src/commands/code-def.ts): - DEF_TYPES extended with 'table', 'view', 'index', 'procedure', 'schema', 'database', 'trigger'. The chunker's normalizeSymbolType already maps create_table → 'table' etc; without this allowlist extension the chunks were indexed correctly but invisible to `gbrain code-def <name>`. This was the codex F2 missing-piece surfaced in /plan-eng-review (D6). Wave plan: ~/.claude/plans/system-instruction-you-are-working-tender-haven.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * v0.40.9.0 feat(chunker): .sql indexing via tree-sitter, code-def works on SQL DDL (#1173) Closes #1173. gbrain sync now indexes .sql files; gbrain code-def returns CREATE TABLE / FUNCTION / VIEW / INDEX / PROCEDURE / TYPE / SCHEMA / DATABASE / TRIGGER + ALTER TABLE/VIEW sites by name. Bumps: VERSION + package.json 0.40.8.0 → 0.40.9.0. Updates: CLAUDE.md (37 grammars, SQL branch documented), llms-full.txt regenerated. Full release notes in CHANGELOG.md including the 11 MB binary-size disclosure and the 6 decisions (D1-D6) captured during /plan-eng-review. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(sql): fill remaining coverage gaps — TRIGGER/TYPE/PROCEDURE/SCHEMA + code-refs + idempotency + DML-only file Unit tests (test/chunkers/code.test.ts, 7 new cases): - CREATE TRIGGER extracts name + symbolType=trigger - CREATE TYPE (enum) extracts name + symbolType=type - CREATE PROCEDURE extracts name + symbolType=procedure - CREATE SCHEMA (best-effort — grammar version dependent) - Header symbolType reflects inner DDL kind, never the bare 'statement' wrapper - Empty SQL input → empty chunk array - Whitespace-only SQL → empty chunk array E2E tests (test/e2e/code-indexing.test.ts, 6 new cases): - findCodeRefs returns SQL chunks by substring match (validates the ILIKE-based ref path works on SQL with DDL + DML coverage) - CREATE TRIGGER + CREATE TYPE chunks land in content_chunks with correct symbol_type after import (engine-level regression) - findCodeDef on CREATE TYPE returns the chunk (DEF_TYPES allowlist regression pin: 'type' was added to DEF_TYPES in the prior commit) - findCodeDef on CREATE TRIGGER returns the chunk (DEF_TYPES regression pin: 'trigger' is in the allowlist) - DML-only file still produces a code page (just with zero symbol-named chunks — closes the question codex F14 raised) - Re-importing same SQL file is idempotent (content_hash short-circuit behaves the same on SQL as it does on TS/Python/Go) All 63 SQL-related tests pass (chunker + sync classifier + E2E). The pre-existing master flakes (check-system-of-record.sh, longmemeval under shard concurrency) pass in isolation — not regressions from this branch. Wave plan: ~/.claude/plans/system-instruction-you-are-working-tender-haven.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): root-cause 4 master flakes — GBRAIN_SCAN_ROOT env + .slow rename + budget bumps Four flakes surfaced during the v0.40.9.0 full unit sweep. All pass in isolation; all fail under 8-shard parallel CPU contention. Fixes below hit the actual root cause, not symptoms — no quarantine-and-ignore. ────────────────────────────────────────────────────────────────────── 1. check-system-of-record.sh — "catches violations in scripts/ alongside src/" ────────────────────────────────────────────────────────────────────── Root cause: under shard load, the test's `spawnSync('git', ['init', '-q'])` in /tmp/gate-test-* occasionally silently fails (filesystem contention), so the fakeRepo has no .git dir. The gate then runs `git rev-parse --show-toplevel` which walks UP past the fakeRepo into our real gbrain repo, sets ROOT=/real/gbrain/repo, scans the clean real src/+scripts/, exits 0. The test "expects exit 1 + 'naughty.ts' in stdout" sees exit 0 and empty stdout — fails. Fix: - scripts/check-system-of-record.sh: honor `GBRAIN_SCAN_ROOT` env var BEFORE the git-rev-parse fallback. Pure additive — production callers unchanged, tests get deterministic resolution. - test/check-system-of-record.test.ts: `runGate` sets `GBRAIN_SCAN_ROOT: cwd` in spawnSync env. Closes the flake at the cause, not at the symptom (a retry loop would have papered over the real bug — the gate's resolution was too clever for its own good). ────────────────────────────────────────────────────────────────────── 2-4. eval-longmemeval.test.ts — 3 timeouts under 8-shard parallel ────────────────────────────────────────────────────────────────────── Root cause: the file takes ~50s in isolation (full LongMemEval harness replay with stubbed LLM). Under 8-shard parallel, CPU contention pushes individual tests past bun's default 60s timeout. 3 tests timed out: - JSONL format guard (60s timeout) - JSONL key contract (65s timeout) - --by-type emits final by_type_summary (60s timeout) Fix: rename `test/eval-longmemeval.test.ts` → `.slow.test.ts`. This is exactly what the .slow taxonomy exists for per CLAUDE.md: > "*.slow.test.ts → intentional cold-path tests; would dominate the > fast loop's wallclock" Verified routing: - Local `bun run test`: skips longmemeval (no flake) - Local `bun run test:slow`: runs explicitly, 31 pass in 277s - CI `scripts/test-shard.sh`: still runs (.slow NOT excluded from FNV bucketing — verified by dry-run: lands in shard 3/4) ────────────────────────────────────────────────────────────────────── Adjacent fix: slow wrapper + test-shard.slow.test.ts beforeAll budget ────────────────────────────────────────────────────────────────────── The longmemeval move surfaced a 4th flake: `test-shard.slow.test.ts`'s beforeAll shells out 4×`scripts/test-shard.sh --dry-run-list` (~4s solo each); when longmemeval is now running in the same slow-wrapper invocation hogging CPU, the 4 sequential dry-runs slip past the 60s beforeAll timeout. Fixes: - scripts/run-slow-tests.sh: bump bun test --timeout 60s → 120s. Slow tests are explicit by-name; a generous per-test budget is correct posture, not a workaround. - test/scripts/test-shard.slow.test.ts: bump beforeAll budget 60s → 180s. Matches the actual workload under parallel slow-shard execution. ────────────────────────────────────────────────────────────────────── Verification ────────────────────────────────────────────────────────────────────── - `bun test test/check-system-of-record.test.ts` — 6 pass (in isolation) - `bun run test:slow` — 31 pass in 277s (was: 1 fail at 89s before fixes) - Full `bun run test` re-run in progress; will confirm 0 fail. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): two more flake-hardening rounds — shard-aware perf gate + shard cap 600→900 Round 1 caught 4 named flakes; the post-fix sweep surfaced 2 more from the same flake class (calibration values that were correct when set but are no longer correct for the larger test suite). 5. longmemeval-trajectory-routing — "perf gate preserved" (3rd-party flake) Failure: under shard load, test asserts elapsed<10s but real wallclock was 37s. The gate is supposed to catch real harness-layer regressions, not raw cycle counts; 8-shard CPU contention routinely 3-5x's wallclock. Fix: mode-aware ceiling. Solo run keeps the tight 10s gate (catches real algorithmic regressions). Shard run (detected via `$SHARD` env set by the parallel wrapper) loosens to 60s — still catches >6x regressions but tolerates parallel contention. Per-test timeout bumped 5s default → 90s. 6. Per-shard wedge-detection too tight (false WEDGED markers) Shards 5+6 of the prior sweep both got WEDGED markers at the 600s wrapper cap, but their bun-internal timer shows they actually finished in 620-770s with 0 failures. The 600s shard cap was calibrated when shards held ~600 tests; suite growth through v0.40.x pushed individual shards to 1100+ tests and 620-770s legitimate wallclock. Fix: bump GBRAIN_TEST_SHARD_TIMEOUT default 600→900. Real hangs still hit the 900s cap; fully-completed shards no longer false-kill at 600s. Env override preserved. ────────────────────────────────────────────────────────────────────── Cumulative flake hardening (across 2 commits) ────────────────────────────────────────────────────────────────────── 1. check-system-of-record gate — GBRAIN_SCAN_ROOT env override 2. eval-longmemeval (3 tests) — rename to .slow 3. run-slow-tests.sh — bump --timeout 60s → 120s 4. test-shard.slow.test.ts — bump beforeAll 60s → 180s 5. longmemeval perf gate — shard-mode-aware ceiling 10s/60s 6. Per-shard wedge cap — bump 600s → 900s All root-cause fixes; zero retry-loop / quarantine-and-ignore. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): clamp local default shard count 8 → 4 — kills PGLite contention SIGKILLs Sweep #3 (after the prior 6 hardening fixes + master merge) caught a new flake class: shard 5 got SIGKILL'd (rc=137) during source-health.test.ts's 92-migration PGLite replay. 8 parallel shards each running their own PGLite WASM init + 92-migration replay contend severely on shared FS state — even with the 900s shard cap, shard 5 wedged so hard the wrapper fell back to SIGKILL. Root cause: 8-shard parallel was aggressive (we picked detect_cpus on a 12-perf-core M-series, clamped to 8). CI runs 4 via test-shard.sh and is stable. 8 → 4 trades ~2x local wallclock for reliability + matches CI fan-out exactly. Override still available via --shards N or SHARDS=N (clamped at 8 ceiling). Side benefit: also resolves the 2 .serial.test.ts spawn failures in sweep #3 — those serial tests run AFTER the parallel pass, so when the parallel pass leaks PGLite write-locks under heavy contention, the serial spawn tests inherit the polluted state and timeout on their own subprocess spawns. Reducing parallel contention upstream cleans up the FS state by the time serial runs. ────────────────────────────────────────────────────────────────────── Cumulative flake hardening (3 commits, 7 fixes) ────────────────────────────────────────────────────────────────────── 1. check-system-of-record gate — GBRAIN_SCAN_ROOT env override 2. eval-longmemeval (3 tests) — rename to .slow 3. run-slow-tests.sh — bump --timeout 60s → 120s 4. test-shard.slow.test.ts — bump beforeAll 60s → 180s 5. longmemeval perf gate — shard-mode-aware ceiling 10s/60s 6. Per-shard wedge cap — bump 600s → 900s 7. Default local shards — clamp 8 → 4 (matches CI) All root-cause fixes; zero quarantine-and-ignore. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): bump shard timeout 900→1500 — fixes 4-shard 968s overshoot Sweep #4 at the new 4-shard default ran cleanly: 0 failures, 10072 pass. BUT shard 1 was false-killed at 900s even though its internal completion was 968s (the same flake pattern as the prior 600→900 bump, just at the new shard sizing). Reason: 8→4 shard reduction means each shard now runs 2x more files (159 vs 80) and 2x more tests (~2420 vs ~1100). Internal wallclock per shard climbed from 620-770s (8-shard) to 960-1020s (4-shard). The 900s cap was sized for the prior 8-shard sizing; 4-shard sizing needs more headroom. 1500s gives ~55% headroom over observed 4-shard wallclock and catches real hangs that wouldn't complete in 1500s anyway. ────────────────────────────────────────────────────────────────────── Cumulative flake hardening (4 commits, 8 fixes) ────────────────────────────────────────────────────────────────────── 1. check-system-of-record gate — GBRAIN_SCAN_ROOT env override 2. eval-longmemeval (3 tests) — rename to .slow 3. run-slow-tests.sh — bump --timeout 60s → 120s 4. test-shard.slow.test.ts — bump beforeAll 60s → 180s 5. longmemeval perf gate — shard-mode-aware ceiling 10s/60s 6. Per-shard wedge cap — 600s → 900s → 1500s (8→4-shard recalibration) 7. Default local shards — clamp 8 → 4 (matches CI) 8. (this commit) — calibrate cap for new shard sizing Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(test): CI flake — warm-create perf gate ceiling now mode-aware (1500ms solo / 4000ms loaded) CI test_3 (Ubuntu, run #77585655194) failed on the test/eval-longmemeval.slow.test.ts > 'warm-create speed gate' p50 assertion. GHA Ubuntu runners are meaningfully slower than my Apple Silicon dev box under parallel shard load — the 10-trial loop took 17364ms total which puts per-trial p50 well above the 1500ms ceiling. This is the same flake class as D5 in the local sweep hardening (longmemeval-trajectory-routing perf gate). Apply the same shard-aware ceiling pattern: 1500ms solo (catches real harness regressions), 4000ms when `$SHARD` (local parallel) OR `$CI` (GHA et al) is set. Verified solo on Apple Silicon: p50=44ms (well under 1500ms tight gate). Verified with `CI=true` env: p50=44ms (well under 4000ms loaded gate). 4000ms still catches >50x algorithmic regressions on a 25-44ms baseline. ────────────────────────────────────────────────────────────────────── Cumulative flake hardening (5 commits, 9 fixes) ────────────────────────────────────────────────────────────────────── 1-8. (prior 4 commits) — see PR comment #4527950030 9. (this commit) warm-create gate — shard/CI-mode-aware ceiling Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
dd1cc121d8 |
v0.35.3.1 feat(eval): temporal-aware contradiction probe + verdict enum (#1052)
* rfc: temporal axis for contradiction probe Field report on residual HIGH findings from gbrain eval suspected-contradictions and proposal for a 4-phase fix (Phase 1 = judge prompt + verdict enum is the recommended starting point). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(eval): pass effective_date to judge prompt; bump PROMPT_VERSION Lane A1 of the temporal-contradiction-probe wave. Threads page-level effective_date through the search projection into the contradiction judge so the LLM can reason about supersession instead of treating every dated pair as a contradiction. Changes: - SearchResult interface adds optional effective_date + effective_date_source fields; rowToSearchResult populates them from the row data with date-only YYYY-MM-DD normalization (handles both postgres.js Date and PGLite string). - 8 SELECT projection sites (3 in postgres-engine, 5 in pglite-engine) now carry p.effective_date + p.effective_date_source through their inner CTEs and outer SELECTs so search results expose the field on both engines. - PairMember (eval-contradictions/types.ts) gets the two fields as required (string | null) so the type forces every constructor to think about temporal anchoring. Runner's searchResultToMember + takeToMember handle the normalization; takes inherit the chunk's page-level date. - buildJudgePrompt emits `Statement A (from: YYYY-MM-DD)` when effective_date is non-null, else `(date unknown)`. Prompt instructions explain the tag so the model knows what to do with it. - PROMPT_VERSION bumps '1' → '2'. Cache-key tuple shape unchanged; old rows miss naturally on first run against the new prompt. Test fixtures in 5 files updated to include the new required fields. All 205 eval-contradictions unit tests + 101 search-related tests pass. Typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(eval): replace contradicts:boolean with verdict:enum (6 members) Lane A2 of the temporal-contradiction-probe wave. Expands the judge's classification vocabulary from a binary contradicts:bool to a six-member verdict enum so the probe can distinguish "this changed" from "this is wrong". Verdict taxonomy: no_contradiction — drop from findings contradiction — genuine conflict at same point in time temporal_supersession — newer claim updates/replaces older; not an error temporal_regression — metric/status went backwards over time (signal) temporal_evolution — legitimate change, neither supersession nor regression negation_artifact — judge misread an explicit negation Changes: - types.ts: Verdict union (6 members); Severity gains 'info'; ResolutionKind extended with temporal_supersede, flag_for_review, log_timeline_change; JudgeVerdict.contradicts → verdict; ContradictionFinding now carries verdict; ProbeReport adds queries_with_any_finding + verdict_breakdown (additive). - judge.ts: parseResolutionKind + parseVerdict guards; normalizeVerdict reads the new field and applies the C1 confidence floor only to verdict='contradiction' (the new verdicts are informational classifications, no floor). Prompt rubric rewritten to ask for verdict + extended severity scale. - severity-classify.ts: 'info' joins the rank with value 0; defaultSeverityForVerdict maps each verdict to its baseline severity (D7 — supersession=info, regression=high, etc.). parseSeverity gains a fallback param so consumers can override 'low' default. - auto-supersession.ts: classifyResolution + renderResolutionCommand handle the three new resolution kinds. Probe still NEVER auto-mutates — the new kinds render paste-ready commands or informational lines. - cache.ts: isJudgeVerdict shape check matches the new verdict field; old v1 rows fail the guard and treat as misses. - runner.ts: emit predicate at cache-hit and judge-success branches changes from `verdict.contradicts` to `verdict.verdict !== 'no_contradiction'`. Without this, the new verdicts vanish from the report. Added per-verdict tally + queriesWithAnyFinding alongside the strict queriesWithContradiction. - trends.ts: latest run verdict breakdown surfaces in the trend chart. Test fixtures updated across 8 test files. All 210 eval-contradictions unit tests pass. Typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(eval): relax date-filter rule 3 when both sides dated Lane B of the temporal-contradiction-probe wave. The v1 date pre-filter skipped pairs whose chunk-text-extracted dates differed by >30 days as a cost-saving heuristic. That heuristic silently killed exactly the cases the new verdict taxonomy exists to surface — role transitions across years (e.g. a 2017 historical record vs. a 2025 current state), MRR claims years apart, status changes recorded over time. Lane A1+A2 made temporal supersession explicit and cheap to classify. The filter no longer needs to skip these pairs; the judge can label them. Changes: - date-filter.ts: shouldSkipForDateMismatch accepts optional effectiveDateA and effectiveDateB. When BOTH are non-null, returns skip=false with the new 'both_have_effective_date' reason — the judge will see the dates via the (from: YYYY-MM-DD) prompt tag from Lane A1. Other rules (same-paragraph dual-date override, missing-date fallback) preserved verbatim and still run first. - runner.ts: threads pair.{a,b}.effective_date into the date-filter call. Pairs that previously vanished into the skip bucket now reach the judge. Tests (R1 IRON RULE regression suite, 6 new cases): - both sides effective_date → not skipped - both sides effective_date overrides >30d chunk-text rule - rule 1 (same-paragraph dual-date) still wins over effective_date relaxation - rule 2 (missing chunk dates) still applies when effective_date partially present - undefined effective_dates fall through to v1 behavior (back-compat) - empty-string effective_date treated as missing (only real dates enable the relaxation) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(cli): cost-estimate prompt + --budget-usd + Haiku routing Lane C of the temporal-contradiction-probe wave. Three layers of cost guardrail, all stacked: (a) cost-estimate prompt at probe-run-time. Before the runner spends any tokens after a PROMPT_VERSION change, eval-suspected-contradictions reads the most recent persisted prompt_version from eval_contradictions_runs and compares. When they differ: - TTY: prints an upper-bound estimate + Ctrl-C window (default 10s, override via GBRAIN_PROBE_PROMPT_GRACE_SECONDS). - non-TTY: prints the estimate + auto-proceeds (autopilot path). - --yes override or GBRAIN_NO_PROBE_PROMPT=1: skip entirely. Mirrors the v0.32.7 runPostUpgradeReembedPrompt pattern. (b) --budget-usd N hard cap (pre-existing; PreFlightBudgetError surfaces when the estimate alone exceeds the cap, and CostTracker halts the run mid-flight when cumulative cost exceeds it). Documented in the help text alongside (a). (c) Judge model now routes through resolveModel() with configKey 'models.eval.contradictions_judge', tier 'utility' (Haiku-class default), and env var GBRAIN_CONTRADICTIONS_JUDGE_MODEL. The legacy --judge CLI flag still wins as the highest-precedence override. Doctor's model touchpoint registry (src/commands/models.ts:50) carries the new key so `gbrain models` and `gbrain models doctor` surface it. Also in this lane: - CLI: --severity accepts 'info' (the new Severity member from Lane A2). - CLI: --severity output shows [verdict] tag alongside slug pairs so operators distinguish genuine contradictions from temporal classifications. - Human summary: prints the new queries_with_any_finding metric and the per-verdict breakdown table. - Help text: explains the cost-prompt + budget-cap + model-routing interactions in one paragraph. New tests (9 cases on the cost-prompt helper): - --yes override skips - GBRAIN_NO_PROBE_PROMPT=1 skips - prompt_version unchanged → skips - non-TTY auto-proceeds with stderr note - TTY proceeds after grace - TTY aborts on Ctrl-C - fresh brain (no prior runs) fires the prompt - GBRAIN_PROBE_PROMPT_GRACE_SECONDS override honored - estimate banner contains query count + judge model + dollar amount All 225 eval-contradictions tests + 25 model-config tests pass. Typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(eval): R4/R5/R6 IRON-RULE regressions for the verdict-enum wave Lane D of the temporal-contradiction-probe wave. The Lanes A1/A2/B/C lanes landed the behavior; this lane pins the regressions that protect the wave against future drift. R4 (runner emit predicate): five new tests, one per non-no_contradiction verdict, prove the runner.ts emit rule surfaces each one as a finding with the correct verdict tag, and that: - queries_with_contradiction (Wilson-CI denominator) ONLY counts verdict ='contradiction' — the strict metric is preserved - queries_with_any_finding counts every non-no_contradiction verdict - verdict_breakdown tallies correctly Plus one negative case: verdict='no_contradiction' produces zero findings. Without R4, a future runner refactor could collapse the new verdicts back to /dev/null and the report would silently shrink. R5 (cache key shape): direct shape assertion on buildCacheKey output. The key tuple is exactly 5 fields (chunk_a_hash, chunk_b_hash, model_id, prompt_version, truncation_policy). Adding a 6th field would silently break every operator's brain (no migration path). R6 (contradiction severity unchanged): four tests on normalizeVerdict pin the legacy semantics — judge-supplied severity wins (whether 'high' or 'low'), and on garbage severity input the fallback is 'medium' (per defaultSeverityForVerdict('contradiction')) NOT 'low'. The contradiction verdict's severity must never default to 'low', which would silently mask genuine conflicts as cosmetic naming issues. The temporal_regression case is included for parity (garbage → 'high' since regressions are real investor red flags). 236 eval-contradictions tests pass (211 + 6 R4 + 1 R5 + 4 R6 + 9 cost-prompt from Lane C). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(ci): privacy lint for docs/proposals/*.md Captures the residual TODO from the temporal-contradiction-probe wave's plan: prevent the bug class where an RFC lands in docs/proposals/ with PII that should never appear in a public technical artifact. The original RFC had to be scrubbed at force-push time (Step 0); this lint catches the same patterns at CI time so the next one can't slip through. Sibling to scripts/check-privacy.sh: - check-privacy.sh: bans the literal "Wintermute" repo-wide. - check-proposal-pii.sh: focuses on docs/proposals/*.md and the OTHER PII classes — personal-relationship vocabulary, private repo refs. Design contract: the denylist names PATTERNS, not real people. Naming specific real names (deceased relatives, therapist first names, dealflow contacts) inside this script would leak PII into the repo just by appearing here. The structural patterns below catch the SURROUNDING vocabulary that always accompanies such content in personal RFC prose. Trade-off: a future RFC that names a real person without any contextual markers won't be caught — accepted as residual risk handled by human review. Patterns flagged in docs/proposals/*.md: - garrytan/brain (private repo reference) - trial separation, permanent separation - couples session, couples therapist - divorce attorney(s) - grandmother's funeral, aunt's funeral - wintermute (also caught by check-privacy.sh; listed here for proposal-scoped clarity) Bare common words (separation, funeral) are NOT banned — only the combined personal-context phrases. "Separation of concerns" and other software vocabulary survives. Wired into: - `bun run verify` (gates every push) - `bun run check:all` - `bun run check:proposal-pii` (standalone) Tests: 15 cases in test/scripts/check-proposal-pii.test.ts. - Each pattern flagged when present, plus exit-code + stderr signal. - Two negative cases (separation-of-concerns, funeral metaphor) prove the lint doesn't false-positive on legitimate software prose. - No-proposals-dir → exit 0 (not a failure). - Multi-hit case proves all patterns surface together with a summary count. - The two test fixtures that name "Wintermute" / "WINTERMUTE" as sentinel literals are allowlisted in check-test-real-names.sh per the same meta-rule-enforcement exception as check-privacy.sh itself. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore(privacy): allowlist new privacy-guard files in check-privacy.sh check-privacy.sh bans the literal Wintermute repo-wide. The two new files from the v0.34 privacy lint (scripts/check-proposal-pii.sh and its test) necessarily name the token to do their job. Same meta-rule-enforcement exception as scripts/check-privacy.sh itself, scripts/check-test-real-names.sh, test/recency-decay.test.ts, and the existing entries — describing what the rule forbids requires naming it. Without this allowlist, `bun run verify` fails on check:privacy. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: bump version and changelog (v0.35.1.0) Temporal-contradiction-probe wave — Phase 1 of the RFC at docs/proposals/temporal-contradiction-probe.md. Headline: the contradiction probe now classifies pairs into a 6-member verdict enum (no_contradiction, contradiction, temporal_supersession, temporal_regression, temporal_evolution, negation_artifact) and sees the page-level effective_date for each chunk via a (from: YYYY-MM-DD) tag in the prompt. The pre-judge date filter no longer skips dated wide-gap pairs, so the role-transition class (e.g. a 2017 historical record vs. a 2025 current state) reaches the judge and gets classified as temporal_supersession instead of vanishing into the skip bucket. PROMPT_VERSION bumped 1 → 2 (cache fully invalidated). Three-layer cost guardrail: TTY-only cost-estimate prompt with Ctrl-C window, --budget-usd hard cap, Haiku-tier routing via new models.eval.contradictions_judge config key. Also adds a CI privacy lint (scripts/check-proposal-pii.sh) wired into bun run verify that catches PII patterns in docs/proposals/*.md so future RFCs can't ship with personal-context vocabulary the way this wave's source RFC did at draft time. Phases 2-4 deferred to follow-up RFCs per the plan. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: garrytan-agents <garrytan-agents@users.noreply.github.com> Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
943e7b9dec |
v0.31.4.1 chore: align VERSION + package.json with #795 + mandate 4-segment versions (#815)
* v0.31.4.1 chore: align VERSION/package.json with #795 + mandate MAJOR.MINOR.PATCH.MICRO
PR #795 (takes v2) landed on master with `v0.31.4` in its commit subject but
never bumped VERSION, package.json, or CHANGELOG.md. Master shipped at 0.31.3.
This corrective release:
- Bumps VERSION + package.json to 0.31.4.1 (the dot-suffix follow-up channel
documented in CLAUDE.md, so the patch number doesn't churn to 0.31.5)
- Adds the v0.31.4.1 CHANGELOG entry covering takes v2 (lessons from a 100K-take
production extraction), the auth-on-Postgres regression fix, and the new
`gbrain eval takes-quality` CLI surface
- Updates CLAUDE.md to mandate `MAJOR.MINOR.PATCH.MICRO` for every new release.
Historical 3-segment versions in git log + migration filenames stay valid;
do not rewrite. Going forward only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: regenerate llms-full.txt for v0.31.4.1 doc edits
The build-llms regen-drift guard caught that llms-full.txt was stale relative
to the CHANGELOG + CLAUDE.md edits in the prior commit. Per CLAUDE.md the
bundle is auto-derived: bump VERSION/CHANGELOG/CLAUDE.md, then run
`bun run build:llms`. Did the second part now.
llms.txt unchanged (it's just the curated index). Only llms-full.txt picks
up the v0.31.4.1 CHANGELOG entry and the new "Version format is mandatory"
section in CLAUDE.md.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(ci): exclude *.serial.test.ts from test-shard.sh hash buckets
Root cause of test (2) failing on the v0.31.4.1 PR (and on master since
#795 landed): CI's scripts/test-shard.sh hashed every test file into 4
shards via FNV-1a, INCLUDING *.serial.test.ts files. Serial files share
file-wide state (top-level mock.module, module singletons) that's
supposed to be quarantined by the .serial.test.ts naming + local
run-serial-tests.sh running them at --max-concurrency=1.
In CI the quarantine didn't apply. eval-takes-quality-runner.serial.test.ts
(new in #795) hashes into shard 2, where it calls:
mock.module('../src/core/ai/gateway.ts', () => ({
chat: async (opts) => { ... },
configureGateway: () => undefined,
}));
That replaces every export of gateway.ts at module-load time for the
WHOLE shard process. voyage-multimodal.test.ts also lives in shard 2
(both files happen to hash there), and it imports `embedMultimodal` from
gateway.ts. After the serial file loads, `embedMultimodal` is undefined
inside the shard process, and all 18 of voyage-multimodal's
embedMultimodal tests fail. Tests still passed locally because
run-unit-shard.sh excludes .serial files from its parallel pass.
Fix:
- scripts/test-shard.sh: add `-not -name '*.serial.test.ts'` to the
find expression so serial files no longer compete for shard buckets.
Add --dry-run-list flag to mirror run-unit-shard.sh's interface so
the regression test can introspect without spawning bun test.
- .github/workflows/test.yml: add a `bun run test:serial` step that
runs on shard 1 (which already runs `bun run verify`). Uses the
existing scripts/run-serial-tests.sh which invokes bun test at
--max-concurrency=1, matching local behavior.
- test/scripts/test-shard.slow.test.ts: 4 regression cases that pin
the contract (no serial files in any shard, no e2e files in any
shard, plain files partitioned without overlap). .slow.test.ts
because it shells out 4× with pure-bash FNV-1a hashing (~14s
wallclock); excluded from the local fast loop, runs in CI via the
same hash bucketing as other slow tests.
- CLAUDE.md: update the CI vs local divergence section so this
intentional asymmetry is documented going forward.
Build-llms drift in test (1) was fixed in the prior commit (
|
||
|
|
058fe69575 |
v0.26.7 test: isolation foundation (helpers + lint + quarantine) (#613)
* test: add withEnv helper + canonical PGLite block JSDoc withEnv(overrides, fn) saves prior values, runs the callback, restores via try/finally — including on throw. Handles delete via undefined override. Nested calls compose. Cross-test safe; explicitly NOT intra-file concurrent-safe (process.env is process-global). 7 unit cases covering sync, async, delete-key, delete-when-prior-unset, restore-on-throw, nested compose, multi-key atomic restore. reset-pglite.ts JSDoc extended with the canonical 4-line PGLite block (beforeAll create + afterAll disconnect + beforeEach reset). The lint script in the next commit enforces this exact shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: add check-test-isolation lint script + wire into verify Grep-based lint enforcing 4 rules on non-serial unit test files: R1: no process.env mutations (use withEnv() or rename to *.serial.test.ts) R2: no mock.module() (rename to *.serial.test.ts) R3: new PGLiteEngine( only inside beforeAll() context R4: PGLiteEngine creators must pair with afterAll{disconnect} Wired into 'bun run verify' and 'bun run check:all' (NOT 'bun run test' which is the parallel runner script with no pre-check chain). Matches the existing scripts/check-*.sh family shape (jsonb, progress, etc). 51 baseline violators captured in scripts/check-test-isolation.allowlist. List MUST shrink over time — entries removed by v0.26.8 (env sweep) and v0.26.9 (PGLite sweep). New files cannot be added. CLAUDE.md ## Testing section extended with R1-R4 rules table, the canonical 4-line PGLite block, withEnv pattern, and when-to-quarantine guidance. 16 fixture-driven test cases for the lint: clean, R1 (5 patterns + 1 negative), R2, R3 (top-level vs in-beforeAll), R4 (missing disconnect), *.serial.test.ts skip, test/e2e/ skip, allowlist (3 cases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: quarantine cycle and embed mock.module test files Both files use mock.module(...) at top level — leaks across files in the same shard process. The check-test-isolation lint (R2) bans this pattern in non-serial files; quarantine is the escape hatch. Per v0.26.7 plan D5: prefer quarantine over DI on runCycle/runEmbed. Production signatures stay frozen; tests run at --max-concurrency=1 in the serial post-pass (the existing pattern shipped in v0.26.4 for brain-registry and reconcile-links). Quarantine count: 2 → 4. Cap raised to 10 informational per D15. Renames: test/core/cycle.test.ts → test/core/cycle.serial.test.ts test/embed.test.ts → test/embed.serial.test.ts Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * chore: bump version and changelog (v0.26.7) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs: post-ship documentation sync for v0.26.7 - README.md "Contributing" line: point to bun run test + bun run verify (parallel fast loop) - CONTRIBUTING.md "Running tests": rewrite for the v0.26.4/v0.26.7 test surface (parallel runner, verify, slow/serial/e2e tiers) - CONTRIBUTING.md adds "Writing tests that survive the parallel loop" section: R1-R4 lint, canonical PGLite block, withEnv pattern, when to quarantine - llms-full.txt regenerated to pick up the README + CONTRIBUTING changes Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
d97f159793 |
v0.26.4 test: parallel unit-test loop (12x speedup, failure-first logging) (#605)
* test: parallel unit-test wrapper + failure-first logging (commit 1/8) Lay foundation for v0.26.4 parallel test loop: - scripts/run-unit-parallel.sh: spawns N shards (default min(8, cpu_count)) via run-unit-shard.sh, captures per-shard logs, post-shard single-writer failure-log aggregation at .context/test-failures.log, 10s heartbeat to stderr, per-shard 600s timeout (gtimeout/timeout/bg-pid fallback chain), loud final banner with absolute path + tail-30 of failures, summary file for at-a-glance status. Single writer eliminates concurrent-write hazards on the failure log. - scripts/run-serial-tests.sh: discovers *.serial.test.ts files (concurrency- unsafe by design), runs them with --max-concurrency=1. Invoked after the parallel pass. - scripts/run-unit-shard.sh: now accepts --max-concurrency=N (forwarded to bun test); --dry-run-list moved into argv parsing alongside; excludes *.serial.test.ts in addition to *.slow.test.ts. - bunfig.toml: trim stale comment about typecheck-chained timeout. - .gitignore: add .context/ (Conductor workspace artifacts directory; the failure log + summary + per-shard logs all live here). No package.json changes yet (commit 2). No test reorganization yet (commits 4-7). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: split package.json scripts; bun run test = parallel fast loop (commit 2/8) Per Codex Tension #4 (verify scope), distinguish three tiers cleanly: - `bun run test` = fast loop, file-level parallel fan-out via the new wrapper (scripts/run-unit-parallel.sh). No pre-checks, no typecheck, no wasm compile in the hot path. ~15s of pre-test gates removed. - `bun run verify` = CI's authoritative gate set: check:jsonb + check:progress + check:wasm + typecheck. Matches what .github/workflows/test.yml runs on shard 1, no scope drift. The 4 checks not in CI (privacy, no-legacy-getconnection, trailing-newline, exports-count) move to `bun run check:all` for opt-in local use. - `bun run test:full` = verify + parallel + slow + smart e2e (runs e2e only if DATABASE_URL is set; else loud skip notice to stderr per Open Item #7). The local equivalent of "everything CI runs." Adds `bun run test:serial` for the *.serial.test.ts subset (concurrency- unsafe files run with --max-concurrency=1). Bumps VERSION + package.json to 0.26.4. Both move together per the CI version-gate contract in CLAUDE.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: fix-wave for parallel wrapper + tighten privacy gate (commit 3/5) Wave: makes the new wrapper actually green and tightens the CI gate it exposed. Wrapper bug fixes (scripts/run-unit-parallel.sh): - grep_count helper: avoids the `grep -c | echo 0` double-output bug where 0 matches yields a 2-line "0\n0" string and breaks arithmetic. - bun_summary_count helper: parses Bun's actual end-of-shard summary format (`N pass` / `N fail` / `N skip`), not the per-test markers (which are `✓` / `(fail)`, never `(pass)` / `(skip)`). - Heartbeat now reads `^\s+✓` (Bun's per-test pass marker) for live progress mid-run; final summary still uses the summary-line counts for accuracy. Privacy gate tightening: - Move scripts/check-privacy.sh into `bun run verify` (was previously only in the now-removed `bun run test` chain). Without this, after commit 2 the privacy check ran in nothing automatic. - .github/workflows/test.yml now calls `bun run verify` instead of inlining the gate list. Single source of truth for "what's the ship gate." This is what verify == CI was supposed to mean per Codex T#4. - Pre-existing `Wintermute` references in src/core/mounts-cache.ts:6 and :324 caught by the now-running gate; replaced with `your OpenClaw` per CLAUDE.md privacy rule (verify gate now passes on master HEAD). - test/privacy-script-wired.test.ts updated: regression guard now asserts verify includes check:privacy AND that test.yml runs `bun run verify`, replacing the obsolete "test script includes check-privacy.sh" assertion. Quarantine 2 cross-file-contention flakes: - test/brain-registry.test.ts: 28 tests pass alone (41ms); 1 test ("empty/null/undefined id routes to host") fails when run alongside other files in the same shard. Renamed → *.serial.test.ts so it runs in scripts/run-serial-tests.sh's serial pass after the parallel pass completes. - test/reconcile-links.test.ts: 6 tests pass alone (1s); a beforeEach hook times out (~896s) under cross-file contention. Same treatment. Both flakes are bun-process-level shared-state leaks (PGLite singletons or top-level imports). Fixing them properly is the v0.27.0+ intra-file parallelism project (TODO P0 — see commit 5). Measurement after this commit: bun run test = 94s (was 18 min sequential) 3639 pass, 0 fail, 0 skip across 8 parallel shards + 34 serial tests Failure-log + heartbeat + summary all working Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: regression tests for parallel wrapper + serial-test contracts (commit 4/5) Three regression suites pin the v0.26.4 contracts. Without these, future refactors of the wrapper or shard scripts could silently regress the work in commits 1-3. test/scripts/run-unit-shard.test.ts (4 cases — gap b): - Asserts the unit-shard `--dry-run-list` output excludes every *.slow.test.ts and *.serial.test.ts file, plus the test/e2e/ subtree. - Catches a future `find` expression that drops one of the `-not -name` clauses and silently un-quarantines slow/serial files into the parallel pass. test/scripts/serial-files.test.ts (3 cases — gap e): - Every checked-in *.serial.test.ts (via `git ls-files`) is listed by scripts/run-serial-tests.sh's `--dry-run-list`. - The script's source contains `bun test --max-concurrency=1` (the serial-pass guarantee that quarantined files don't run intra-file concurrent and reintroduce the contention they were quarantined for). - Disjoint set: a file is never in both the unit-shard list AND the serial list — pins the carve-out contract. test/scripts/run-unit-parallel.test.ts (6 cases — gaps a + d): - Exit-code propagation (a): wrapper exits non-zero when ANY shard has a failing test; exits zero when all pass. The hardest contract to silently break in a fan-out wrapper (`for ... &; wait` returns the LAST child's status, not any failure's). - Failure-log contract (d): on failure, .context/test-failures.log exists, is non-empty, contains the `--- shard N:` prefix and the failing test's describe text. Stderr banner contains the absolute log path. On success, the log is cleared (no stale content). - Summary file format: `shard N/M: pass=X fail=Y skip=Z rc=W` per shard, machine-parseable for future tooling. The wrapper test runs against a 4-file tempdir (3 pass + 1 fail) so it executes in ~500ms; spawning the wrapper against the real test suite would take ~90s and isn't worth the cost in a regression suite. All 13 cases pass on first run. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * docs(v0.26.4): testing tier docs + CHANGELOG + intra-file P0 TODO (commit 5/5) Closes the v0.26.4 ship. CLAUDE.md Testing section rewritten: - New tier table: test (fast loop, 85s) / verify (CI gates, 12s) / test:full (everything local) / test:slow / test:serial / test:e2e / check:all. Each row names its scope, wallclock, and when to use. - Intentional CI vs local divergence section: CI matrix (test-shard.sh, hash-bucketed, includes slow) vs local fast loop (run-unit-shard.sh, round-robin, excludes slow + serial). Codex correctly flagged that a parity test would always fail by design — this is the documentation that explains why. - Failure-first logging contract: .context/test-failures.log format, stderr banner, summary file, wedge handling. - File taxonomy: *.test.ts / *.slow.test.ts / *.serial.test.ts / test/e2e/. Names the two currently-quarantined files and points at the intra-file P0 TODO for the proper fix. CHANGELOG.md `## [0.26.4]` entry per voice rules: - Two-line headline: "bun run test finishes in 85 seconds. Was 18 minutes." + failure-log directive. - Lead paragraph names what shipped and why. - Numbers-that-matter table: BEFORE / AFTER / Δ for wallclock, pre-test gates, failure visibility, shards, pipe-survival. - "What this means for you" closing tied to the inner-loop user. - "To take advantage of v0.26.4" block per the v0.13+ self-repair template (gbrain upgrade + contributor steps). - Itemized changes by area (new scripts, script extensions, package.json tier split, CI tightening, failure-first logging, quarantine, regression tests, bunfig). - "What did NOT ship" section names the intra-file project + E2E template-DB project as P0/P1 follow-ups with concrete acceptance criteria. - Process section names the codex review + scope-correction loop honestly: "snapped back to ship today once empirical measurement showed Bun's --max-concurrency does nothing on tests not marked test.concurrent()." - For-contributors note on portability + single-writer + fallback paths. TODOS.md adds two P-rated entries: - P0: intra-file parallelism via --concurrent flag. Sweep ~58 PGLite sites + ~40 env mutations + 2 mock.module sites. Target: bun run test < 30s. ~1-2 weeks. Detailed acceptance criteria. References Codex findings and plan-file rationale. - P1: E2E parallelism via Postgres template databases. CREATE DATABASE TEMPLATE gbrain_template per test file. ~1-2 days. llms.txt + llms-full.txt regenerated via `bun run build:llms` to absorb the CLAUDE.md changes (per CLAUDE.md's "After any release ship that touches the Key Files annotations in CLAUDE.md, run bun run build:llms" rule). The build-llms regression test was firing in shard 7 of the parallel pass — caught the drift, regeneration cleared it. Final measurement after fix: 94s wallclock, 3652 pass, 0 fail across 8 parallel shards + 34 serial tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |