Repository navigation
Releases: savant0x/savant-code
Release list
v0.0.36
0.0.36 — 2026-10-12
v0.0.36 — development line, package release not yet published.
Verified source progress is committed and pushed tomainautomatically;
package publication and release tags remain separate operator actions.
This bump opens the dated heading so post-release work
accumulates in one place, per the no-unreleased-accumulators ruling: the
researcher-acceptance and lesson-feature-pipeline closures, the managed
scratchpad and provider-inventory passes, and everything else that lands before
the v0.0.36 cut. Release notes are written here at cut time; nothing in this
section is a package-release claim until then.
Release-audit closures (closed 2026-10-19)
- FID-2026-1018-010 — low — Preserve clickable child identity. The shared
clickable normalizer scopes React child identity withReact.Children.toArray
before flattening, so staticButton/CommandPaletteandFollowupLine
siblings stop reporting missing unique keys while explicit keys inside nested
arrays stay distinct. Host children stay non-selectable and no fragment is
introduced. Implementation:0c50fa8e; focused suite 5 pass / 0 fail, CLI
typecheck and scoped ESLint clean. - FID-2026-1018-011 — medium — Bound shared UI event subscriptions. Renderer
resize/focus/blur and ancestor scrollbar change now share one native
subscription per emitter and event, with independent consumer tokens; dispatch
snapshots its initial subscribers, skips removals and postpones additions, and
the native listener is released with its last subscriber. Thirty real animation
consumers keep their resize/focus behavior and return to baseline listener
counts across three mount/unmount cycles. Implementation:106ee6f8; 5 pass /
0 fail, 41 assertions. No operator-terminal observation is claimed by the
native render tests; LIVE-004's warning residuals stay tracked separately. - FID-2026-1018-013 — medium — Audit lifecycle and tooling hygiene. Standalone
probes execute only at their entrypoints, the console-capture and
exit-provenance diagnostic resets are wired into the CLI preload, and
object/native-FFI state carries exact self-validating lifetime exemptions
instead of a global audit suppression. Skill-evolution output moved under the
managed scratchpad active tree, audit-evidence tests run from their own
workspace, and two stale exact ledger-size pins became the audited minimums
they already described. Implementation:20b2f55c; scripts suite 1,122 pass /
0 fail. - FID-2026-1018-014 — high — Dependency advisories and unused packages.
Removed seven unused backend/native packages, upgraded vulnerable direct and
transitive pins, kept the compatible Zod 4.4.3 pin, adopted the
ESLint-9-supported typescript-eslint line while preserving the prior
catch-binding policy, and replaced two type-only runtime schemas with static
types. Persisted Bun patches bound the braces parser depth at 128 and map
gray-matter's YAML-4 engine names; a durable hostile-input probe now runs first
in the pristine-install bundle gate. The registry audit fell from 25 affected
names to one patchedbraces@3.0.3finding with no upstream fix — mitigation,
not a zero-advisory claim — and the SDK distribution stays unpublished.
Implementation:60c50a67. - FID-2026-1018-012 — medium — Release-audit reconciliation. Current docs now
match shipped behavior: the wheel/scrollbar picker claims that the allocator
repair removed are corrected, SDK installation is described as source-pinned
while its distribution stays unpublished, the scaffold examples are named with
their real consumer, and the ignored local dev links were replaced with
reachable sources. Archived records gained machine-readable commit evidence,
the configured recovery destination is reported instead of an unobserved
"OneDrive-synced" claim, andSCOPE.mdwas reconciled with the closed children.
The 0.0.36 heading moved above its own recent entries as a byte-identical
relocation, soextractChangelogSectionno longer drops the newest picker,
worktree and provider notes from generated release text. Implementation:
789ec02c.
Committed slices re-ran the hard gates: 14-workspace plus scripts typecheck exit
0, CLI 4,233 pass / 18 skip / 0 fail, scripts 1,122 pass / 0 fail, ESLint 0
warnings, Markdown lint exit 0, validate:repository PASS.
Session-summary month organization (closed 2026-10-19)
- FID-2026-1019-001 — low — Group session summaries by month automatically.
dev/session-summaries/held 367 dated artifacts (22 in 2026-07, 93 in
2026-08, 78 in 2026-09, 174 in 2026-10) in one flat directory. The SessionEnd
review now moves every dated root-level file into itsYYYY-MM/bucket —
canonicalYYYY-MM-DD-*names and the pre-conventionYYYY-MMDD-*shape
alike, and dated logs/screenshots with them — without renaming or rewriting
one byte. Planning is pure, so--checkand--dry-runreport exactly what
the apply path does; an existing destination is reported and never
overwritten; a second run is a no-op; the step fails open so organization can
never break the review. Records that cite a summary by its old flat path
(LIVE-003 evidence, the canonical learning rules, LF-005, live docs) still
resolve through a directory-scoped fallback, so historical citations were not
rewritten. The 12 summaries tracked in git moved as 100% renames. Gates: 13
unit tests pass, scripts suite 1,135 pass / 0 fail, scripts typecheck and
ESLint clean,validate:repositoryPASS (six pre-fix reference failures
gone), and a probe summary was grouped by a real SessionEnd run.
Implementation:53c270da.
Repository hygiene and docs/data parity (closed 2026-10-18)
- FID-2026-1018-007 — medium — Audit storage and reconcile current guidance.
Corrected README development callouts, SDK/local-agent examples and API docs,
testing guidance, malformed/dead links and design-generator version metadata.
Preserved old scope history outside the active register and untracked a
174,027-byte regenerable Sigma intermediate while keeping its local copy.
Audit:docs/reports/repository-hygiene-audit-2026-10-18.md.
Implementation:463d8096; 11/11 declared gates and SDK build pass; all 166
JSON-family files validate with their domain parsers, all 74 design resources
pass production integrity checks, and current-doc link checks pass. Large
ignored reference/dependency trees stay; external-home diagnostics remain
operator-owned. This is source progress, not a release or publication claim.
2026-10-19 — Stop /model from blanking the CLI (FID-2026-1018-008, critical)
Opening the model picker emptied the screen while the process kept running and
painting frames. The console channel was blocked: OpenTUI replaces
console.error during activation, so the failure text went to an overlay the
app never opens. Re-wrapping console capture on top of OpenTUI named it —
mounting 4,075 native rows returned null from createTextBuffer, React threw
in completeWork, the error boundary's <text> fallback failed identically,
and React unmounted the root. The picker now mounts only the window
getPickerViewport already computes. Measured with a new dwell probe on the
real catalog: before, the picker never appeared and render-tree-empty fired at
8 s; after, it opens, survives a 26 s dwell, and the session quits through its
normal exit path at 408 MB. Implementation: 24cf1bae. Operator acceptance
(LIVE-004): five /model opens on the same catalog during a live session with
three bashers running, none blanked, no render-tree-empty and no
TextBuffer failure recorded.
2026-10-18 — Credit a windowed boot read that reached EOF (FID-2026-1018-009, high)
A read_files call that carried limit earned no grounding credit even when
the whole file came back: limit: 2000 on the 923-line ECHO.md was read as a
partial window, so the required harness grounding set never completed, the
completion gate blocked three times, disarmed, and the turn ended with no tool
call. Credit now follows the window's effect — an offset past line 1 is
always partial, and a limit is partial only when the response used it up.
Three suites pass (27 tests), typecheck, ESLint, Prettier, Markdown lint and
validate:repository are clean. Implementation: 59d6226f.
2026-10-18 — Clarify worktree busy-lock recovery (FID-2026-1018-006, low)
Busy advice now requires confirming no live lifecycle writer remains before
removing a confirmed abandoned, empty lock. An empty directory does not prove
abandonment. Lock behavior stays fail-closed; the existing suite checks advice
and preservation of empty/populated locks. Implementation: a9413a69;
3/3 declared gates, scoped Prettier and SDK build pass.
2026-10-18 — Validate worktree acceptance artifacts (FID-2026-1018-005, medium)
The instrument now wraps its proof, lints before commit and after merge,
uses a covered tracked-file change for discard, names shells for lock steps,
and reconciles unique-row counts. Run-4 report and qualified assessment are
preserved durably. Implementation: 72aefe15; 2/2 declared gates and Markdown
lint pass. Future runs require a new authorized active converged vehicle.
2026-10-18 — Accept the demonstrated live lane lifecycle (FID-2026-1017-008, low)
Run 4 demonstrated create, isolation, scoped writes/refusals, fast-forward merge,
first-attempt graph refresh, dirty refusal, explicit discard and busy refusal.
Proof merged as a99db5b8; MD013 repaired as e0d29fb0. All 15 acceptance
gates pass. The report's 34-PASS headline conflicts with 43 PASS table labels
and one substituted SKIP. The covered-file substitution and extra repair commit
remain explicit deviations; closure does not certify unchanged-instrument
conformance or the declared untested live paths. Retained branch/stash preserved.
2026-10-18 —...
v0.0.35
0.0.35 — 2026-10-01
v0.0.35 — OpenAI as a first-class platform provider: a platform
sk-key
(/provider openai) routesopenai/<id>— and bare slugs while OpenAI is active —
over the Responses API at api.openai.com, while the ChatGPT-subscription OAuth
lane keeps precedence for its allowlisted models, and the/providerpicker finally
sorts alphabetically. The connector layer lands: the monid port ships as
packages/connectorsand its catalog reaches the agent vocabulary as a four-tool
meta-family (connector_search/describe/invoke/credentials). Direct
mode is the product — the backend-mode surface is retired across CLI and SDK
(stage 2), only an explicit env backend key defers boot routing, direct-mode 402s
render the provider's own message, and the dead login surface is deleted. Also:
the harness asserts its own identity against supplier-branded personas. Previously
shipped in v0.0.34: live-verified Vercel AI Gateway + Clean APIs, the
Cloudflare dual-credential wizard, and the Law 3 verification-gate soundness fix.
Added
- TokenHarbor catalog live realignment — 68-model roster, incl.
claude-haiku-5.5(FID-2026-1010-001, medium; closed and archived
2026-10-11; local commitf6c2048d). Operator directive 2026-10-10:
"a new model has been released on tokenharbor, called claude haiku 5.5,
however we don't have it in our model list. We need to add it". Grounding
that add against the vendor's authenticated/v1/modelsmeasured the
larger defect: the one gateway whose catalog is deliberately checked-in
rather than fetched carried 17 ids against a live roster of 68 — 52
missing (claude-opus-5.5,claude-sonnet-5.5,gpt-6-astra, the whole
muse-sparkfamily, every-fastvariant) and 1 no-longer-callable
(tokenharbor/th-orchestra). Nothing enforced the snapshot's refresh, so
it had silently rotted against a vendor that ships weekly. The realignment
re-copies the roster in the vendor's own order, uses the vendor'slabel
field verbatim for display names, re-sources 6 retained windows down to
the vendor's own publication, and pins the 3 uncorroborated ids at a
conservative 200k NEEDS-REVIEW rather than a family guess.
gemini-3.6-flash— removed earlier as roster-absent and now callable
again — is re-added, which is the point the record makes about its own
precedent: a roster-absence removal is a snapshot fact, never a permanent
ban. The Verifier's strongest finding closed a real hole the record's
premise predicted: the cli-side names map is not derived from the common
catalog, so nothing pinned it — an id added without a name silently fell
back to the sliced id.TOKENHARBOR_NAMESis now exported and asserted
bidirectionally against the catalog map. All ten declared gates passed
live; the five cli catalog suites plus the common catalog pin are 59 pass
/ 0 fail.
Added
-
Mistral AI provider integration (FID-2026-1009-005, low; closed and
archived 2026-10-11; local commit8d915d8f). Added the authenticated
catalog, dedicatedmax_context_lengthparser, registry/gateway wiring,
truthful window coverage, degraded picker visibility, and generated provider
documentation. All 17 declared gates passed. -
DSML stream recovery (FID-2026-1009-006, high; closed and archived
2026-10-11; local commitc89de4ae). Recover DSML tool calls across
reasoning/text chunks, strip stray markers, and skip orphan tool-call deltas
without terminating the session. All four declared gates passed. -
Local commit authority; pushes remain authorization-gated
(FID-2026-1011-001, medium; closed and archived 2026-10-11; local commit
15306286). ECHO G1/G2 and single-agent guidance now permit approved,
path-scoped local commits without separate authorization while keeping every
push explicitly gated. The generated protocol bundle is synchronized. -
Local model-compliance telemetry completed (FID-2026-1007-012,
low; closed and archived 2026-10-09; local commit512659cc). Metadata-only law
events carry resolved route/session/role identity into rolling 7d/30d/all
aggregates. The existing/telemetrycommand now serves summary/laws/models
while preserving consent controls. An authenticated desktop Compliance panel
shows ranked laws, a numeric law/model heatmap and dated trends, with
empty/error/disconnect recovery. SessionEnd reports drift and reviewable
dominant-law drafts without automatic promotion. Seven build-order phases
completed; browser smoke 10/10; full root regression 8,572 pass, zero failures. -
An evidence-calibrated provider identity gauntlet, offline and sweepable
(FID-2026-1007-008, high; closed and archived 2026-10-07; local commits
7e661983+66abdcfa+37d425be+b1c67fde; register item T163). The
audit of HCNSec
kimi-k3had stopped at a fingerprint timeout, and the shipped capability runner
scores task success, which is not provenance — so the route had no dated answer
about what it serves. Two halves land. The passive seam
(packages/agent-runtime/src/provider-boundary/identity-observation.ts) records
only what a completed call already returned — route, requested and served model
ids, usage, non-sensitive request ids — and replays the newest dated verdict as
advisory context; it performs no request, so a user's turn can never be delayed or
rerouted to satisfy an audit, and a pin reads its own source and fails if it ever
growsfetch(, a spawn, a node http client or a WebSocket. A verdict is bound to a
manifest version and a timestamp, so an old or unparseable date becomes an
explicitly stale advisory instead of quietly describing an endpoint that may have
changed. The active gauntlet (scripts/providers/lib/identity-core.ts+
identity-runner.ts, reachable asbun run providers:identity -- --provider <slug> --model <id> --base-url <url>) is a pure, budget-bounded, control-required engine
behind a thin transport. What it refuses to conclude is the design: no control, an
unavailable control, or fewer than two completed probes all endinconclusive, so
one probe never decides; absent token usage isno-signalrather than a tokenizer
breach; an exhausted run names the dimension that ended it instead of being
silently truncated into a pass; credentials are redacted from headers, text and
failure messages; and the research's hypotheses stay hypotheses — the tokenizer
band reports a breach as inconsistent evidence, latency is recorded as operational
data that does not identify hardware, and no numeric decision threshold is applied
anywhere (an invariant pin strips comments and proves the addendum's 0.85
auto-failover appears nowhere in the code). Three defects were caught by the pins
rather than by reasoning: a control that failed was being counted as separated
(six refused probes read as evidence of a different model), the 0.85 pin failed
against the modules' own comments until it scanned code only, and the CLI's first
draft defaulted--base-urlto a placeholder host so a misconfigured run spent
quota against a name nobody chose. The operator then required that the tool be
re-usable and rejected a single-target one-shot: every run now writes a dated
report (dev/provider-identity/), and--all/--models a,b,csweep every
catalog route and report each separately — a route being down is never the
provider being down (HCNSec servedglm-5.3-flashwith 200 whilekimi-k3
returned 500 in the same minute), with the servedmodellabel as a first-class
signal. A live sweep of the seven-route HCNSec catalog read ok 1 / failed 6. A
fourth defect surfaced from the live runs: the transport counted an HTTP error
envelope as a completed sample, so two dead endpoints read asmatched.
Receipt 9/9; the record is closed and archived 2026-10-07 on the operator's
ruling that the reusable tool, not one route's verdict, is the deliverable. The
observedglm-5.3-flash->longcat-2.5-preview-freesubstitution needs its own
record. -
The sidebar reports provider cache reuse truthfully (FID-2026-1007-009, medium;
closed 2026-10-07; local commits8c528f12+07fbbbd9; register item T164).
Cache reuse was invisible in the CLI, and three layers had each destroyed the fact
the row needs:emitCacheDebugUsagecoerced an absent cache field to0,
isCachedTokenCountKnownthen treated every0as unknown, and the only cache
monitor was constructed per step and fed only underCACHE_DEBUG_FULL_LOGGING— so
an ordinary run accumulated nothing and no CLI code consumed it at all. Presence
now travels end to end: the emitter reportscachedInputTokensReported, the R3 seam
lets presence win while the legacy> 0heuristic stands unchanged for records
without the flag, and a new pure accumulator folds every completed usage into
agentState.cacheUsagefrom the always-ononUsagecallback. The aggregate is
input-token weighted (sum(cached) / sum(eligible input)) so a 100-token call
cannot speak for a 900-token one, is bucketed by provider route and model so
switching models never blends unlike traffic, excludes unreported records from the
ratio instead of diluting it, rejects negative and cached-over-input counts as
invalid rather than clamping them into a plausible number, and ignores a repeated
observation key so a re-finalized response is not counted twice. The Session
section renders one always-presentCacherow that keeps three meaningfully
different states apart ——when nothing usable was observed,Not reportedwhen
the provider omitted the field, and0%for a reported cache miss — with the toke...
v0.0.34
0.0.34 — 2026-09-28
/provider free — free-options discovery, agent-answerable (FID-2026-0928-012) — closed 2026-09-28
Savant-Code is BYOK — there is no Savant backend or credit balance, so
"free" means free tiers/models of the gateways the user wires with their own
keys, and nothing told the user what those were. New /provider free
subcommand: on invocation (never at boot) it live-fetches the keyless
custats free-models catalog (free-llm-models.custats.info, agent-facing by
design — robots Policy A; 24h TTL cache, 30s timeout, soft-degrade to the
last-good cache with a staleness note on failure), splits free lanes by the
user's OWN wired keys (readStoredProviderKeys ∪ non-empty env vars — the
same truth applyPersistedProviderApiKeys consumes), and lists wired &
free (models usable today), free but not wired (with the exact
/provider <name> onboarding command), and local & free (ollama, no
key). The same refresh writes ~/.savant-code/free-options.md — the
agent-answerable reference — so the user and the agent share one canonical
surface: ask the agent "what free options do I have?" and it reads that
file. free joins the /provider grammar words (wizard custom-id
reservation picks it up automatically). Content is untrusted third-party
text rendered as read-only information; nothing mutates configuration.
custats feeds wired in as the discovery pipeline's second source (FID-2026-0928-011) — closed 2026-09-28
The free-compute discovery pipeline (providers:harvest) was single-source
(freeairouter.com). New providers:custats leg adds
freetokens.custats.info/feed (RSS, 196 offers — the 87 api_provider
offers parse to an offers ledger with expiry dates; offers are TIME EVENTS
and never enter the host candidate queue) and free-llm-models.custats.info
(OpenRouter-schema catalog, 161 rows — enrichment + retirement signal via
newModelIds/archivedModels/expiration_date; all 6 of its providers are
already tracked). Host attribution is conservative two-mechanism (host
literals + ≥3-char brand-label tokens; "Vercel AI Gateway" prose now
attributes, "Z AI" deliberately lands in the operator-review bucket); new
discovery lanes still enter only through SEED_HOSTS review. Freshness gates
(RSS ≤72h, catalog ≤48h) soft-skip stale cycles instead of failing
automation. LIVE: 43 attributed / 44 unattributed / 1 expiring soon
(Vercel Ling 3.0 window, 6 days out). RED-first: 18/18 pins; the pins caught
two real defects pre-live (fixture lying about the malformed-row contract;
matcher blind to brand-label prose).
Law 3 credit + FID receipt deadlock closed: the write-boundary residual accepted as final (FID-2026-0927-003) — closed 2026-09-28
Closed by operator ruling (2026-09-28): asked to choose between running the
declared gates at write time or accepting the repository-only stale-receipt
demotion, the operator ruled "T90-F3 residual needs no code" — the
repository-only demotion is the final disposition. The F1 fix (Law 3 credit
is outcome-aware; a red bun test can no longer be credited as a pass),
the F2 fix (failure-attributed exemption + self_correct fallback end the
deadlock without opening a masking vector), and the F3 repository-gate half
(a stale receipt demotes to a warning when every declared gate passes the
C3 live re-run) all stand as shipped and mutation-proven. The write boundary
(pre-write-gates-fid.ts:105, scripts/fid-check.ts:40) intentionally
keeps treating a stale receipt as fatal: it cannot run the C3 re-run at
write time, and the operator declines the weaker write-time guarantee. The
FID's Open Remediation section now records accepted behavior, not
outstanding work.
CommandCode GLM ids re-keyed to the live roster; window-truth probe repaired (FID-2026-0928-010) — closed 2026-09-28
The T62-followup(1) register item, grounded LIVE on 2026-09-28. The static
commandcode catalog pinned zai-org/glm-5.2/glm-5.3 lowercase while the
live roster serves zai-org/GLM-5.2/GLM-5.3 — the realign FID's own
CHANGELOG says uppercase, so the lowercase spellings shipped as a
transcription defect that its test pins then embalmed; the wire path sends
catalog ids verbatim after the prefix strip. Catalog, protocol map, and
fallback-table rows are re-keyed to the roster casing, and the two rows'
windows are re-sourced to the gateway's own publication (the commandcode
roster publishes context_length per id — 1,000,000 for both rows, a
strictly conservative correction from 1,048,576 / 1,310,720; upstream votes
kept in the comment trail). The provider's fail-open /models boundary
(keyless GET → HTTP 200 with the full 82-id roster, re-measured 2026-09-28;
TokenRouter/TokenHarbor 401 for the same shape) is vendor-side posture and
is now documented on the registry entry with a pin, not patched. Bonus
repair: verify-window-truth.ts had been structurally red since the
realign — 4 sample rows referenced removed/pre-realign table keys. Samples
re-pointed (incl. tokenharbor/deepseek-v4-flash to orcarouter after a
2-of-3 vote upheld the table row against a bazaarlink drift), two re-keyed
commandcode samples added, and a new in-process pin makes stranded probe
samples a gate failure instead of silent rot (LIVE: probe exits 0, 14/14
rows match). RED-first pin suite observed 1 pass/4 fail pre-change.
Every scripts/** file is now type-gated: 36 errors fixed, boundary widened (FID-2026-0928-007) — closed 2026-09-28
The T84-C triage reproduced the unreproducible 36 errors across 14 files
figure (the earlier TS5102 failures were a cwd/config-resolution artifact)
and categorized every error. Under the operator's Option 1 ruling:
scripts/tsconfig.json now compiles the entire tree (include: ["**/*.ts"]) in the standing typecheck:scripts hard gate — previously a
closed include list covered only the release engine, and not even every test
in its own directory.
The 36 errors fell in four classes, all fixed: 8 real production defects
(audit-evidence.ts wrote a durationMs field its own type denied;
fid-verify.ts normalized Bun's signalCode: undefined to null at the
boundary rather than widening the contract; candidates-io.ts,
harvest-phases.ts/health.ts, propose-provider.ts type-lag repairs),
8 stale buildReceipt calls in fid-verify.test.ts that had silently
verified receipts built with verifiedAt: undefined (bun does not
arity-check), 18 test-fixture friction errors (typed fixtures against
CustomProviderConfig/ReportInput/NudgeCandidate, explicit
as unknown as typeof fetch doubles), and 2 errors in a production-dead
file (provider-stamp.ts, rewritten as the canonical-typed seam; its
drifted DiscoveryStamp import and hand-rolled stamp fields are gone).
Cloudflare is now setup-surfaced: the dual-credential seam (FID-2026-0928-008) — closed 2026-09-28
Under the operator's Option A ruling, ProviderSetupInfo gained optional
extraEnvVars populated by deriveSetupConfig from credentials.extra, and
Cloudflare flipped setupAvailable: true — the last registered gateway that
was fully routed yet invisible in /provider. The wizard now prompts for the
account id after the token (staged per session in beginProviderSetup,
chained through routeKeySetup's new post-save getNextInputMode hook, with
an emptyValueMessage override so an account id is never called an "API
key"); saveProviderApiKeyExtra persists extras under their own env-var
names in the shared 0600 store; applyPersistedProviderApiKeys applies them
at run start. The provider-exception manifest dropped the stale
setup-exclusion entry — the audit gate flagged it live. Registry test's
setup-provider count pin moved 18 → 19; README (EN + zh-CN) provider
surfaces updated.
Utility-tier duplication is now mechanically enforced (FID-2026-0928-009) — closed 2026-09-28
The shelved idea-shelf report became a filed record, was activated by the
operator, and shipped in three sequenced parts. Part 4 (sweep): canonical
homes created (isRecord in common/util/object.ts, sha256/sha256Hex in
the new common/util/hash.ts, the asOptionalString/asOptionalNumber
pair in the new cli/src/utils/openrouter-models/wire-guards.ts); all 9+8
per-shim guard copies deleted in favor of the shared import; withTimeout
deduped to common/util/promise.ts (the OSC resolve-value variant renamed
withTimeoutValue — different behavior, different name); the four
genuinely-different isRecord predicates renamed for what they are. Final
counts: one body per primitive. Parts 1+2+3 (the gate): the new
no-duplicate-shared-primitive ESLint rule (registry-driven:
shared-primitives.json) errors on any top-level re-declaration of a
registered primitive outside its canonical home, wired active in the
standing eslint . --max-warnings 0 pre-push leg, with 5 fixture-backed
pins. It earned its keep on first run: 7 additional stragglers the manual
scan missed, each explicitly dispositioned (the clean-process attestation
tree's independence is contract, not duplication). Part 5: the rule
header documents harvest inheritance — future provider shims must import the
shared guards, so the fan-out that created 17 duplicates cannot recur
silently.
All eight live catalogs probed: nested-shape reconciliation closes with a null result (FID-2026-0928-006) — closed 2026-09-28
The T96-followup per-vendor live probe ran against every live catalog endpoint
in the registry (all HTTP 200): openrouter 459, nous 418, cleanapis 33
(re-measured by FID-2026-0927-005), apinex 34, kiosapi 36, bai 57, orcarouter
204, nvidia 81, vercel 389 models. The three parsers that read the nested
architecture.* fields are exactly the three vendors that measura...
v0.0.33
0.0.33 — 2026-09-22
The last five hook events, and the contract that described them (FID-2026-0919-031) — Closed + archived 2026-09-22
- The five declared-but-inert events now fire, each with the semantics it had
to be given first.Stop/Interruptsplit on who ended the turn
(finished on its own terms vs cancelled; a failure fires neither, and both are
main-agent only — children report viaSubagentStop).PreCompactis the
compaction attempt (the pruner spawn) andPostCompactonly fires on the
runtime's existingprunedpredicate, so a compaction that removed nothing
cannot claim the context was compacted — the unmatchedPreCompactis the
signal.Notificationis the runtime handing control to the operator (an
ask_usercall), carrying the questions. - The census now asks for reachability, not spelling. Naming an event in a
helper's parameter type is what a type annotation does without firing anything,
so a helper-mediated event counts only with a caller outside the module — and
only with a caller passing that event when the helper is event-parameterized.
Both holes were found by trying to break the rule: deleting theNotification
call site and deleting theStopcall site each now fail the probe by name. - The documented contract was read back against the source, and five drifts
corrected. The events table (all twelve fire, with semantics), the
payload-field table (outcome / compaction / notification fields), theSource
section — which named a parser function in a file that does not contain it and
three wiring files that fire nothing — the missingactionconfig row, and the
previously unstated behaviour ofmatcheron a tool-less event (it is not
consulted: the hook runs, because a config typo becoming a hook that silently
never runs is the failure mode the event classification exists to prevent). - Found and fixed by the new pins, not by review:
fireNotificationHook
hardcodedtool_name: 'ask_user', so a notification raised for any other
reason would have named a tool that never ran. - 16 new pins / 4 negative legs; full chain 7593 pass / 0 fail at
implementation. - Closed + archived 2026-09-22 on the operator's closure directive; the
receipt was re-stamped LIVE at the archived path so the closed record is
byte-consistent with its final content. Commit SHA pending operator git
execution (G2 withheld).
The hook surface tells the truth: acting agent on PreToolUse, session outcome, fired-vs-declared event census (FID-2026-0919-030) — Closed + archived 2026-09-19
PreToolUsecould not say who was acting. It is the only hook event that
can BLOCK a tool, and it is documented as composing with the EHEL gate — which
gates per agent. Both call sites (the native gate chain and the custom/MCP
path) sentsession_id+cwd+tool_name+tool_inputonly, so the natural
policies were inexpressible: "deny writes unless the caller isforge" had no
field to test, and a subagent's call arrived under the child's run id with
nothing naming the child. Both sites now carry the acting agent, and a census
pin makes a third site impossible to add without it.SessionStart/SessionEndwere outcome-blind.SessionEndfires in a
finallywith identity only, so a clean end and a crash were indistinguishable
at the hook — theSubagentStopdefect one boundary up. The outcome is now
computed on every path (return, error-form return, thrown) and reported, with
SessionStartdeliberately outcome-free. Both lifecycles share ONE builder
(hooks/run-outcome.ts;hooks/subagent-outcome.tsre-exports), because two
implementations of the same boundary binding is how FID-2026-0919-027's
governance leak started.- Five of the twelve declared hook events never fired, and nothing said so.
PreCompact,PostCompact,Stop,InterruptandNotificationare in the
config vocabulary (so they parse and load) and were documented in
docs/design/hook-system.mdas active — but had zero firing sites in the
runtime. A hook declared for one of them was silently inert: no parse error, no
warning, nothing to observe. The sets are now data (FIRED_HOOK_EVENTS/
NEVER_FIRED_HOOK_EVENTS, each inert event with the blocker that keeps it
inert) with compile-time exhaustiveness gates, verified against the runtime
source byscripts/hook-events-check.ts, which also fails if this repo's own
protocol.config.yamldeclares an inert hook. The doc's Events table now states
what fires today. - The blockers are named, not hidden: three of the five have no defined
trigger in the repo's own docs (Stop/Interruptare documented as the same
thing;Notificationhas no trigger at all), and the compaction pair needs an
attempt-vs-effect semantics ruling plus two scattered sites — the pruner can
complete having compacted nothing, so firing "around compaction" without a
predicate would emit an event that lies. - 10 new pins / 49 expectations, driven at the real boundaries (
createHookGate
for the payload the engine receives,mainPromptfor all three session
endings) plus the source census. Full chain 7577 pass / 0 fail. Three negative
legs: drop the agent field → 3 red; drop the session outcome → 3 red; give an
inert event a firing site → 2 red and the probe exit 1. All sources restored. - Closed + archived 2026-09-19 (operator directive). Record at
dev/fids/archive/FID-2026-0919-030-hook-surface-truth.md; receipt re-stamped
LIVE at the archived path (5/5 gates), fingerprintsha256:724b6c62…. Commit
SHA pending operator git execution (G2 withheld).
Boundary observability and enumeration: SubagentStop outcome payload + SessionState/FileContext field partitions (FID-2026-0919-029) — Closed + archived 2026-09-19
- Operator hooks could not tell a finished child from a failed one.
SubagentStart/SubagentStopfired with type, session and cwd only, so
three genuinely different endings — the loop returned usable output, the loop
returned the error form ({ type: 'error', message }, which is how a silent
no-assistant-turn run already reports itself), and the loop threw — produced
byte-identical payloads. The hook contract already supported
tool_result/error_message(the same fieldsPostToolUse/
PostToolUseFailureuse);executeSubagent, the single funnel both spawn paths
share, never set them.hooks/subagent-outcome.tsnow builds the payload and
every terminal branch sets it — including thecatch, which reports the cause
and still rethrows. The default before any branch is the truthful
"unknown ⇒ failed", so an unhandled path fails loudly instead of reporting
success. The payload carries identity and shape only (status,agentType,
runId,creditsUsed,outputType,errorMessage): hook JSON is stdin for
hook commands, so a child's transcript would be unbounded and would be a
content-leak path.SubagentStartis pinned to stay outcome-free. SessionStateandProjectFileContextnow have enumerated boundary
contracts. FID-2026-0919-028 madeAgentStateself-enforcing at the spawn
boundary and recorded this as the natural extension. Both types have a boundary:
cloneSessionStatedeep-copiesmainAgentState(JSON round-trip, for
byte-parity with the persisted snapshot) and sharesfileContextby reference
(~230ms per snapshot avoided on the render thread); run start rewrites 10 of the
16 file-context fields across two modules and carries the other 6.
common/src/types/session-boundary-fields.tsclassifies every key once,
AssertNevergates make an unclassified field a build failure, and each
exemption carries the reason it is safe.gitChangesis now declared as
carried — captured at session init and not refreshed on resume — rather than
left for someone to discover.- The census, not just the type, is the gate. A boundary can drift by gaining
a writer without gaining a type key, so the pins include a census over the two
modules that assignfileContext.*: a new unclassified writer fails a test.
scripts/handoff-transport-check.tsnow asks all three boundary questions
(child, snapshot, run start) reading the shipped lists. - 15 new pins (7 hook-outcome through the real
handleSpawnAgents→
executeSubagentboundary, 8 partition pins driven off the shipped lists, 81
expectations). Full chain 7567 pass / 0 fail. Every gate was proven by a
negative leg: dropping thetoolResultargument → 3 pins red; a field injected
into each type →error TS2344at its gate; a new run-start writer → census
unclassified; a writer on a carried field and a copiedfileContext→ the
probe exit 1. All sources restored. - Closed + archived 2026-09-19 (operator directive). Record at
dev/fids/archive/FID-2026-0919-029-boundary-outcome-and-enumeration.md; receipt
re-stamped LIVE at the archived path (7/7 gates), fingerprint
sha256:fb6eabb5…. Commit SHA pending operator git execution (G2 withheld).
Spawn boundary made self-enforcing: an unclassified AgentState field is a build failure (FID-2026-0919-028) — Closed + archived 2026-09-19
- The mechanism that dropped the governance configuration is closed, not just
the fields it dropped.createAgentStateinherited a hand-written list of
parent fields, so the next field added toAgentStatewould be silently
absent on every child — exactly how FID-2026-0919-027's four governance fields
went missing, and why finding them took a full audit. Every one of the 54
AgentStatekeys is now classified exactly once inspawn-child-fields.ts:
13 inherited, 14 child-owned, and 27 deliberately absent with a
stated reason each (groundingCheckpoint,maxContextLength/digestCaps
because `createLoopC...
v0.0.32
0.0.32 — 2026-09-18
Free-compute harvester probes run through a bounded pool (FID-2026-0918-001)
- The daily harvester (
scripts/providers/harvest-freeairouter.ts) probed
every tracked host serially — one host at a time, up to 3 network
round-trips × 10s timeout each — and 41 of 71 tracked hosts sit at
boundary-unverifiable, re-probed every run by design. The probe loop
dominated the run's wall clock. - New
scripts/providers/lib/probe-pool.ts:runWithConcurrencyworker
pool withPROBE_CONCURRENCY = 6(named constant beside the timeout it
overlaps). Both probe sites wired through it: the daily probe-merge phase
and the Stage-E health loop — the latter split into its own module
scripts/providers/lib/health-probe.ts(move-only seam split) to hold
harvest-report-phase.tsunder the 300-line ceiling. Per-host etiquette
untouched: hosts are distinct vendor endpoints, still one probe set each. - RED-first: 9-pin suite written before the implementation (cap, ordering,
empty, oversized limit, serial degradation, rejection propagation,
constant pin, pooled health ×2). LIVE evidence: full--probeharvest
exit 0 in 13.7s (214 records, ~43 probes) — the serial bound was minutes. - Gates: probe-pool 9/0; providers tree 110/0; eslint 0 warnings;
quality:report PASS; lint:md + prettier clean; fid:verify 5/5 gates PASS,
receipt stamped. Commit69f6e7a7. Closed + archived 2026-09-18.
Unverifiable hosts re-probe on a 3-day cadence (FID-2026-0918-002)
- The harvester re-probed all 41
boundary-unverifiablehosts every daily
run even though a boundary verdict only needs re-measurement after the
lapse window (PROBE_LAPSED_AFTER_DAYS = 3). New
shouldReprobeUnverifiable()gate skips hosts with a fresh
lastProbeAttemptUtc(< 3 days) and fail-opens on stale/never/malformed
values — worst case one extra probe, never lost evidence. Every attempted
probe stampswithProbeAttempt()so failed measurements don't re-fire
early. - State layer: optional
lastProbeAttemptUtconCandidateStatewith
defensive parse — plus an explicit carry-forward line indiffCandidates,
which rebuilds every re-sighted host record from a field literal and
would otherwise have silently dropped the field on every run (a pin
proves a re-sight preserves it). - LIVE double-run evidence: run 1 stamped 40 hosts (14.0s); same-day run 2
skipped every freshly-stamped host (identical host sets, zero timestamp
diffs) in 1.13s. Combined with FID-2026-0918-001 the daily scan drops
from ~14s to ~1.1s typical wall clock, evidence freshness bounded at
3 days by construction. - Gates: probe-cadence 9/0; providers tree 119/0; typecheck common exit 0;
quality PASS; fid:verify 5/5 gates PASS. Commit69f6e7a7. Closed +
archived 2026-09-18.
/model picker now activates the selected provider's routing (FID-2026-0917-005)
- Selecting a model in the
/modelpicker persisted the model's provider to
settings.jsonbut never activated it in the runtime environment.
process.env.DIRECT_PROVIDERandprocess.env.INFERENCE_BASE_URLstayed
empty, soisDirectProviderMode()returned false — the usage monitor
queried the SavantCode backend (402 → "Out of credits. Please add credits
at https://savant-code.com/usage") and the inference request itself routed
togetWebsiteUrl()(savant-code.com) instead of the selected provider.
The UI said the provider was selected, but requests silently passthrough-ed
to the SavantCode website. A different layer from the OpenRouter key fixes
(FID-2026-0917-003/-004) with the same user-visible symptom; the/provider
picker avoided the bug because it already calledactivateConfiguredProvider. - The selection logic is extracted into
applyModelPickerSelection(model)in
cli/src/utils/provider-setup.ts(Law 13 — one function, one truth: resolves
model.provider ?? 'openrouter', persists the model preference, and
activates viaactivateConfiguredProvider, the same guarded seam the
/providerpicker uses).handleModelPickerSelectis now a one-line
delegation, so the regression suite exercises the real production seam
rather than a copy of its logic. The provider preference is persisted only
when activation declines (unkeyed provider) — no duplicated write on the
happy path. - Fail-closed preserved: an unkeyed provider declines activation and leaves an
explicitINFERENCE_BASE_URLuntouched — the SDK surfaces a clear
missing-key error at send time rather than sending a stale credential. - Gates: typecheck cli exit 0; eslint 0/0 on all three files; prettier clean;
model-picker-activation + provider-setup 25 pass / 0 fail (77 expects);
receipt 3/3 PASS re-stamped live at the archived path; independent Verifier
AUDIT PASS on all functional criteria (two findings fixed en route: a
tautological test target resolved by the extraction, and a redundant persist
call removed). Production call-graph confirmed:use-chat-pickers.ts→
build-chat-layout-props.ts:181(onModelPickerSelect) → production chat
UI. Commits91daaf93(fix + test) +6b326d61(FID record). Closed +
archived 2026-09-17.
Rejected OpenRouter master key now fails closed, not silently (FID-2026-0917-004)
resolveOpenRouterApiKey()treated any failed master-key exchange as a
soft failure: log a warning, then fall through toOPENROUTER_API_KEY.
When that fallback held a stale or revoked key, the CLI silently sent a
dead credential and the operator saw the vendor 401User not found.at
chat-completions time — an error naming neither the dead key nor the failed
exchange that selected it. Second occurrence of this exact anti-pattern
(FID-2026-0917-001 added the diagnostics but kept the fallthrough).- A 401/403 from the
/api/v1/keysexchange is now terminal: it
negative-caches (cachedKey = null) and returnsundefinedinstead of
substituting a different credential for the one the operator configured.
Becauseopenrouteris a registeredkind: 'gateway'provider
(common/src/providers/registry.ts:23-25),getModelForRequest's
active-provider guard throws the templated missing-key error before
createDefaultInferenceModelis reached — so the operator gets an accurate
message, not a dead key sent upstream. Transient failures (429, 5xx,
network) keep the soft fallthrough, since a still-valid regular key remains
legitimately usable while the exchange endpoint is unavailable. - Returning
undefinedpreserves the existingstring | undefinedcontract
— no new throw sites, no caller breakage. The negative cache reuses the
existing environment-signature invalidation and
resetOpenRouterApiKeyCache(), so a fresh key stored via/provider
recovers without a restart. - Gates: sdk typecheck exit 0; resolver suite 13 pass / 0 fail (5 new);
eslint 0 warnings; prettier clean;lint:mdexit 0; independent Verifier
AUDIT — 4 PASS / 1 FAIL refuted with registry evidence (the flagged
?? apiKeyfallback is unreachable on the liveDIRECT_PROVIDER=openrouter
path because the gateway guard throws first). Shipped to the rebuilt
sdk/distthe running CLI loads. Closed + archived 2026-09-17.
OpenRouter key shadowed by Bun dotenv auto-loader in dev boot (FID-2026-0917-003)
- Every OpenRouter call in local dev failed with
User not found.because
Bun's dotenv auto-loader is not disabled by the--cwd ..flag in the
dev script, contrary to the comment atload-dev-env.ts:5-6. With
cwd=cli/, Bun pre-seededprocess.env.OR_MASTER_KEYfrom the stale
cli/.env.localbeforeload-dev-env.tsran; the "existing env wins" rule
then permanently locked in that value, so the good repo-root key was
always skipped. - Three-part fix:
--no-env-fileadded to the dev script
(cli/package.json:17) soload-dev-env.tsis the sole deterministic
loader; the false comment replaced with the real mechanism; the divergent
staleOR_MASTER_KEYremoved fromcli/.env.local(gitignored — a
local-machine fix). The staleOPENROUTER_API_KEYwas also cleared from
HKCU\Environment. - Bidirectional probe, identical command, one flag different: stale key →
401 →User not found.; root key → exchange OK → HTTP 200. Gates:
typecheck cli exit 0; probe exit 0; quality exit 0. Closed + archived
2026-09-17.
EHEL Law 3 gate no longer deadlocks writes on a lint-failing doc (FID-2026-0917-002)
- The EHEL pre-write Law 3 gate blocked every write tool call — including
the exactstr_replacethat would have fixed the violation — because a
markdown doc (dev/handoff.md) sat indirtyFileswith a failing
markdownlint (MD040) run keeping it out ofverifiedFiles. The violation
blocked its own remedy: a write/verify ordering deadlock. Root cause was a
policy enforced at one lifecycle point and not another:classifyFileKind
already classifies*.mdasdocsandevaluateWritesAtStepBoundary
already declares "documentation artifacts gate on markdownlint, never on
Law 3" — but the pre-write gate checked only theisExemptWritePathprefix
list (dev/fids/,dev/nova/,dev/scratchpad/), omittingdocs/,
dev/handoff.md,dev/session-summaries/, andREADME.md. - One-predicate fix reusing the existing classifier (Law 13 — one function,
one truth):unverifiedDirtynow filters toclassifyFileKind(f) === 'code'. Code verification is not weakened — a dirty code file still
hard-blocks, and a mixed doc+code set still blocks while naming only the
code file (pinned by a regression test). The Law 15 advisory scanner is
intentionally left unguarded: it reports ALL unverified files, docs
included, as an advisory rather than a block. - Second independent blocker fixed:
dev/wiki/patterns/*.md(MD013,
machine-generated 286-char lines) kept repo-widelint:mdat exit 1, so no
doc coul...
v0.0.31
0.0.31 — 2026-09-13
Release pre-audit stage added (FID-2026-0913-004)
- After four consecutive post-confirmation aborts on v0.0.31 release
night, the release now sweeps its precondition surface BEFORE printing
the plan: worktree churn (harness telemetry auto-commits), zombie
release locks (dead-owner locks removed), leftover unpushed tags
(deleted only when ls-remote-verified absent), a dry-run of the real
pre-push credential scan including its 2MB blob cap, config-dir
pollution detection, and the test-isolation canary. Blocking findings
abort before confirmation with exact remediation; safe fixes are
applied and logged. - Standalone:
bun run release:preaudit(fixes) /release:preaudit:check
(report only).
Release-gate test isolation fixed; operator credentials restored (FID-2026-0913-003)
- Defect: the fid-gate live re-run executes test gates from the repo
root, where only the rootbunfig.tomlpreload applies — the CLI's own
test-env pin never loads. Under the release's public profile
(NEXT_PUBLIC_CB_ENVIRONMENT=prod),getConfigDir()ignored the tests'
SAVANT_CODE_CONFIG_DIRoverride, so CLI provider tests read and wrote
the real~/.savant-code/directory: two v0.0.31 release attempts failed
therepository-validationgate deterministically, and the operator's
realcredentials.jsonwas overwritten with test fakes. - Recovery: all gateway keys restored from the live shell environment;
the polluted file preserved ascredentials.json.polluted-by-release-gates.bak. - Fix (three layers): the root preload (
sdk/test/setup-env.ts) demotes
an inheritedprodto the test runtime (explicit per-test values still
win); fid-gate children spawn withNODE_ENV=test/BUN_ENV=test; a
canary test plus an executable probe pin the release shape (override
honored, real config dir byte-identical) so any regression fails closed. - Evidence: the exact release-shaped repro went from exit 1 (5/18
failing, credentials polluted) to exit 0 (18/18, byte-identical config
dir);validate:repositoryPASS.
Quality rule is ceiling-only; hard-cap split program clears all 9 over-cap files (2026-09-13)
- Operator ruling (2026-09-13): the file-size rule is a pure ceiling —
under-cap files may grow freely; exceeding 300 lines is a hard violation.
The growth ratchet ("exceeds baseline N") is removed from
scripts/quality-report.ts;dataConstantExemptionsgrowth-freeze,
exemption guards, andapprovedGrowthrejection are preserved. - FID-2026-0913-002: nine files over the cap split along existing seams
(facade re-exports, zero consumer churn) — stream.ts (331→288 +
stream-error-chunk 110), custom-providers (431→153 + parse 245 + catalog
82), provider-wizard (467→74 + instructions 117 + steps 279 + replay 63),
provider-subcommands (402→40 + parse 36 + replies 63 + picker 72 +
handlers 248), route-user-prompt (312→281 + route-masked-key-setup 94),
lookup (310→236 + model-info 84), and three over-cap test files split
with exact test-count parity (wizard 579→299/261/46, commands 363→278 +
harness 142, str-replace 402→267/155). Two pre-existing stale pins
exposed and repaired honestly (the commands-file wizard walk + CFG
fixture predated the FID-2026-0911-003 protocol step — proven failing at
HEAD pre-split by stash test). Baseline refreshed to 1,498 files;
quality: PASS; archived FID-2026-0912-005 carries an erratum for its
shifted pinned line numbers.
hcnsec + TokenBom gateway providers: audited 14-model static allowlist (2026-09-13)
- FID-2026-0913-001 — CLOSED + archived 2026-09-13 (implementation
commit5e8cd5c8). Adds the two identity-audited gateways as
built-in providers (15th/16th registry entries): HCNSec
(api.hcnsec.cn/v1,HCNSEC_API_KEY) and TokenBom
(tokenbom.com/v1,TOKENBOM_API_KEY) — OpenAI protocol,
idTransform: 'strip',order: 4(TokenHarbor static pattern: no
wrapper file, no audit-manifest entry). Both carry STATIC catalogs of
exactly the 7-genuine-channel allowlist per gateway that the operator's
identity audits confirmed (Tasks 43-E/44-C; full report
docs/provider-identity-audit-2026-09-13.md) — deliberately not live
/v1/models, which re-exposes the substituted, injected, and dead
listings the audits rejected. Picker surfaces the allowlists with
per-model context windows pinned from the OpenRouter catalog (13/14;
doubao conservatively defaulted + flagged), a new
common/src/constants/model-config/gateway-catalogs.tsmodule (the
300-line cap forces the split), gateway merge + setup + docs regen.
RED-first 10 legs; gates: typecheck ×4, regression 59/0 + 35/0 + 48/0,
eslint 0, prettier, lint:md,generate:provider-docs:checkexit 0.
Closure gate: keyed live round-trip through the production chain —
1,378-model combined catalog, hcnsec 7/7 + tokenbom 7/7, HTTP 200 chat
on both gateways. Trust posture: personal-use static allowlists;
exclusions stay excluded.
Vendor-path tool-call classification: native-incomplete machinery extended to Anthropic/Google-compatible families (2026-09-12)
- FID-2026-0912-005 — CLOSED + archived 2026-09-13 (implementation
commita6853358).
Origin: the Task 40 audit of tool-call repair against Pi's fail-closed
truncated-args rule found that vendor SDK families
(@ai-sdk/anthropic / @ai-sdk/google viamodel-factories.ts) bypass the
OpenAI-compatible flush gate, so invalid (truncated/unknown-tool) tool
calls degraded to a generic tool-error — steering, strike counting with
exhaustion, and the PostToolUseFailure experience-capture ledger never
fired. Fix is SDK-boundary-only:promptAiSdkStream'stool-callbranch
now classifiesinvalid === trueparts through the single
normalizeNativeToolCallStreamErrorfactory with a fail-closed null
guard, and forwards valid parts byte-identically. RED-first: pin test
observed 2 fail / 1 pass pre-fix, 9/9 post; runtime-integration suites
(part-f, strikes, experience-capture, steering) 16/16 with ZERO runtime
changes; typecheck ×4; receipt 5/5 PASS; lint:md + prettier clean.
Residual documented in the FID (no finishReason on vendor
classification → generic retry guidance rather than the split-payload
hint; follow-up only if observed).
Skill-evolution suite: SkillOpt + WikiSkill adapted, implemented RED-first, closed + archived (2026-09-12)
- FID-2026-0912-001..004 — all four implemented + CLOSED (this
pass, operator directive: complete all open FIDs at automation
level 3). The self-improving harness's four structural gaps are
closed with zero governance change (operator-only trust preserved):
trust/untrust now append full ledger entries and trust runs a
fail-closed drift gate against the draft'sbaselineSha(-001,
commitd95502f); the destructive 30-day draft purge is replaced by
a monotonic archive move withARCHIVED.jsonprovenance (-002,
commitf83ea32); a durable pattern wiki (dev/wiki/) is written
mechanically by the session-end review from dedup-engine promotions,
update-only and never boot-read (-003, commitc36db40); and a
cold-spawnedscribe-proposerdrafts at most one atomic proposal
from wiki evidence alone through a shared gate (strict mean lift
AND zero per-task regressions — the SkillOpt #67 conjunction) with
honest[✓ PROVEN]/[⚠ UNPROVEN — TRUSTING BLIND]labels,
rejected-proposal wiki memory, and a store-enforced one-proposal cap
(-004, commit3921356). Gates: typecheck ×6, common 721/0, agents
109/0, cli + evals suites green, eslint 0, lint:md, prettier.
Honest boundary: live proposer behavior (drafting quality under
isolation on free-tier models) is operator-observable only;
rejection-heavy early output is the gate working, not failing.
Open-FID sweep: two closures, two implementations, one vendor-held gate (2026-09-12)
- FID-2026-0911-001 — closed. /provider picker add-new entry
(sentinel action row → full wizard; unknown-selection silent
fall-through fixed) shipped and archived; the operator's pre-closure
due-diligence findings routed to FID-2026-0911-003. - FID-2026-0909-008 — closed. Tool-call truncation root cause:
Steps 1-5 shipped; the live finish-reason proof is wired as an
always-on instrument (experience capture) rather than left as an
open-awaiting-failure status. - FID-2026-0911-003 — CLOSED (this pass). Custom-provider
hardening from the operator's due diligence:resolveProtocol
latent-misdispatch fix, optional anthropic protocol for custom
providers (wizard step + validation + lift), a protocol-aware live
key probe at the wizard terminal step (never blocks the save),
/provider test <id>, and a/healthlive line — one verify helper
behind three surfaces. Committed8984711; closed 2026-09-12 after a
ground-truth pass verified every GREEN claim at file:line. Live
wizard test with a real Anthropic-outlier entry waived at closure,
never passed — first natural use confirms forward. Archived. - FID-2026-0911-004 — implemented + CLOSED (this pass). B.AI
gateway provider (14th registry entry): OpenAI Chat Completions +
Responses + Anthropic Messages surfaces behind oneBAI_API_KEY,
authenticated live catalog via the resolveKey pattern,
uniform-prefix parser pins. Committed2e58cf06. Keyed acceptance
PASSED with the operator's key: catalog 47/47 via the production
chain, chat 200pongonbai/qwen3.8-flash, fail-closed 401;
model-entitlement map recorded (premium 403 deposit-gated, mid-tier
400 on zero balance — account state, not integration state). - FID-2026-0911-002 — rests at
fixed(vendor-held). OrcaRouter
integration is complete and probe-proven (catalog 195/195 via the
production chain, key authenticated, fail-closed verified); the HTTP-
200 completion is blocked by OrcaRouter's own account gate. The
op...
v0.0.30
0.0.30 — 2026-09-08
NDJSON handoff matrix executed live — 6/6, four transport defects fixed forward (closed + archived 2026-09-08)
- FID-2026-0907-007 — medium — the BO Phase 3 "Prove" gate executed: the
6-case handoff matrix ran against the actual CLI child and caught four
transport defects every in-process DI suite structurally could not see.
Determinism seam: a local fake OpenAI-compatible SSE gateway +
INFERENCE_BASE_URLdirect-mode routing + a bare-slug model preference in
a temp config dir. The four fix-forwards (the BO's explicit Phase 3
contract): (1) the dev boot banner polluted stdout in both modes
(common/src/env.tsconsole.log→console.error— stderr is the
diagnostics channel); (2) the default NDJSON frame writer omitted the
\ndelimiter, gluing consecutive frames onto one unparseable stdout
line (headless-run.ts— every DI suite injects a collector, so only the
real-process gate could catch it); (3) a mid-stream cancel rode the 90s
run timeout because a held LLM request yields NO stream boundaries →
cancel now aborts AT ARRIVAL (onCancelhook in
createControlFrameReader; run-side semantics extracted to the new
headless-control-plane.ts— 300-line ceiling); (4) the SDK's generic
"Run cancelled by user" masked the parent-authored reason →
PARENT_CANCEL_REASONis framed when this child consumed the cancel
frame. One test pin corrected to ground truth (v1 emitsanswer\n\n).
Matrix split per the 300-line ceiling:handoff-matrix-harness.ts(251)- cases 1-3 (
handoff-matrix.test.ts, 90) + cases 4-6
(handoff-matrix-part-b.test.ts, 91). Gates: matrix 6 pass / 0 fail
(25 expects, case 4 aborts in 6.4s); headless DI suites 56/0;
typecheck cli 0; eslint--max-warnings 0clean; prettier clean;
quality: PASS (1467)(honest bumpheadless-run.ts→ 297); receipt
3/3 PASS. Closed + archived 2026-09-08 (receipt re-stamped at the
archived path with all three gates re-run live). The cross-repo smoke
(real Savant parent → built CLI) carries OPEN as the operator-assisted
boundary — never claimed by the record.
- cases 1-3 (
code_search cap parameters + self-remedying truncation markers (closed + archived 2026-09-08)
- FID-2026-0908-003 — low —
code_searchgainsglobalMaxResults+
maxOutputStringLengthin the tool schema; truncation markers are now
self-remedying. The layered caps (per-filemaxResults15, global 250
results, 20,000-char output) were executor-internal — onlymaxResults
was schema-declared, and the run-layer wiring for the other two
(sdk/src/run/tool-call.ts:199-210) was dead: zod silently stripped the
keys, so a model believing it had raised a cap had not. Both caps are now
declared (optional ints, ceilings 5000 / 200000, executor-matching
defaults — default callers byte-identical), and every truncation marker
names the cap that fired with its value plus both remedies (narrow the
pattern/cwd/globs first; raise the named parameter). Surfaced live during
the 2026-09-08 A-Z audit when a Detective evidence sweep hit the 20K
output cap at 102 matches. RED-first suitecode-search-caps-markers.test.ts
(6 fail → 6/0); 37/0 across the five code-search suites (part-c's
marker-prefix pin intact); typecheck ×4 exit 0; receipt 3/3 PASS. Two
verify-step discoveries fixed en route: the example patterns were
de-tokenized (TODO|FIXMEtripped the production-placeholder scan —
re-patterned to'deprecated'/'deprecated|legacy'), and a malformed
parallel-sessionFID-2026-0908-002-usage-telemetry.mddraft was
quarantined todev/scratchpad/active/per the T20-F operator precedent.
Closed + archived 2026-09-08 (receipt re-stamped at the archived path
with all three gates re-run live).
skill_manage speaks the canonical command-result template (closed 2026-09-08)
- FID-2026-0908-001 — medium —
skill_manageoutput mapped onto the
canonical single-command template at the handler boundary. The handler
returned a bespoke{ok, error}/{ok, name, version, action, nextSha, pendingTrust}envelope while every command-class tool returns the
{stdout, stderr, exitCode}shape (run_readonly_commandis the
template). Fix:resultToValue(result, attemptedAction)maps success →
exitCode: 0+ human-readablestdoutsummary + identity fields, and
failure →exitCode: 1+ the exact engine error onstderr; the
ok/error/messagechannels are retired (exitCodeis the success
signal;messagefolds intostdout);outputValueSchema
(common/src/tools/params/tool/skill-manage.ts) declares the same shape
withexitCode: z.union([z.literal(0), z.literal(1)]). Engine +
SkillManageResultuntouched (three CLI script consumers unaffected).
RED-first suiteskill-manage.test.ts(4 pins; 4 fail pre-fix → 4/0,
22 expects); live probe PASS (real handler, temp root: create → exit 0
quarantined-pending-trust envelope, delete → exit 0, invalid name →
exit 1 +"invalid skill name: Invalid Name!"on stderr); independent
Verifier audit (2 FAIL + 4 NEEDS-REVIEW) fully discharged in Loop 3;
receipt 3/3 PASS re-stamped at the archived path. The operator-directed
48-tool handler-output sweep (same day) found this was the ONLY bespoke
envelope — nil divergence elsewhere; verdict recorded in the FID's
Lessons Learned. Closed + archived 2026-09-08; the active FID queue is
now empty.
NDJSON delegation transport (Phases 1-2) + provider surface hardening — 7 FIDs closed + archived (2026-09-08)
Operator closure directive ("properly update the changelog and move the completed fids to the
archive"): the six active fixed records closed + archived 2026-09-08 with receipts re-stamped
live at their archived paths (all gates re-run, 18:18–18:20Z). The active FID queue is now empty.
BO Phase B FIDs -006/-007 (stdin control reader, live handoff matrix) were never authored at
that pass — the trio's "archive after FID-007" sequencing pointed at a record that did not
exist, exposed during this session's ground-truth pass and recorded in each closure. Phase 2
(FID-006, stdin control reader) was then authored + implemented + closed the same day (below);
Phase 3 (the FID-007 live handoff matrix, SCOPE T21-E) was executed the same day — 6/6 live,
four transport defects fixed forward (top entry); the cross-repo smoke carries open as the
operator-assisted boundary.
- FID-2026-0907-003 — medium — NDJSON delegation frame module + argv-exact
--jsonactivation
(BO Phase B FID 1/5). New purecli/src/headless-ndjson.ts(294 lines):serializeFrame
(strict{v,type,ts,data}envelope in wire order, one JSON object per line),
createNdjsonEmitter(injectable writer, epoch-ms clock, step/duration counters, thinking
accumulation, unknown-kind no-op),parseControlFrame+createControlFrameReader(tolerant
control channel: cancel/steer parsed, unknown/v≠1/malformed skipped, EOF → end, never
blocks). Declared--jsonCommander option (argv-exact). Suite 18/0; receipt 2/2 PASS. - FID-2026-0907-004 — medium — handleEvent tap: progress frames from the headless event stream
(BO Phase B FID 2/5). Pureheadless-ndjson-tap.ts(97 lines) maps the five ratified kinds
fromPrintModeEvent(tool_call_started/completed;iteration_completedsynthesized per
tool_result;thinking_started/completedwith implicit-start + flush-before-next-event span
bookkeeping).runHeadlessPrintgainsjsonMode/jsonFrameWriter(DI per the headless
convention); the tap is created only in JSON mode, composing additively intohandleEvent
(error-event stderr logging preserved); the dispatch threads--jsonon the
--print/stdin/CI branch. Suites 40/0; receipt 4/4 PASS. - FID-2026-0907-005 — medium — artifact + error frames; stdout purity (BO Phase B FID 3/5).
Emitter hoisted above every exit boundary (usage and client-init failures frame too); exactly
oneartifactframe at the answer point carrying the exact--printanswer; error frames at
all four nonzero-exit boundaries plus mid-run error events (FID-004's recorded deferral
discharged); pureheadless-outcome.tsseam suppresses the raw stdout answer write in JSON
mode (the artifact frame owns the answer channel; stderr byte-identical in both modes).
Suites 50/0; receipt 5/5 PASS; honest baseline bumpheadless-run.ts284 → 296. - FID-2026-0907-006 — medium — stdin control-frame reader wiring (BO Phase 2 FID 4/5). The
FID-003 pure reader gains its first production caller: in JSON mode the reader attaches to
stdin (newjsonControlInputDI param; production bindsprocess.stdin) and drains at the
handleEventstep boundary BEFORE the tap —cancel→ cooperative abort (exit 1 via the
existing throw path + one rule-4 error frame; no frames after the ack, including
completion-race artifact suppression),steer→ accepted + parked (parkedSteerNoteson the
result + one stderr diagnostic), unknown/v≠1/malformed skipped by the parser, EOF harmless,
non-JSON never attaches (byte-identical v1). Ceiling-forced seam: the four answer helpers
moved verbatim toheadless-answer.ts(61 ln;extractFinalAnswerre-exported; headless-run
back to 294 ln via comment-only condensation — absolute ceilings take no baseline bumps).
RED-first suiteheadless-control.test.ts(5 pins; 2 pass/3 fail pre-wiring); 55/0 across
the five headless suites; receipt 5/5 PASS. Closed + archived same day; the live parent→child
round-trip carries as FID-007's Phase 3 cross-repo smoke — never claimed here. - FID-2026-0907-008 — low — APInex gateway provider (12th provider) — keyed live acceptance
PASSED 2026-09-08. Registry entry (apinex: gateway/openai/strip, authenticated live
cataloghttps://api.apinex.bond/v1/models,APINEX_API_KEY), thin Nous-shaped wrapper
(resolveKey+ single-prefix normalization over multi-sla...
v0.0.29
0.0.29 — 2026-09-06
Release delta since v0.0.28 (2026-09-02). Detailed per-FID entries follow
below in reverse-chronological order; the highlights:
-
Quality campaign to zero: all five residue source monoliths
decomposed (native.ts, gateway.ts, office-scene.tsx, public-release.ts,
plus the 811-path dirty-tree drain), 6 FIDs closed + archived, and
quality:reportreached 0 violations. -
Release pipeline durability + desktop integration:
git-bundle-backup.ts(FID-008) and two new pipeline stages —
BACKUP_BUNDLE(verified incremental bundle before any public artifact;
FID-009) andDESKTOP_BUNDLES/DESKTOP_RELEASE(desktop packaging as
pipeline stages with the fail-closed updater manifest;
FID-2026-0903-001), desktop gated onSAVANT_CODE_RELEASE_DESKTOP=1. -
Providers: KiosAPI and OpenCode Zen (four-protocol) added end-to-end
with live operator confirmation; recursive-schema sanitizer for strict
upstreams. -
Triggers (FID-2026-0824-005, opt-in
SAVANT_TRIGGERS=1): loopback
webhook receiver with bearer auth + replay/rate guards, fixed-template
directive injection (payloads are data, never prompts), dependency-free
cron scheduler with missed-run resume,triggers_*JSON-RPC management
surface, desktop TriggersPanel, and the relay guide (Tailscale Funnel /
cloudflared). En route: two gate-integrity bugs fixed (stdin-watchdog
truncating the pre-push suite; a leaked fetch mock faking later tests). -
Quality-ratchet file remediation (FID-2026-0819-005): live inventory
62 → 5 violations; 11 test monoliths decomposed at exact parity and the
two template type files split into re-export hubs — every test and type
file now under the 300-line ceiling. -
Roadmap: the Maus-parity suite dissolved by operator decision —
computer use, voice, mobile companion, and security keychain FIDs closed
out-of-scope with the master; the roadmap program is removed. -
Governance: G1/G6 amendment — agents permitted local commits + push;
public releases flow exclusively through this pipeline. -
FID-2026-0903-001 (fixed 2026-09-05) — desktop packaging integrated
into the automatic release pipeline:DESKTOP_BUNDLES(after
BACKUP_BUNDLE, beforeGITHUB_RELEASE) dispatches
desktop-release.ymlwith the cut's tag and watches the run fail-closed
(conclusion + HEAD-SHA binding to the release commit);DESKTOP_RELEASE
(after the npm publishes, beforePOST_RELEASE_VERIFY) locates the
successful run (re-derived from the Actions list, never persisted),
downloads artifacts, re-runs the fail-closedlatest.jsongenerator
locally, and attaches bundles + manifest viagh release upload --clobber. POST_RELEASE_VERIFY now asserts the updater manifest at the
per-release URL (the pinnedreleases/latestendpoint excludes
prereleases — its check stays with the operator's post-promotion smoke).
Gated onSAVANT_CODE_RELEASE_DESKTOP=1for the first integrated cut;
workflow amendment derives the bare version from the tag for the
generator (Loop 1 AUDIT V2). 18-test desktop suite; receipt stamped;
live validation on the next release cut. -
FID-2026-0905-009 (fixed 2026-09-05) —
BACKUP_BUNDLErelease stage
wired into the public-release pipeline betweenGIT_PUSHand
GITHUB_RELEASE: after the release commit is pushed, the pipeline writes
the verified incremental bundle (last-backup..main) to the
OneDrive-synced destination via the FID-008 backup core before the GitHub
release and npm publishes run — a backup failure aborts the release
(fail-closed; the marker never advances on an unverified bundle), and the
stage is resume-aware (a pre-009 receipt runs the backup for real rather
than retro-marking). Newscripts/public-release/backup-stage.ts(41
lines) + 6-test scratch-repo suite; 13fid:verifygate receipts PASS;
preview plan line added. Operator live smoke on the next release cut. -
FID-2026-0905-001/-004/-005/-007 (closed 2026-09-05) — the source-
monolith decomposition campaign completed; all five residue monoliths of
closed -0819-005 are gone andquality:reportsits at 0 violations:
tool-executor/native.ts894 → 249 facade + pipeline stages with
gate-order-pinning tests (24fae6f0);cli/src/server/gateway.ts
1,327 → 236 + 8gateway/stage modules behind a byte-identical facade
with per-session GatewayContext state and afid-eventsbus (7e4be78);
desktop office-scene.tsx2,126 → 179 + 14scene-*modules with
RED-first pure-logic extraction and a single-owner focus bus (3c737fb);
scripts/public-release.ts3,065 → 178 + 23 domain modules, the ~420-line
runReleaseTransactionrefactored into stage helpers with statement order
preserved and the export surface mechanically verified identical
(32255bb). Suite parity held at every step (1335/0, 35/0/163, 413/0/
5,718, 57/0/216 respectively);fid:verifyreceipts stamped for all. -
FID-2026-0905-006 (closed 2026-09-05) — provider-drift baseline
violations resolved: 10 over-ceiling test files split under 300 at exact
suite parity, theproviders.tsdata-constant exemption merged into the
existingdataConstantExemptionsblock (growth-frozen at 335), and the
env-sanitize lists in all three provider-setup test files now DERIVED
fromPROVIDER_SETUP_CONFIG+RESEARCH_KEY_SERVICESso the next
provider cannot re-create the KIOSAPI_API_KEY leak class (commits
98129016…7e4be78); also resolved R5 (bun:testimports in
model-config.test.ts). -
FID-2026-0905-008 (closed 2026-09-05) —
scripts/git-bundle-backup.ts:
the G5 backup durability layer replacing "push often" — baseline bundle
once, incrementals overlast-backup..main, verify-or-no-advance (the
last-backuptag moves only after the written bundle verifies),
idempotent no-op at marker==HEAD,SAVANT_BUNDLE_DIRfor the
OneDrive-synced destination; 7 scratch-repo tests (32255bb). -
Governance (2026-09-05) — operator amendment to the G1/G6 version-
control workflow recorded in ECHO.md and BO-2026-08-23: agents are
permitted local commits + push; public releases flow exclusively through
therelease:publicpipeline (local push + pipeline releases). -
FID-2026-0905-002 (closed 2026-09-05) — KiosAPI added as a first-class
provider (Path A registry entry + authenticated live model catalog in the
Nous pattern):kiosapi/<model>routes tohttps://kiosapi.com/v1with
KIOSAPI_API_KEY(Bearer,striptransform), key entry via.env.local
or/provider kiosapi, models surfaced in the/modelpicker via the
combined gateway catalog, missing-key errors fail closed naming the env
var. 4 new gateway tests (parser incl. GLM-5.3-free preservation,
combined-catalog inclusion, persisted-key refresh, failure isolation).
Closed on operator live confirmation ("kiosapi works"); static gates
green (common provider 24/0, gateway 16/0, sdk free-mode 4/0). -
FID-2026-0905-003 (closed 2026-09-05) — OpenCode Zen added end-to-end
under routing idopencode-zen: registry entry,ProviderProtocolunion
extension (responses,gemini,multi), 70-entry
OPENCODE_ZEN_PROTOCOLSmap + sharedPROVIDER_PROTOCOL_MAPSrecord,
Responses factory branch (@ai-sdk/openai@2.0.50) and Gemini branch
(@ai-sdk/google@2), public live catalog wired into the gateway picker,
keyOPENCODE_API_KEY(.env.localor/provider opencode-zen),
unknown models fail closed with a clear error. Includes the
operator-ordered credential merge: Go + Zen shareOPENCODE_API_KEYvia
theopencoderesolver chain (legacyOPENCODE_GO_API_KEYfallback).
6 SDK routing tests (all 4 protocols + key-required + fail-closed), 4
CLI catalog tests, map-structure coverage test. Closed on operator live
confirmation ("zen works", per-protocol paths + Gemini tolerance
included); static gates green. -
FID-2026-0905-004 (closed 2026-09-05) — Zen Responses-path runtime
rejection fixed (Upstream request failed: [invalid_request_error] Recursive JSON schemas are not currently supportedon
opencode-zen/muse-spark-1.3-contributor-free; chat-path models were
immune). Root cause: five tools (gravity_index,render_ui,
set_output,spawn_agents,spawn_agent_inline) serialize to
genuinely recursive$defsschemas, and SDK-native branches sent them
raw. Fix: shared outbound cycle-cut (schema-sanitize.ts) applied as
fetch middleware to the anthropic/responses/gemini factory branches;
chat path byte-identical. Verified: 9 sanitizer unit + 4 branch
round-trip tests, full static gates, and operator live confirmation
("it works"). Closed by explicit operator ship directive;fid:verify
receipt unstamped (pre-existingmodel-config.test.tsred tree). -
FID-2026-0819-005 (fixed) — quality-ratchet file-remediation program
completed (operator-held → closed 2026-09-05): live inventory driven from 62
violations to 5 — every test file and every type-definition file in the
repo is now under the 300-line ceiling. Final phase (Loops 348–358): 11
test monoliths decomposed at exact test/assert parity (savant-code-api,
sqlite-adapter, error-handling, init-direnv, loop-agent-steps part-a,
skill-management, llm chat-language-model, use-usage-query,
loop-agent-steps part-f rebalance, openai-compatible chat-model), and the
two template type files split into re-export hubs (agent-definition.ts →
agent-definition-support.ts + agent-models.ts; tools.ts →
tool-params-core/-discovery/-research) with zero import-surface change —
24 consumers verified, including theinit.tsraw-text scaffold, which
now copies all 8.agents/typesfiles via the new
init-type-files.tsinventory module. One downstream contract fix:
publish.ts bridges its API cast throughunknownbecause named
intersection aliases lack TypeScript's implicit index signature. -
**F...
v0.0.28
0.0.28 — 2026-09-02
Release delta since v0.0.27 (2026-08-21). Detailed per-FID entries follow below in
reverse-chronological order; the highlights:
- Compaction integrity rebuild — master FID-2026-0824-022 + children -023…-027
(visibility/transparency layer, preservation contract + digest schema,
minimal-surgery algorithm, evidence spill + requiresRawEvidence splice,
removed-content ledger + metrics + model notice) all implemented and closed
2026-08-24. - Eval system rebuild v3 — master FID-2026-0824-013 + children -014…-019 (FSM
alignment, sandbox hardening, skill-efficacy engine, governance corpus + bounded
autorater + Tier-1 pre-push smoke, erosion regression guard, capability ingestion- Tier-3 release pipeline) closed 2026-08-25.
- Desktop chat surface + Auto Drive dashboard — FID-2026-0820-010 closed
2026-08-25 (structured no-terminal chat, dashboard projection, Emergency Halt,
parent graph); workspace regions FID-2026-0824-009 closed 2026-08-25. - Compaction summary output — FID-2026-0828-001:
/compact(and auto-compaction)
now emit the pruner's summary of the window as a first-class transcript entry
rendered through TrafficLightPanel, and the terminal-state mirror race that dropped
theprunedphase + summary report on compact-and-stop runs is fixed. Summary is
recovered from the pruner's compacted history (the pruner is a programmatic agent
that never streams text) and stripped of<structured_state>framing tags; the
block renders collapsed-by-default with easy expand/collapse and a whole-block copy
button. Live/compactverified by the operator 2026-08-28. - Nous free-model 400 "missing tags" fix — the Nous inference API requires a
tags: ['user=…']body from raw-key (Bearer) callers; without it every
nous/…(and bare-slugDIRECT_PROVIDER=nous) request was rejected400 missing tags. Fixed by injecting the required tag on both routing paths, single shared
constant. - Sidebar context readout fix — FID-2026-0827-001:
CONTEXT_TOKEN_SMALL_COUNT_FLOOR
small-count exact adoption indampTokenCount("context stuck at 0/x"). - Enforcement-layer + Recorder closures — FID-2026-0823-011 (accepted with waiver),
FID-2026-0824-001/-010 (live-evidence discharge), deck visual trio (waiver). - Model migration — stealth/ox-alpha → z-ai/glm-5.3-flash (API-valid; prod config
updated). - Repo hygiene — tree-drain migration drained the 644-path backlog into 27
path-scoped atomic commits under the G1–G9 git-workflow adoption; protocol bundle
regenerated; all gate surfaces green at release. - Discord Rich Presence refinements — presence enabled by default, client id
hardcoded to the Savant Discord application (feature-theft guard), three-line
activity layout (project / model / action), provider-trimmed model labels
(nous/meituan/longcat-2.0:free→longcat-2.0),openrouter/freerendered
as "OpenRouter Free". Operator live-confirmed.
2026-09-02 — Release-ready audit: deck rebuild closed, desktop CLI-parity program closed, sidecar env fix closed (7 FIDs archived)
The 2026-08-29…09-02 sessions rebuilt the desktop command deck and closed the
desktop parity program. All seven FIDs are archived with re-stamped gate
receipts; the repo-wide validate:repository FID-ledger issues went 40 → 0.
- Deck rebuild: neon-noir agent office (R3F) — FID-2026-0831-001 +
FID-2026-0831-002 closed:@react-three/fiberoffice replacing the stage
renderer — 10-agent robot cast with per-role accents and glowing rims,
walk-to-station on live tool calls, obstacle-aware routing, activity
beacons + ThinkingDots/SparkBurst, speech bubbles from the driver text
snapshot, day/night cycle, break furniture, click-to-focus + follow-cam,
real Savant emblem. Floor suites 178/0 across the passes; live smoke
discharged by the operator across five native sessions. - Desktop CLI-parity program — FID-2026-0901-006 closed after 36 passes:
timestamps under messages, model display + real context window (no more
hardcoded x/200k), markdown chat bubbles with traffic-light headers,
"Savant roster" rename, FID queue initial-sync fix (connectOnceboot-path
idempotence + hello-time inventory push, panel went 0 → 27 open),
deck mini-chat island with semi-transparent backdrop,dev/scratchpad
auto-management (hygiene guard + README contract). - Sidecar env + SDK client init — FID-2026-0901-001 closed: the Tauri
supervisor now forwardsNEXT_PUBLIC_*+ inference keys to the sidecar
child process, fixing the desktop boot crash-loop and chat send failures. - Deck live fidelity + visual activity — FID-2026-0828-002 (defect B:
emissive/body-base/palette trio) and FID-2026-0829-001 (six activity
layers + lane-alignment fix) closed; their remaining surfaces were
superseded by the 0831 rebuild. - Ledger hygiene — forbidden
**Author:**attribution fields removed
(FID-2026-0824-028/-030), archived FID-2026-0822-013 superseded steps given
explicitdeferred::operator-approvedmarkers, stale gate receipts
re-stamped PASS viabun run fid:verify … --write.
2026-08-28 — Compaction summary: history recovery + collapsed transcript block, and Nous free-model tags fix (fixed, live confirmed)
Two session fixes landed while soft-testing the /compact summary output
(FID-2026-0828-001) and the v0.0.28 release live run:
- Compaction summary actually renders now. The original capture primitive
(prunerSummaryBuffer, FID-2026-0824-023) only fills fromonResponseChunk
STRING chunks, but the context-pruner is a PROGRAMMATIC (handleSteps) agent
that never streams text — so the buffer was always empty in production and the
emission gate never fired (/compactproduced literally zero output, operator
live test). Fix: recover the summary from the compacted history's
<conversation_summary>→<historical_memory>→<compaction-summary>memory
message the pruner always writes (extractPrunerSummaryFromHistory,
spawn-agent-inline.ts), stripping the<structured_state>/</structured_state>
framing wire tags so the block shows clean readable text. The streamed buffer
stays only as a defensive fallback. - Block polish (operator-directed). The summary transcript entry now renders
COLLAPSED BY DEFAULT — header (✓ Compaction summary — removed N messages · −X tokens · Y% of window) + first line only, so/compactreads as a one-line
confirmation instead of a multi-row wall; a clickable▾ expand/▴ collapse
header plus a dedicated▴ collapsebutton under the expanded content make the
fold round-trip easy; and the whole block carries the shared⎘copy button
(copies the header + full summary).CompactionSummaryContentBlockgained an
id+isCollapsed/userOpenedso the standard block-toggle handler
(updateMessageCollapse) expands/contracts it. - Nous free-model
tagsfix. Messagingnous/tencent/hy3:freereturned
400 This request is not valid… missing tags: the Nous inference API requires a
tagsarray with auser=…entry from raw-key (Bearer) callers (undocumented in
its OpenAPI because the supported path is OAuth). Added anextraBodyseam to the
OpenAI-compatible chat model and settags: ['user=savant-code']for the Nous
provider on BOTH routing paths (prefixednous/…viacreateProviderModeland
bare-slug viacreateDefaultInferenceModel), mirrored from a single shared
constant. Operator-verified live 2026-08-28.
Gates: typecheck common/agent-runtime/cli exit 0; compaction suites (agent-runtime
9/0 incl. programmatic-pruner recovery + <structured_state> strip; cli 15/0 incl.
collapsed/expand/copy block + id-toggle); Nous SDK suite 15/0 incl. the tags body
assertions; eslint --max-warnings 0; prettier clean; fid:verify --check sweep PASS.
2026-08-27 — FID-2026-0827-001: sidebar context readout stall near zero fixed (closed + archived)
Operator-reported "context seems stuck at 0/x" during a live 2026-08-27 session — the
sidebar Tokens used/max readout showed used = 0 while the denominator resolved to the
real ~1M window. Root cause: dampTokenCount (display-only damper from FID-2026-0821-003-A)
applies a ±5% relative deadband + 12% max-step ramp against the currently displayed
value, so a small early-session count against a large window ramps imperceptibly from ~0.
Fix: NEW CONTEXT_TOKEN_SMALL_COUNT_FLOOR = 10_000 in
cli/src/state/chat-store/compaction-helpers.ts — any count at or below the floor (incl.
any transition out of zero) is adopted exactly; deadband/ramp unchanged above the floor.
2 regression tests in chat-store-noop-guards.test.ts (small-count exact adoption;
below-floor replacement). Gates: cli typecheck exit 0 · suite 12 pass / 0 fail (15 expect
calls) · eslint/prettier/markdownlint clean · Verifier audit PASS 4/4 with evidence
(guard fixes the reported stall, tests fail pre-fix, receipt ↔ reality match, metadata
consistent) · two cosmetic observations recorded, no action needed. Receipt re-stamped at
the archived path sha256:787cb606...2402 (2/2 declared gates live PASS); repo-wide
fid:verify --check sweep PASS. Live visual-meter confirmation recorded as the
operator's boundary, resolved by directive — never claimed passed. Closed + archived to
dev/fids/archive/ 2026-08-27.
2026-08-26 — FID-2026-0823-011 Recorder stall closed fixed-with-waiver (closed + archived)
The Recorder read-then-stop behavioral boundary is PERMANENTLY ACCEPTED by operator waiver. Evidence state at close: three controlled live probes (UPDATE stalled twice in bounded ~26-30K contexts even with the Turn Contract and the corrective retry suffix naming the exact failure; CREATE shape with immediate-write instruction succeeded once), plus real-world recurrences during 08-24/25 work — establishing that prompt-level levers cannot reliably make this model execute an UPDATE-shaped wri...
v0.0.27
0.0.27 — 2026-08-21
Checkpoint release: quality-ratchet decompositions, documentation sync,
and harness fixes.
- Quality-ratchet remediation: decomposed 169 files over the 300-line
ceiling into focused modules while preserving all public surfaces, test
coverage, and type safety. Net reduction: ~30k deletions across cli,
common, packages, and sdk workspaces. - Documentation sync: README.md (added 3 missing workspaces),
CONTRIBUTING.md (updated typecheck/test references), agents/README.md
(added Adversary), packages/knowledge-graph/README.md and
packages/design-systems/README.md (created), common/README.md and
savant-free/README.md (updated references), docs/sdk-overview.md
(fixed stale import count). - Harness fixes: all 7 pre-push gates pass (typecheck ×11, test suite,
ESLint, lint:md, Prettier, credential scan, protocol bundle).
2026-08-20 — FID-2026-0820-016: Programmatic gate blocks silently drop results — orphaned tool-calls and evidence-free NO-OUTPUT (closed)
Root-caused and fixed the FID-2026-0820-013 Round 3 output-injection open item:
when any execution gate blocks a programmatic (handleSteps-generator) tool
call — FSM phase gate, sandbox policy, EHEL, hooks, ZTAP, spawn validation —
the executor returned early without creating a tool result, leaving an
orphaned tool-call in history, delivering nothing to the generator, and
hiding the block reason from the model entirely.
- Live-confirmed root cause (basher artifact probes): under the default
'prompt'permission mode,run_terminal_commandreturns a prompt
decision thatcheckSandboxPolicydowngrades to deny (no subagent
approval channel — documented Phase-1 limitation), so the basher's command
never executes in any FSM phase; RED/idle-phase spawns are additionally
hard-blocked by the FSM gate. - Fix (single boundary, Law 13):
executeSingleToolCall
(execute-tool-calls.ts) now captures gate error chunks and synthesizes the
blocking tool result —{ blocked: true, reason }with the shared
pre-execution toolCallId — completing the call/result pair in history and
returning the reason to the generator, which reports it honestly instead
of NO-OUTPUT. Scoped to the gate-block signature; result-less tools
(end_turn, set_output) are byte-identical. - Q8 verified: the EHEL verification tracker (echo-record.ts +
enforcement.ts afterToolCall) credits from the INPUT at post-gate call
sites — blocked calls never reach either credit point; the synthesized
history-only result cannot corrupt the dirty/verified ledger.
Gates: agent-runtime typecheck exit 0; focused suite 2 pass / 0 fail; full
agent-runtime suite 1130 pass / 0 fail / 2988 expect() across 129 files;
ESLint 0 warnings; Prettier clean; lint:md clean. Perfection Loop complete:
RED (live probe matrix) → GREEN (Thinker, 6 thoughts, 2 material
refinements) → AUDIT (Verifier PASS, 2 NEEDS-REVIEW resolved at source) →
ADVERSARIAL (CLEAN, 11/11 gate-site emission matrix verified). Live-behavior
check (basher reporting the sandbox block reason instead of NO-OUTPUT)
awaits the next session relaunch (process-lifetime module caching).
Closed + archived 2026-08-20.
2026-08-20 — FID-2026-0820-015: Subagent spawn reliability cluster — basher silent no-execution fabrication, scout reasoning-400, conversion-crash evidence (closed)
Three live subagent-spawn defects reproduced and fixed in one session:
- BASHER-1 (critical): the basher agent never executed its
commandparam yet reported
success — its summarization prompt asserted the output was already in context, so the model
fabricated plausible output (reproduced 2/2, including a false "Exit status: 0" on a
never-run command chain). Fixed inagents/basher.ts: the generator now verifies a
delivered tool result ('json' | 'media') before the summarization STEP and returns an
explicit no-output error otherwise; the prompt premise is conditional with the honest
NO-OUTPUT: result not deliveredescape hatch. - SCOUT-1 (high): scout spawns failed with HTTP 400 "Reasoning is mandatory for this
endpoint and cannot be disabled." —agents/scout/scout.tshardcoded
reasoningOptions: { enabled: false }against the inherited reasoning-mandatory model.
Removed; the runtime default applies. - CONV-1 (high, evidence only): 5 crashes of
convertCbToModelMessages
(common/src/util/messages/aggregate.ts:86→sdk/src/impl/llm/stream.ts:99) recorded —
every history-inheriting agent spawn (Recorder/Verifier/Adversary) crashed on
object-valued tool results whileincludeMessageHistory: falseagents spawned cleanly.
Owned by FID-2026-0820-013's in-tree fix; root-cause correlation documented for its
relaunch check. Multi-agent spawn schema cleared of suspicion (caller-side malformed
params, correctly caught).
Gates: agents typecheck exit 0; agents suite 84 pass / 0 fail; ESLint 0 warnings; prettier
clean; markdownlint clean; bundled agents regenerated via prebuild (grep-verified in
02-basher.ts / 33-scout.ts). AUDIT tool-mediated (Verifier/Adversary spawns unavailable —
themselves CONV-1 reproductions #4/#5, recorded in the FID). Live behavioral verification
deferred to relaunch from the working tree (same stale-binary caveat as
FID-2026-0820-012/-013/-014). Closed + archived 2026-08-20.
2026-08-20 — FID-2026-0820-014: EHEL enforcement cluster — stale turn-end latch, apply_patch gate bypass, readonly verification credit (closed)
Three sibling defects around the FID-2026-0820-012 Law-3 deadlock family, all fixed and audited:
- EC-1 (critical):
post-write-scanners.tsgated strict-mode Law 15 on the stale
hasVerifiedSinceLastDirtylatch (set false by every write, cleared only by
resetForNewTurn— which never runs while the scanner blocks), so a fully verified
strict-mode turn could never end. Now uses the cumulativedirtyFiles-minus-
verifiedFilespredicate — one source of truth with the pre-write Law 3 gate and
evaluateTurnEnd. - EC-2 (high):
pre-write-gates.tsgetTargetPathignoredinput.operation.path,
so everyapply_patchcall bypassed the Law 1/Law 7 gates and the FID
Recorder/anti-deferral checks. Now resolvesoperation.pathand the FID gate reads
operation.diff; the new-file exemption and exempt-path carve-out apply to the
resolved target. - EC-3 (high): the compliance tracker credited verification only from
run_terminal_command;run_readonly_commandverification (the safer channel) never
reached it, producing false Law 3 steering. Both channels now credit.
Tests: 10 new/updated regression tests (post-write-scanners.test.ts,
pre-write-gates-apply-patch.test.ts new, echo-record.test.ts new). Gates: agent-runtime
typecheck exit 0, focused 34/0, full suite 1128/0, ESLint 0 warnings, prettier clean,
lint:md clean. Verifier PASS + Adversary CLEAN (prettier FAIL refuted by tool output).
Live-behavior check deferred to relaunch from the working tree (stale binary — same
caveat as FID-2026-0820-012/-013).