Skip to content

Releases: savant0x/savant-code

v0.0.36

Choose a tag to compare

@savant0x savant0x released this 19 Oct 07:47

0.0.36 — 2026-10-12

v0.0.36 — development line, package release not yet published.
Verified source progress is committed and pushed to main automatically;
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 with React.Children.toArray
    before flattening, so static Button/CommandPalette and FollowupLine
    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 patched braces@3.0.3 finding 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, and SCOPE.md was reconciled with the closed children.
    The 0.0.36 heading moved above its own recent entries as a byte-identical
    relocation, so extractChangelogSection no 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 its YYYY-MM/ bucket —
    canonical YYYY-MM-DD-* names and the pre-convention YYYY-MMDD-* shape
    alike, and dated logs/screenshots with them — without renaming or rewriting
    one byte. Planning is pure, so --check and --dry-run report 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:repository PASS (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 —...

Read more

v0.0.35

Choose a tag to compare

@savant0x savant0x released this 11 Oct 21:18

0.0.35 — 2026-10-01

v0.0.35 — OpenAI as a first-class platform provider: a platform sk- key
(/provider openai) routes openai/<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 /provider picker finally
sorts alphabetically. The connector layer lands: the monid port ships as
packages/connectors and 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 commit f6c2048d).
    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/models measured 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-spark family, every -fast variant) 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's label
    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_NAMES is 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 commit 8d915d8f).
    Added the authenticated
    catalog, dedicated max_context_length parser, 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 commit c89de4ae).
    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 commit 512659cc).
    Metadata-only law
    events carry resolved route/session/role identity into rolling 7d/30d/all
    aggregates. The existing /telemetry command 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-k3 had 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
    grows fetch(, 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 as bun 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 end inconclusive, so
    one probe never decides; absent token usage is no-signal rather 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-url to 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,c sweep every
    catalog route and report each separately — a route being down is never the
    provider being down (HCNSec served glm-5.3-flash with 200 while kimi-k3
    returned 500 in the same minute), with the served model label 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 as matched.
    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
    observed glm-5.3-flash -> longcat-2.5-preview-free substitution needs its own
    record.

  • The sidebar reports provider cache reuse truthfully (FID-2026-1007-009, medium;
    closed 2026-10-07; local commits 8c528f12 + 07fbbbd9; register item T164).

    Cache reuse was invisible in the CLI, and three layers had each destroyed the fact
    the row needs: emitCacheDebugUsage coerced an absent cache field to 0,
    isCachedTokenCountKnown then treated every 0 as unknown, and the only cache
    monitor was constructed per step and fed only under CACHE_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 reports cachedInputTokensReported, the R3 seam
    lets presence win while the legacy > 0 heuristic stands unchanged for records
    without the flag, and a new pure accumulator folds every completed usage into
    agentState.cacheUsage from the always-on onUsage callback. 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-present Cache row that keeps three meaningfully
    different states apart — — when nothing usable was observed, Not reported when
    the provider omitted the field, and 0% for a reported cache miss — with the toke...

Read more

v0.0.34

Choose a tag to compare

@savant0x savant0x released this 29 Sep 01:43

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...

Read more

v0.0.33

Choose a tag to compare

@savant0x savant0x released this 22 Sep 18:22

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 / Interrupt split on who ended the turn
    (finished on its own terms vs cancelled; a failure fires neither, and both are
    main-agent only — children report via SubagentStop). PreCompact is the
    compaction attempt (the pruner spawn) and PostCompact only fires on the
    runtime's existing pruned predicate, so a compaction that removed nothing
    cannot claim the context was compacted — the unmatched PreCompact is the
    signal. Notification is the runtime handing control to the operator (an
    ask_user call), 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 the Notification
    call site and deleting the Stop call 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), the Source
    section — which named a parser function in a file that does not contain it and
    three wiring files that fire nothing — the missing action config row, and the
    previously unstated behaviour of matcher on 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
    hardcoded tool_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

  • PreToolUse could 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) sent session_id + cwd + tool_name + tool_input only, so the natural
    policies were inexpressible: "deny writes unless the caller is forge" 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/SessionEnd were outcome-blind. SessionEnd fires in a
    finally with identity only, so a clean end and a crash were indistinguishable
    at the hook — the SubagentStop defect one boundary up. The outcome is now
    computed on every path (return, error-form return, thrown) and reported, with
    SessionStart deliberately outcome-free. Both lifecycles share ONE builder
    (hooks/run-outcome.ts; hooks/subagent-outcome.ts re-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, Interrupt and Notification are in the
    config vocabulary (so they parse and load) and were documented in
    docs/design/hook-system.md as 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 by scripts/hook-events-check.ts, which also fails if this repo's own
    protocol.config.yaml declares 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/Interrupt are documented as the same
    thing; Notification has 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, mainPrompt for 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), fingerprint sha256: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 / SubagentStop fired 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 fields PostToolUse /
    PostToolUseFailure use); executeSubagent, the single funnel both spawn paths
    share, never set them. hooks/subagent-outcome.ts now builds the payload and
    every terminal branch sets it — including the catch, 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. SubagentStart is pinned to stay outcome-free.
  • SessionState and ProjectFileContext now have enumerated boundary
    contracts.
    FID-2026-0919-028 made AgentState self-enforcing at the spawn
    boundary and recorded this as the natural extension. Both types have a boundary:
    cloneSessionState deep-copies mainAgentState (JSON round-trip, for
    byte-parity with the persisted snapshot) and shares fileContext by 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.ts classifies every key once,
    AssertNever gates make an unclassified field a build failure, and each
    exemption carries the reason it is safe. gitChanges is 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 assign fileContext.*: a new unclassified writer fails a test.
    scripts/handoff-transport-check.ts now asks all three boundary questions
    (child, snapshot, run start) reading the shipped lists.
  • 15 new pins (7 hook-outcome through the real handleSpawnAgents →
    executeSubagent boundary, 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 the toolResult argument → 3 pins red; a field injected
    into each type → error TS2344 at its gate; a new run-start writer → census
    unclassified; a writer on a carried field and a copied fileContext → 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.
    createAgentState inherited a hand-written list of
    parent fields, so the next field added to AgentState would 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
    AgentState keys is now classified exactly once in spawn-child-fields.ts:
    13 inherited, 14 child-owned, and 27 deliberately absent with a
    stated reason
    each (groundingCheckpoint, maxContextLength/digestCaps
    because `createLoopC...
Read more

v0.0.32

Choose a tag to compare

@savant0x savant0x released this 18 Sep 19: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: runWithConcurrency worker
    pool with PROBE_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.ts under 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 --probe harvest
    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. Commit 69f6e7a7. 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-unverifiable hosts 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 stamps withProbeAttempt() so failed measurements don't re-fire
    early.
  • State layer: optional lastProbeAttemptUtc on CandidateState with
    defensive parse — plus an explicit carry-forward line in diffCandidates,
    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. Commit 69f6e7a7. Closed +
    archived 2026-09-18.

/model picker now activates the selected provider's routing (FID-2026-0917-005)

  • Selecting a model in the /model picker persisted the model's provider to
    settings.json but never activated it in the runtime environment.
    process.env.DIRECT_PROVIDER and process.env.INFERENCE_BASE_URL stayed
    empty, so isDirectProviderMode() 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
    to getWebsiteUrl() (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 called activateConfiguredProvider.
  • 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 via activateConfiguredProvider, the same guarded seam the
    /provider picker uses). handleModelPickerSelect is 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
    explicit INFERENCE_BASE_URL untouched — 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. Commits 91daaf93 (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 to OPENROUTER_API_KEY.
    When that fallback held a stale or revoked key, the CLI silently sent a
    dead credential and the operator saw the vendor 401 User 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/keys exchange is now terminal: it
    negative-caches (cachedKey = null) and returns undefined instead of
    substituting a different credential for the one the operator configured.
    Because openrouter is a registered kind: 'gateway' provider
    (common/src/providers/registry.ts:23-25), getModelForRequest's
    active-provider guard throws the templated missing-key error before
    createDefaultInferenceModel is 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 undefined preserves the existing string | undefined contract
    — 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:md exit 0; independent Verifier
    AUDIT — 4 PASS / 1 FAIL refuted with registry evidence (the flagged
    ?? apiKey fallback is unreachable on the live DIRECT_PROVIDER=openrouter
    path because the gateway guard throws first). Shipped to the rebuilt
    sdk/dist the 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 at load-dev-env.ts:5-6. With
    cwd=cli/, Bun pre-seeded process.env.OR_MASTER_KEY from the stale
    cli/.env.local before load-dev-env.ts ran; 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-file added to the dev script
    (cli/package.json:17) so load-dev-env.ts is the sole deterministic
    loader; the false comment replaced with the real mechanism; the divergent
    stale OR_MASTER_KEY removed from cli/.env.local (gitignored — a
    local-machine fix). The stale OPENROUTER_API_KEY was 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 exact str_replace that would have fixed the violation — because a
    markdown doc (dev/handoff.md) sat in dirtyFiles with a failing
    markdownlint (MD040) run keeping it out of verifiedFiles. 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 *.md as docs and evaluateWritesAtStepBoundary
    already declares "documentation artifacts gate on markdownlint, never on
    Law 3" — but the pre-write gate checked only the isExemptWritePath prefix
    list (dev/fids/, dev/nova/, dev/scratchpad/), omitting docs/,
    dev/handoff.md, dev/session-summaries/, and README.md.
  • One-predicate fix reusing the existing classifier (Law 13 — one function,
    one truth): unverifiedDirty now filters to classifyFileKind(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-wide lint:md at exit 1, so no
    doc coul...
Read more

v0.0.31

Choose a tag to compare

@savant0x savant0x released this 13 Sep 21:30

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 root bunfig.toml preload 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_DIR override, so CLI provider tests read and wrote
    the real ~/.savant-code/ directory: two v0.0.31 release attempts failed
    the repository-validation gate deterministically, and the operator's
    real credentials.json was overwritten with test fakes.
  • Recovery: all gateway keys restored from the live shell environment;
    the polluted file preserved as credentials.json.polluted-by-release-gates.bak.
  • Fix (three layers): the root preload (sdk/test/setup-env.ts) demotes
    an inherited prod to the test runtime (explicit per-test values still
    win); fid-gate children spawn with NODE_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:repository PASS.

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; dataConstantExemptions growth-freeze,
    exemption guards, and approvedGrowth rejection 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
    commit 5e8cd5c8).
    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.ts module (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:check exit 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
    commit a6853358).

    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 via model-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's tool-call branch
    now classifies invalid === true parts through the single
    normalizeNativeToolCallStreamError factory 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's baselineSha (-001,
    commit d95502f); the destructive 30-day draft purge is replaced by
    a monotonic archive move with ARCHIVED.json provenance (-002,
    commit f83ea32); 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, commit c36db40); and a
    cold-spawned scribe-proposer drafts 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, commit 3921356). 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 /health live line — one verify helper
    behind three surfaces. Committed 8984711; 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 one BAI_API_KEY,
    authenticated live catalog via the resolveKey pattern,
    uniform-prefix parser pins. Committed 2e58cf06. Keyed acceptance
    PASSED with the operator's key: catalog 47/47 via the production
    chain, chat 200 pong on bai/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...
Read more

v0.0.30

Choose a tag to compare

@savant0x savant0x released this 09 Sep 07:03

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_URL direct-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.ts console.log → console.error — stderr is the
    diagnostics channel); (2) the default NDJSON frame writer omitted the
    \n delimiter, 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 (onCancel hook 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_REASON is framed when this child consumed the cancel
    frame. One test pin corrected to ground truth (v1 emits answer\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 0 clean; prettier clean;
      quality: PASS (1467) (honest bump headless-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.

code_search cap parameters + self-remedying truncation markers (closed + archived 2026-09-08)

  • FID-2026-0908-003 — low — code_search gains globalMaxResults +
    maxOutputStringLength in the tool schema; truncation markers are now
    self-remedying.
    The layered caps (per-file maxResults 15, global 250
    results, 20,000-char output) were executor-internal — only maxResults
    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 suite code-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|FIXME tripped the production-placeholder scan —
    re-patterned to 'deprecated' / 'deprecated|legacy'), and a malformed
    parallel-session FID-2026-0908-002-usage-telemetry.md draft was
    quarantined to dev/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_manage output 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_command is the
    template). Fix: resultToValue(result, attemptedAction) maps success →
    exitCode: 0 + human-readable stdout summary + identity fields, and
    failure → exitCode: 1 + the exact engine error on stderr; the
    ok/error/message channels are retired (exitCode is the success
    signal; message folds into stdout); outputValueSchema
    (common/src/tools/params/tool/skill-manage.ts) declares the same shape
    with exitCode: z.union([z.literal(0), z.literal(1)]). Engine +
    SkillManageResult untouched (three CLI script consumers unaffected).
    RED-first suite skill-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 --json activation
    (BO Phase B FID 1/5).
    New pure cli/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 --json Commander 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).
    Pure headless-ndjson-tap.ts (97 lines) maps the five ratified kinds
    from PrintModeEvent (tool_call_started/completed; iteration_completed synthesized per
    tool_result; thinking_started/completed with implicit-start + flush-before-next-event span
    bookkeeping). runHeadlessPrint gains jsonMode/jsonFrameWriter (DI per the headless
    convention); the tap is created only in JSON mode, composing additively into handleEvent
    (error-event stderr logging preserved); the dispatch threads --json on 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
    one artifact frame at the answer point carrying the exact --print answer; error frames at
    all four nonzero-exit boundaries plus mid-run error events (FID-004's recorded deferral
    discharged); pure headless-outcome.ts seam 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 bump headless-run.ts 284 → 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 (new jsonControlInput DI param; production binds process.stdin) and drains at the
    handleEvent step 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 (parkedSteerNotes on 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 to headless-answer.ts (61 ln; extractFinalAnswer re-exported; headless-run
    back to 294 ln via comment-only condensation — absolute ceilings take no baseline bumps).
    RED-first suite headless-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
    catalog https://api.apinex.bond/v1/models, APINEX_API_KEY), thin Nous-shaped wrapper
    (resolveKey + single-prefix normalization over multi-sla...
Read more

v0.0.29

Choose a tag to compare

@savant0x savant0x released this 06 Sep 05:21

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:report reached 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) and DESKTOP_BUNDLES/DESKTOP_RELEASE (desktop packaging as
    pipeline stages with the fail-closed updater manifest;
    FID-2026-0903-001), desktop gated on SAVANT_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, before GITHUB_RELEASE) dispatches
    desktop-release.yml with the cut's tag and watches the run fail-closed
    (conclusion + HEAD-SHA binding to the release commit); DESKTOP_RELEASE
    (after the npm publishes, before POST_RELEASE_VERIFY) locates the
    successful run (re-derived from the Actions list, never persisted),
    downloads artifacts, re-runs the fail-closed latest.json generator
    locally, and attaches bundles + manifest via gh release upload --clobber. POST_RELEASE_VERIFY now asserts the updater manifest at the
    per-release URL (the pinned releases/latest endpoint excludes
    prereleases — its check stays with the operator's post-promotion smoke).
    Gated on SAVANT_CODE_RELEASE_DESKTOP=1 for 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_BUNDLE release stage
    wired into the public-release pipeline between GIT_PUSH and
    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). New scripts/public-release/backup-stage.ts (41
    lines) + 6-test scratch-repo suite; 13 fid:verify gate 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 and quality:report sits at 0 violations:
    tool-executor/native.ts 894 → 249 facade + pipeline stages with
    gate-order-pinning tests (24fae6f0); cli/src/server/gateway.ts
    1,327 → 236 + 8 gateway/ stage modules behind a byte-identical facade
    with per-session GatewayContext state and a fid-events bus (7e4be78);
    desktop office-scene.tsx 2,126 → 179 + 14 scene-* modules with
    RED-first pure-logic extraction and a single-owner focus bus (3c737fb);
    scripts/public-release.ts 3,065 → 178 + 23 domain modules, the ~420-line
    runReleaseTransaction refactored 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:verify receipts 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, the providers.ts data-constant exemption merged into the
    existing dataConstantExemptions block (growth-frozen at 335), and the
    env-sanitize lists in all three provider-setup test files now DERIVED
    from PROVIDER_SETUP_CONFIG + RESEARCH_KEY_SERVICES so the next
    provider cannot re-create the KIOSAPI_API_KEY leak class (commits
    98129016…7e4be78); also resolved R5 (bun:test imports 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 over last-backup..main, verify-or-no-advance (the
    last-backup tag moves only after the written bundle verifies),
    idempotent no-op at marker==HEAD, SAVANT_BUNDLE_DIR for 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
    the release:public pipeline (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 to https://kiosapi.com/v1 with
    KIOSAPI_API_KEY (Bearer, strip transform), key entry via .env.local
    or /provider kiosapi, models surfaced in the /model picker 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 id opencode-zen: registry entry, ProviderProtocol union
    extension (responses, gemini, multi), 70-entry
    OPENCODE_ZEN_PROTOCOLS map + shared PROVIDER_PROTOCOL_MAPS record,
    Responses factory branch (@ai-sdk/openai@2.0.50) and Gemini branch
    (@ai-sdk/google@2), public live catalog wired into the gateway picker,
    key OPENCODE_API_KEY (.env.local or /provider opencode-zen),
    unknown models fail closed with a clear error. Includes the
    operator-ordered credential merge: Go + Zen share OPENCODE_API_KEY via
    the opencode resolver chain (legacy OPENCODE_GO_API_KEY fallback).
    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 supported on
    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 $defs schemas, 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-existing model-config.test.ts red 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 the init.ts raw-text scaffold, which
    now copies all 8 .agents/types files via the new
    init-type-files.ts inventory module. One downstream contract fix:
    publish.ts bridges its API cast through unknown because named
    intersection aliases lack TypeScript's implicit index signature.

  • **F...

Read more

v0.0.28

Choose a tag to compare

@savant0x savant0x released this 03 Sep 02:20

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
    the pruned phase + 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 /compact verified 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-slug DIRECT_PROVIDER=nous) request was rejected 400 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 in dampTokenCount ("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/free rendered
    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/fiber office 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 (connectOnce boot-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 forwards NEXT_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
    explicit deferred::operator-approved markers, stale gate receipts
    re-stamped PASS via bun 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 from onResponseChunk
    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 (/compact produced 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 /compact reads as a one-line
    confirmation instead of a multi-row wall; a clickable ▾ expand/▴ collapse
    header plus a dedicated ▴ collapse button under the expanded content make the
    fold round-trip easy; and the whole block carries the shared ⎘ copy button
    (copies the header + full summary). CompactionSummaryContentBlock gained an
    id + isCollapsed/userOpened so the standard block-toggle handler
    (updateMessageCollapse) expands/contracts it.
  • Nous free-model tags fix. Messaging nous/tencent/hy3:free returned
    400 This request is not valid… missing tags: the Nous inference API requires a
    tags array with a user=… entry from raw-key (Bearer) callers (undocumented in
    its OpenAPI because the supported path is OAuth). Added an extraBody seam to the
    OpenAI-compatible chat model and set tags: ['user=savant-code'] for the Nous
    provider on BOTH routing paths (prefixed nous/… via createProviderModel and
    bare-slug via createDefaultInferenceModel), 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...

Read more

v0.0.27

Choose a tag to compare

@savant0x savant0x released this 21 Aug 20:11

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_command returns a prompt
    decision that checkSandboxPolicy downgrades 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 command param 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 in agents/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 delivered escape hatch.
  • SCOUT-1 (high): scout spawns failed with HTTP 400 "Reasoning is mandatory for this
    endpoint and cannot be disabled." — agents/scout/scout.ts hardcoded
    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 while includeMessageHistory: false agents 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.ts gated strict-mode Law 15 on the stale
    hasVerifiedSinceLastDirty latch (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 cumulative dirtyFiles-minus-
    verifiedFiles predicate — one source of truth with the pre-write Law 3 gate and
    evaluateTurnEnd.
  • EC-2 (high): pre-write-gates.ts getTargetPath ignored input.operation.path,
    so every apply_patch call bypassed the Law 1/Law 7 gates and the FID
    Recorder/anti-deferral checks. Now resolves operation.path and 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_command verification (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).