Skip to content

v0.0.35

Choose a tag to compare

@savant0x savant0x released this 11 Oct 21:18
· 357 commits to main since this release

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 token
    sample beside any percentage and the rejected-sample count visible. No pricing claim
    is made. Two corrections are recorded in the record itself: its declared
    typecheck root gate is not in the permitted vocabulary and became four workspace
    typechecks, and adding an AgentState field tripped the exhaustive classification
    gate in spawn-child-fields.ts, so cacheUsage is declared
    not-inherited-by-design like lastProviderUsage. Receipt 9/9 live at the archived
    path.

  • Every repository gate is now declarable on a FID (FID-2026-1007-003, medium;
    closed 2026-10-07; local commit 0620e143).
    The FID gate executor admits
    four shapes — typecheck <workspace>, test <path>, probe <path>,
    quality — so a gate that is a binary (eslint, prettier), a
    package-manager invocation, a build, or a script that only checks under a flag
    had no declaration in that vocabulary, and a record whose subject was that
    gate could not declare the check that proved it (T154 was the worked example,
    treated as a one-off until this pass enumerated the rest). One shared probe
    body (scripts/probe-runner.ts: argv arrays only, never shell text, spawned
    through process.execPath so a bare runtime name cannot ENOENT through the
    Windows PATH, env inherited so a probe behaves identically under fid:verify
    and by hand) now backs sixteen thin gate probes, and
    scripts/gate-declarability.ts audits all 29 repository gates against the
    real allowlist (resolveGate), failing validate:repository when a
    contract gate has no audited entry, when a declaration the executor rejects is
    tabled, or when a gate is left undeclarable with no stated and permitted
    reason — only repository-validation (C3 recursion) and credential-scan
    (scoped to a pushed commit range) qualify. The injected-budget guard added to
    the same validator ships with its own probe
    (scripts/test-budget-injection-check.ts). The workstream was found complete
    and green but unregistered in the working tree and is registered as SCOPE.md
    item T158; 19 tests pass across its two pin files, scripts typecheck and
    quality exit 0, validate:repository clean.

  • Module-scope test state is isolated, and the class is enumerated rather than
    inferred (FID-2026-1007-002, medium; closed 2026-10-07; local commit
    5299af25).
    bun test loads every file of a workspace into ONE process, so
    a module-scope Map/Set/array/let that accumulates is state every suite
    inherits and a suite's verdict depends on file order — the class behind
    FID-2026-1007-001's 76 failures. A new mechanical audit
    (scripts/audit-module-state.ts over a scan/analyze/wiring/exemptions split,
    probe scripts/module-state-check.ts) enumerated it: 144 bindings across 98
    files
    with no way back to their start state, and six workspaces with no
    test preload at all
    (Bun does not walk up for [test] preload — measured,
    not assumed). All 144 are cured — 96 new reset*/clear* seams, 9
    weak-container declaration flips, no reset performing I/O — across 121 files
    and ten preload surfaces, and the audit now reports 182 of 187 resettable
    bindings wired, with the remaining five in two modules carrying reasons it
    enforces in both directions (an unreached module with no reason fails; a
    reason that no longer describes anything fails too). Wiring exposed two real
    regressions, both repaired at the boundary the failure named: an in-memory
    database's connection IS the database, so its caches reset at the FILE
    boundary (afterAll), and resetting the CLI theme store broke 122 component
    tests that depended on the leak — the store is now reset AND re-initialized
    per case, so a case starts from an initialized default instead of inheriting
    whatever an earlier file left behind. The suite's first scanner was also wrong
    in both directions (a reset*-only matcher, and a blind spot for a
    declaration wrapped across lines); it was validated against fixtures before its
    output was acted on.

  • The agent-runtime suite is green, and removing the noise unmasked three
    production defects (FID-2026-1007-001, medium; closed 2026-10-07; local commit
    228156da).
    The suite was red with 76 failures across four unrelated
    families (run-agent-step, web_search, read-docs, hook-event) and they
    were ONE cause: providerBreakers
    (src/provider-boundary/provider-circuit-breaker.ts) is a process-lifetime
    Map with no reset, every test file shares the single bun test process, and
    the fixtures reuse the literal clientSessionId: 'test-session' — so three
    transient failures (PROVIDER_BREAKER_MAX_FAILURES = 3) left the circuit OPEN
    on legacy:test-session for the rest of the run. A second registry of the same
    class (DEFAULT_SEEN_SHAPES in classified-stream-retry.ts) was the last
    order-dependent failure. The repair is test-boundary only (two exported resets
    called from a bunfig.toml preload, documented as test-only, plus a dedicated
    isolation suite), and removing that noise unmasked three production
    behaviour defects
    it had been hiding, each fixed at its own seam and pinned:
    abort detection did not read through an error's cause chain; the loop's
    fallback message named the wrapper instead of the provider's own error; and a
    guard newer than the operator-mandated AUTONOMY CARVE-OUT
    (run-agent-step/post-terminal-breaker.ts) auto-ended autonomous runs on a
    repeated step shape.

  • Adoption wiring: every delivered module now has a production caller
    (FID-2026-1006-003, high; closed 2026-10-06; local commits through
    6d5fbe48).
    All six surfaces FID-2026-1006-002 left library-complete are
    wired: the compaction cut plan is computed at every step boundary
    (planCompactionCut — never at a tool result, split turns merge) and
    travels as a spawn param to the serialized context pruner, which honors
    cutWindowStart; the cumulative file ledger folds across successive
    compactions behind a watermark and merges into the pruner's preserved file
    state; the loop guard rails gate every step iteration (named stop reason on
    AgentState.loopStopReason; stale-cycle, per-role-budget and iteration-cap
    rails; single-task checklist injection); validatePreset runs at config
    parse against the new orchestration: declaration in protocol.config.yaml
    and error-severity issues fail the gate; the session entry writers run on
    the CLI save path (model_change plus thinking_level_change when the
    effective reasoning level changes, steering-override custom entries,
    idempotent compaction label) and a resumed chat loads only in-context rows
    via getInContextMessages; a chat switch that aborts a mid-turn run renders
    and persists a branch summary. Six wiring suites assert the caller, 19/19
    declared gates pass with receipt
    sha256:ae0aacee30e602dbad18345c40dcb911fd83585b2d7082dbaf3b7593a168d330;
    root typecheck, eslint --max-warnings 0, lint:md, quality:report, and
    validate:repository all exit 0.

  • Pi-harness adoption program (FID-2026-1006-002, high; closed 2026-10-06; local commit 81733c16).
    Twelve adopted work packages from T149's deep pi-harness review, all implemented and
    gate-verified: deterministic steering rules with an audited override; a durable-race catalog
    with instrumented-storage test tiers and a write-order conformance check; tool-outcome
    durability; the atomic transition rule plus a per-path file-mutation queue and a serialized
    database mutation line; compaction cut points (never at a tool result, over-budget turns split
    into two summaries that merge) with cumulative file tracking across successive compactions;
    branch summarization; loop guard rails (stale-cycle detection, per-role activation budget,
    single-task injection) with preset validation; pure decision functions with an injected clock;
    project-trust gating with closest-parent-wins inheritance and a veto-only ProjectTrust hook
    event; the adaptive publisher; session entry classes (custom vs custom_message, label
    bookmarks, model_change/thinking_level_change audit entries, excludeFromContext); and
    marker-based prompt isolation in evals. 22/22 declared gates pass (5 workspace typechecks +
    16 named test gates + quality), receipt
    sha256:b1a3f13c7fa33e485ca6bbffeb366226be2a1a3470d06341651d87c95b50a8c0; root typecheck across
    13 workspaces, eslint --max-warnings 0, lint:md and validate:repository all exit 0.
    Three modules (compaction cut points/file tracking, loop guard rails, session entry classes)
    are library-complete with no production call path yet — recorded as a stated limitation.

  • Zero-intervention provider catalog visibility (FID-2026-1006-001, high; closed 2026-10-06).
    The /model list now shows every authenticated live provider automatically, with
    no operator step. One registry-driven resolver (resolveProviderApiKey: env →
    stored /provider key → undefined) feeds all 8 live catalog wrappers, so a stored
    key reaches the catalog fetch; the gateway warm start is coverage-validated, so a
    stale snapshot missing a keyed provider self-heals (cooldown-gated, no-key never a
    gap); window-coverage:check fails loud on register drift with an atomic --fix;
    and providers:parity regenerates the committed census from the live catalog
    assembly, so a future provider is auto-reconciled with no manual census edit. The
    three originally-stale register entries (codecraft/cleanapis/xkiro) were corrected
    by the mechanism itself. 31 tests across 5 suites; 9/9 declared gates pass
    (typecheck cli/common, five suites, the live fan-out probe, quality).

  • Savant Code landing page (T145; committed 2026-10-06, cef88023). Added the standalone website/index.html project root with product overview, ECHO workflow, provider showcase, installation instructions, and responsive interactive presentation.

  • Three-tier skill evaluation gates (FID-2026-1005-005; closed 2026-10-06, commit e229d9a). Added structural, trigger-routing, and behavioral evaluation for all 11 trusted skills; paired proof trials use constrained temp-workspace tools, description-hash trust checks, and a durable rejection impact ledger. Declared FID gates pass; live token-costed trials remain operator-invoked.

  • Provider failure classification and circuit breaker (FID-2026-1005-006; closed 2026-10-06, commit e229d9a). Provider failures are classified before retry decisions; load-time retry policy validation and a per-provider closed/open/half-open breaker bound recovery probes. Five declared gates pass.

  • Bounded stream recovery (FID-2026-1005-007; closed 2026-10-06, commit e229d9a). Added one checkpoint-seeded, tools-disabled recovery request for eligible truncated reasoning turns, with physical-request accounting and hard bounds. Four declared gates pass.

  • Provider availability verdicts and quota states (FID-2026-1005-008; closed 2026-10-06, commit e229d9a). Distinguishes provider availability verdicts from gateway faults and model eligibility; quota truth uses explicit states and evidence-based notification transitions. Ten declared gates pass.

  • Evidence-classed provider facts and documentation drift gate (FID-2026-1005-009; closed 2026-10-06, commit e229d9a). Registry facts carry evidence class, source, and verification date; registry validation detects unsupported fact changes and a recompute gate catches numeric documentation drift. Seven declared gates pass.

  • ChatAnywhere free-key provider (FID-2026-1005-010; closed 2026-10-06, commit e229d9a). Added the ChatAnywhere provider catalog, documented provider surfaces, and model-picker free-key section with a reusable free-model marker. Live /v1/models and gpt-5.6-sol probe succeeded; declared gates pass.

  • Evidence-based skill learning: single proposal path, durable
    lifecycle events, content-bound proof labels (FID-2026-1005-003, high;
    closed 2026-10-05).
    The self-improving harness's six gaps are closed.
    Recurrence gates on DISTINCT sessions (computeRecurrences now reports
    distinctSessions; three retries in one session never draft). The
    mechanical draft's generic template is deleted — candidates reserve a
    proposal slot mechanically (prepareCandidateHandoff, idempotent by
    content sha, fail-closed on a second proposal per session) and the draft
    body IS the lesson's canonical rule. Every skill mutation emits a
    metadata-only lifecycle event (.savant/skill-lifecycle-events.jsonl)
    consumed by the CLI traffic-light surface, /skills activity, and the
    session-end report, with per-surface cursors that acknowledge only after
    transcript insertion (at-least-once crash replay; green ≠ trusted — the
    notice always reads QUARANTINED — PENDING TRUST · unproven).
    /skills show <name> --review exposes the exact quarantined bytes: draft
    sha, full SKILL.md, diff vs live, proposal evidence. Proof artifacts gain
    skill_content_sha256 + a multi-task fixture manifest;
    PROVEN ON N TASKS requires a current hash, activation, lift, and zero
    regressions — legacy/single-task artifacts stay UNPROVEN. Root typecheck
    exit 0; scripts 49/0, common 11/0, cli 16/0, evals 20/0 focused tests;
    quality PASS; lint:md clean. Live capture-to-trust exercise recorded
    NEEDS-REVIEW (operator TUI session).

  • Right sidebar keyboard access + measured render-path optimization
    (FID-2026-1005-002, medium; closed 2026-10-05).
    The sidebar audit's five
    findings are fixed. Keyboard: section headers and FID-card rows toggle on
    Enter/Space and a new Ctrl+G focus cycle (input unfocused/empty, same guard
    as Ctrl+B) rotates focus through them — OpenTUI 0.5.3 has no Tab traversal,
    so the sidebar provides the parent control; a focused title inverts as the
    compact indicator (right-sidebar-focus.ts, pure + unit-tested). Width:
    the compact rail now serves every terminal below 100 columns (native
    captures showed the 40-column sidebar leaving ~20 columns for chat at 60).
    Reachability: every active FID renders in the scrollable section and is
    individually expandable — the passive "+N more active" label and its
    MAX_VISIBLE_FIDS cap are gone. Text: the Auto Drive goal renders full
    and word-wrapped (60-char slice removed). Refresh cost: archived FIDs are
    counted from directory entries (countArchivedFids, ~0.31 ms) instead of
    parsing all 455 archived files (~54.65 ms); loadFidInventory keeps its
    full contract, the watcher keeps the count fresh. cli typecheck exit 0,
    focused suites 22/22, eslint 0, quality PASS. Live TUI verification of the
    focus traversal + theme contrast recorded NEEDS-REVIEW (no
    core-linux-x64 OpenTUI binary for the WSL capture boot).

  • Inter-agent message integrity + final-result reconciliation
    (FID-2026-1005-001, high; closed 2026-10-05).
    The incident behind the FID
    (an Adversary verdict that looked truncated) decomposed into three
    independently pinned boundaries. Runtime batch relay: a new
    byte-equality boundary probe (subagent-boundary.test.ts) drives a long
    marker-delimited last_message result through handleSpawnAgents and
    proves the selected text survives jsonToolResult unsliced, scratch-turn
    history never leaks. CLI display: spawn-results.ts no longer drops the
    final result when any text streamed — byte-equal keeps the stream, a true
    prefix gets the missing suffix appended, divergence shows the
    authoritative final text beside the preview (pins in
    sdk-event-handlers-final-result.test.ts). Output limits: a
    finishReason === 'length' cut with no tool call now yields an explicit
    Output limit reached: … partial fragment, not a complete answer. chunk
    (stream-output-limit.ts + stream.ts) instead of presenting a
    fragment as a verdict. Full typecheck chain exit 0, quality PASS (1498
    files), focused suites 46 pass / 0 fail, eslint 0 on all touched files.

  • Launch free-provider digest + candidate inbox routing
    (FID-2026-1004-007, low; closed 2026-10-05).
    The free-compute discovery
    pipeline's report now reaches the user at launch: a once-per-day digest
    rewires the previously orphaned renderFreeOptionsAnnounce with the
    expiring offers and the discovery delta (silent when both sources are
    empty), and NEW discovery candidates route into /notifications as
    candidate-kind notices (changed is excluded — probe jitter marks ~34
    hosts changed every run). A new event-driven completion watcher
    (discovery-completion-watcher.ts, the fid-watcher.ts pattern) closes
    the timing gap the audit found: the detached boot harvest can publish
    agent-context.txt after the chat-mount effects run, and the watcher
    routes its new hosts on the artifact's set-key transition — no polling, the
    spawn contract untouched, idempotent downstream via the coordinator's
    fact-value dedup. 25/25 focused tests (8 new watcher legs), cli + common
    typecheck exit 0, eslint 0, quality PASS.

  • Authoritative provider runbook + archived-runbook drift repair
    (FID-2026-1004-005, low; closed 2026-10-05).
    docs/adding-a-provider.md
    is the new authoritative, live provider-integration runbook (490 lines),
    grounded in the enforcing modules and covering the four fail-closed gates
    the archived design doc omits: the WINDOW_COVERAGE_REGISTER
    closed-world invariant, the requiredExceptionKinds derivation table +
    exception-manifest ownership, the gateway.ts positional settled-ladder
    contract, and validateProviderUrlOwnership. The archived
    docs/archive/design/Adding New Providers.md was repaired for four
    measured drifts (stale acme fixture pointer, the omitted quota
    field, the header-vs-Step-3 protocol-map contradiction) and now carries a
    SUPERSEDED banner routing readers to the live runbook, which is linked from
    docs/index.md and docs/providers.md. Docs-only change set.

  • Provider registry reference (FID-2026-1005-004, low; closed 2026-10-05).
    docs/providers.md now carries a generated 24-row registry table (label, id,
    kind, credential, API root, protocol, catalog source) between markers, rendered
    from PROVIDER_REGISTRY by a 4th byte-exact generator surface. The pin suite
    asserts every registry dimension per row against registry values, and
    generate:provider-docs:check fails closed on drift. The file previously
    documented 4 of 24 providers with no drift guard.

  • Intern InkStone (FID-2026-1004-008, low; closed 2026-10-05). The
    Shanghai AI Laboratory science-discovery platform behind
    discovery.intern-ai.org.cn (书生·端砚) joins the registry as built-in
    provider intern — a static 10-model, single-protocol OpenAI gateway at
    https://discovery-api.intern-ai.org.cn/v1 with INTERN_API_KEY. It is the
    China-hosted twin of the already-shipped atria entry, with a 10-model
    roster instead of one. The live probe decided the design: the endpoint is
    reachable (1.8 s keyless) and its model-list route is auth-gated (401
    keyless, 200 with a key, 10 rows), but it publishes context windows in a
    non-OpenRouter schema_version: "2.4" shape
    (input_modalities[].supported_inputs.max_context_length.value) that no
    existing parser reads — so the operator chose a static catalog over a
    bespoke live parser. The probe also caught a real cross-deployment
    divergence: Atria-Dawn-Preview is 524,288 here against the twin's pinned
    262,144. All 10 exact-id windows are pinned from the authenticated probe, and
    inference was verified separately with a real chat/completions round-trip
    (HTTP 200). The entry derives zero exception kinds, so no manifest entry
    is required — adding one would fail closed as a stale kind. 7 new pin legs
    plus the two registry-count pins and the provider-list label pin; typecheck
    ×4 exit 0, common providers 78/78, CLI catalog + pin suites 102/102,
    docs-drift clean, eslint 0, lint:md 0, prettier clean.

  • Harness self-diagnosis integrity (FID-2026-1004-006, high; closed
    2026-10-04, commit 8ef81dd).
    Three defects in the harness's own error
    surfaces, all one shape — a failure reported with a confident, specific
    cause that is wrong. code_search now stats the resolved search directory
    before spawning: a file-path or non-existent cwd fails naming the
    searched path, instead of surfacing as an ENOENT against the vendored
    ripgrep binary and prescribing fetch-ripgrep (measured: a file cwd and
    a non-existent one produce byte-identical uv_spawn errors naming the
    executable); the re-fetch remedy survives only where the binary is
    genuinely absent. The Law 2 scope gate's loadScopeArtifact accumulates
    an item's backticked globs across indented continuation lines (stopping at
    the next item, a blank line, or non-indented text), so the register covers
    its own wrapped entries — T119/T132-class targets no longer sit on lines
    the parser silently dropped; stray prose still contributes nothing
    (fail-closed). The register's open-items count was brought back into
    agreement with its body. The AUDIT-citation gate (step 5) remains blocked
    on the operator ruling that the Verifier agent is not negotiable;
    re-designed plans must keep the role intact. Receipt 6/6 declared gates;
    sdk 589/0; agent-runtime 1,651/0; close-payload/escalating-kill extracted
    verbatim under the 300-line quality ceiling.

  • NEEDS-REVIEW provenance upgrade (FID-2026-1004-004, medium; closed
    2026-10-04).
    One keyless OpenRouter public-catalog cross-vote (466 rows)
    upgraded 27 of the sweep's 28 NEEDS-REVIEW provenance flags to two-source
    consensus (24 agree, 3 conservative-minimum holds), corrected one row DOWN
    (apinex/free/deepseek-v4-flash-0731 1,310,720 → 1,048,576 — over-claim
    removed by 2-of-2), and retained exactly one flag (bai/gemini-3-flash — no
    OpenRouter listing). The mechanical flag-floor pin was re-derived 15 → 4
    with the upgrade evidence cited in the FID and the survivors enumerated in
    the test.

  • Window-census follow-ups (FID-2026-1004-003, medium; closed 2026-10-04).
    The 66 runtime-catalog rows advertising exactly 200000 are classified via
    OpenRouter cross-vote: 50 REAL (claude-haiku-4.5, opus-4.1/4.5, sonnet-4,
    the o-series), 3 consistent with already-flagged table defaults, 7
    LEAK-PROBABLE (the GLM-4.x/5 family under-states 204800/202752 as 200000 —
    catalog-owned ~2% under-window, registered with a re-census trigger rather
    than inert fallback rows), 6 UNDETERMINED (dated NEEDS-REVIEW notes). All
    five zero-row registry providers diagnosed — none dead: cloudflare
    static+account-scoped, ollama local by design (daemon up), codecraft and
    cleanapis auth-gated 401, and xkiro LIVE KEYLESS again (129 rows with
    context_length; the T119-era 403 lifted — rows self-populate on the next
    catalog rebuild via the already-wired fetcher).

  • Gateway context-window coverage sweep (FID-2026-1004-002, high; closed
    2026-10-04).
    264 of 1,843 runtime-catalog ids resolved to the silent 200k
    context-window default: apinex and bai publish no window fields at all (their
    whole rosters), the coverage gate only pinned the catalogs earlier FIDs
    touched, and the audit's "166 non-chat" bucket hid chat flagships
    (orcarouter/openai/gpt-5.5 ran against a 200k denominator with a 1M+ true
    window — the FID-2026-1003-008 RequestInputBudgetError class). Fix
    (operator-ruled sourcing, cross-gateway rows only): 88 consensus-sourced
    rows (apinex 32, bai 41, orcarouter 6, nvidia 9) in two seam-split section
    files plus parent-table additions under the 300-line ceiling; ~150 remaining
    silent ids documented in grouped no-row registers; a
    WINDOW_COVERAGE_REGISTER disposition for every one of the 23 registry
    providers with a fail-closed lint suite (a new provider without a
    disposition fails the build); the LIVE verify-window-truth probe extended to
    census the no-publish gateways' rosters (LIVE 2026-10-04: apinex 34/34, bai
    59/59 registered). Receipt 12/12 gates; full cli battery 3,868 pass / 0
    fail; sdk 586 / 0.

  • Discovery daily cycle rebuilt to spec (FID-2026-1004-001, high; closed
    2026-10-04).
    The T111–T127 batch orphaned the discovery boot-check when
    it moved the announce builder into shared code, leaving the pipeline
    manual-only — report 2 days stale, custats 6 days, with no error anywhere.
    The CLI boot now spawns the freeairouter harvest and (operator ruling)
    the custats leg in the background whenever their artifacts are >24h old
    (repo-gated, free-build exempt, fail-silent, each leg independent), and
    the sanitized announce surfaces once per candidate set as a system
    message. A reachability census pins the call sites so a future refactor
    fails a test instead of silently killing the cycle again.

  • Pending operator decisions are surfaced mechanically (FID-2026-1003-007,
    high; closed 2026-10-03).
    Register items blocked on an operator ruling sat
    with a **Blocker:** sentence that nothing ever presented, so the backlog
    was found by hand and ruled on in one sitting. The session-end review now
    parses the register's own convention and surfaces every blocked item in
    dev/agenda.md (boot-read at intake) plus PRESENT: routing notes; a
    clean register stays silent, and the agenda's 50-line bound is now enforced
    mechanically. A blocker must be declared by a line-leading **Blocker:**
    on the item's own line — the first live run caught the mechanism surfacing
    its own item, whose prose quotes the convention, and that is pinned.

  • CodeCraft API and xKiro providers (FID-2026-1003-001, medium; closed 2026-10-03).
    Both support masked /provider setup, live catalogs, and exact upstream IDs.
    xKiro uses the shared protocol resolver: Anthropic-prefixed models route to
    Messages; other xKiro models use chat. Catalog growth is covered by explicit
    prefix rules. Registry, SDK, CLI fanout/reset, exception owners, and generated
    provider references agree. See provider and model reference.

  • Gateway reconnect event replay (FID-2026-1003-002, low; closed 2026-10-03).
    Every gateway event frame flows through one seq-stamped emission primitive
    with a bounded 1,000-batch replay buffer, so batches flushed during a
    disconnect are no longer dropped. A reconnecting desktop client recovers the
    window in order through the additive replay_events {since} method, the
    additive hello eventSeq, and the 'replay_events' capability, feeding
    recovered batches through the existing onEvents seam; unrecoverable gaps
    surface via onReplayGap. Live wire format, envelope, error codes, and
    GATEWAY_PROTOCOL_VERSION are unchanged (drift-guarded).

  • Durable provider notifications (FID-2026-1003-006, high; closed 2026-10-03).
    Provider changes reach users instead of vanishing: a durable notification
    service with a CLI inbox coordinator and capability-negotiated desktop
    provider_notice frames (provider_notices_v1), semantic model
    added/removed/changed deltas, dated health/removal notices with eligible
    429 fallback hints, and capability-based quota windows with dated offer
    expiry.

  • Provider probe-stage keys documented (T146, 2026-10-06; commit d8e655af).
    The Geaix and Excelnt probe-stage credentials are recorded by name in
    .env.example, and a dated probe report landed at
    dev/session-summaries/2026-10-06-geaix-excelnt-probe.md, so the next
    discovery pass starts from recorded key names instead of re-deriving them.

Changed

  • Sidebar and icon work cancelled by operator (FID-2026-1009-004, FID-2026-1009-007, FID-2026-1009-008, FID-2026-1010-003, FID-2026-1010-005; archived-declined 2026-10-11). Five FIDs are out of the active queue. Earlier implementation and test records remain historical; no product acceptance is claimed.

  • Cyberdeck icon family integration (FID-2026-1009-004, medium; operator-declined and archived 2026-10-11). The operator cancelled this integration because the TUI cannot use SVGs; implementation history is retained without an acceptance claim.

  • Sidebar cyberdeck HUD modernization (FID-2026-1009-008, medium; operator-declined and archived 2026-10-11). The loop-8 findings for the sidebar HUD redesign are retained as historical evidence; the operator later cancelled the sidebar work.

  • Sidebar duplication audit and phase colour restoration (FID-2026-1009-007, medium; operator-declined and archived 2026-10-11). The fixed area above Activity detail repeated the same live facts. Removed the duplicate blocks, made Activity detail the single home for status, and restored per-phase colour on the phase line through the theme.

  • Sidebar operator polish: wordmark headroom, grouped token counts, dropped .0k, and the kiosapi step-5-preview window (FID-2026-1010-003, low; operator-declined and archived 2026-10-11). Operator feedback on the live sidebar after the FID-2026-1009-008 cyberdeck integration. Four items, three of them cosmetic and one substantive:

    1. Wordmark headroom — the Savant wordmark started on the sidebar's very first row with no separation from the top border; the only vertical reserve in SidebarHeader sat below the mark (the documented fold-button reserve). One empty row now precedes it, with that reserve preserved.
    2. Grouped token counts — the Cache row printed its sample ungrouped (85% (1923.8k/2265.5k)) while the Context row directly beneath printed the same numbers grouped (1,923,800/2,265,500). Two rows of one panel disagreed about how to read digits. formatTokens now groups via Intl.NumberFormat('en-US'), the convention right-sidebar-display.ts already used, so both rows derive from one truth.
    3. Dropped .0k — toFixed(1) always emitted one decimal, so exact thousands read 1.0k, 2.0k, 1000.0k. maximumFractionDigits: 1 drops the trailing zero while keeping 1,923.8k intact.
    4. kiosapi step-5-preview window (200k → 1M) — a second operator report arrived mid-pass: the model resolved to the conservative 200k default because neither it nor its -free variant had a row in KIOSAPI_CONTEXT_WINDOW_FALLBACKS, the same defect class as the already-recorded qwen3.8-flash-free row. A 5x undersize steers compaction with the wrong denominator. Both ids now resolve to 1,000,000, sourced from the live OpenRouter read for upstream stepfun/step-5-preview (context_length: 1000000, top_provider agrees). The operator also noted the model is multimodal — that capability is live-derived from the cached catalog (architecture.modality → model-info.ts), so no static registration was required.

    The fourth complaint ("stretched vertically") was measured before being changed: rendering Branding at forced parent heights 3/6/10 produced byte-identical frames (the <ascii-font> element never stretches to fill), and a whole-font-table measurement showed tiny is the only 2-row font in the bundle. Operator ruling: keep the wordmark as-is. Verification: typecheck common + cli exit 0; eslint 0/0; prettier clean; 17/17 sidebar format+cache, 29/29 window suites, 6/6 kiosapi window pins, 3/3 sidebar frame suites.

  • The repo-wide Prettier drift is closed — the declared format gate is green
    end-to-end (SCOPE item T179, low; completed 2026-10-09; operator ruling
    recorded verbatim in SCOPE.md).
    bunx prettier --check . — declared LIVE in
    protocol.config.yaml with "active target 0.0.23" — had failed on 159
    committed files since before v0.0.23 (project version 0.0.35): 132
    art/icons/cyberpunk/*.svg opening-tag wraps plus 27 non-SVG line-length and
    final-newline drifts. Ten files were fixed by hand in-pass (the in-flight
    work's own files, the DSML pair, two final newlines, and two
    .prettierignore exclusions following the file's own generated-artifact
    patterns); the operator then explicitly lifted the no-scripted-edits
    invariant for the project's own formatter — "you can run the fix command
    this one time since i knw the reasons to allow it. Proceed with the fix"
    —
    and the remaining 149 files were migrated with prettier --write .. The
    codegen was re-run afterwards so both generated icon modules stay in sync
    with the reformatted SVG sources (single source of truth; the modules grew
    3,407 → 6,343 and 2,961 → 5,897 lines and the quality baseline was
    re-frozen with the rationale recorded in-line), and the two export tests
    that pinned the old single-line SVG opening tag now assert the family's
    64×64 canvas instead of the tag's whitespace. Verification after the
    migration: prettier --check . exit 0; typecheck across all 13 workspaces
    exit 0; full batteries cli 4,099 / common 837 / sdk 606 / agent-runtime
    1,971 / llm-providers 89 / desktop 403 — all pass, zero failures; eslint
    0/0; markdownlint, quality (1,503 baselined files), icon-palette,
    provider-docs drift, scope-register, learnings and validate:repository
    all PASS; every active FID's receipt re-verified live by fid:verify --check.

  • Sidebar command console polished (FID-2026-1008-006, medium;
    closed and archived 2026-10-09; local commit 2b6075e7).
    Clearer activity/model
    hierarchy, quieter sections, descriptive FID rows and restrained motion.
    Preserves the centered S logo and raised collapse/expand controls; folded
    navigation is centered with more brand spacing. Centered version sits above
    bottom context, which survives collapse/re-expand. F6 navigation preserves
    input and leaves Ctrl+G available to the host. Native UI battery: 84 pass,
    38 revised captures, minimum measured ordinary-text contrast 5.38:1.

  • Build-order register cleaned; five terminal records archived, four live
    orders' status corrected against the working tree (2026-10-07).
    dev/build-orders/
    held nine records with no index, no stated lifecycle, and no SCOPE.md
    registration, so delivered work was indistinguishable from open work. Five
    terminal records moved to dev/build-orders/archive/: the EHEL
    verification-state order (resolved, shipped in cruder form and since
    superseded), the anti-deferral gate order (superseded by archived
    FID-2026-0817-005, whose successor scope-disposition-guard.ts ships), the
    NDJSON Phase B emitter, the gate-chain hardening program (FIDs -0909-001..003
    archived), and the pre-push rewrite (fixture now scans clean). The NDJSON order
    had claimed status: planning and a "child emitter ABSENT" state for work that
    shipped as five closed FIDs (2026-0907-003..007); both were corrected before
    archiving. Four stay live with status restated against code:
    BO-2026-08-23 (Phase 0 + FIDs 1-3 shipped; FID 4's G2 hash audit and G5
    bundle check unbuilt), BO-2026-08-24 (0/7), BO-2026-09-08 (0/7), and the
    BO-2026-09-16 Atria handoff (feature shipped; P1's other-dirty Law 3 block
    and P5's missing green → complete FSM edge both still reproducible). A new
    dev/build-orders/README.md states the lifecycle and records that a build
    order is a proposal, not approved scope. Three references to moved paths were
    repaired in the same pass — cli/src/headless-ndjson.ts:4 (comment only, no
    behavior change) and the dev/fids/README.md link — with
    scripts/tree-drain-manifest/ updated because the drain tool is fail-closed on
    unmatched paths: dev/build-orders is now covered as a directory (the three
    exact-path entries were replaced, which also removed the OVERLAP the pass
    itself triggered by broadening coverage while an exact path still existed),
    and a group was added for the comment repair. The cleanup is recorded as
    FID-2026-1007-010 (closed; commits 63db5305, a3384883, a58472da,
    6888cf74) — the pass owed
    this FID and did not write it, having run as a complex change with no record.
    The four live orders are formalized as tracked FIDs: -011 (drain-manifest
    move safety — directory coverage is landed provisionally, the regression test
    is not written), -012 (telemetry, 0/7), -013 (eval-runner model
    override + usage, 0/7), -014 (git-workflow FID 4's G2 commit-hash and G5
    bundle-verified preflight audit), -015 (Atria handoff friction P1/P5), all
    registered in SCOPE.md as T164-A..T164-F. Verified:
    tree-drain UNCOVERED PATHS back to its pre-existing baseline of 4 (the
    operator's untracked docs), typecheck:scripts + cli typecheck exit 0, eslint
    --max-warnings 0 exit 0, lint:md exit 0, prettier clean,
    validate:repository PASS, and the register/contract/disposition guard suites
    green (8 + 25 + 7 pass, 0 fail).

  • Release script owns the README release callout (FID-2026-1003-007-era
    housekeeping, T94 ruling 2026-10-03).
    The operator's model is now the
    contract: the CHANGELOG's newest released section is the callout's prose
    owner, updateDocSurfaces syncs it into the README at every docs pass,
    and version:check fails closed on callout-body drift (the check
    immediately caught and synced the real tree's hand-drift). Also landed
    under the same decision digest: /init --force refreshes the
    .agents/types scaffold from the current template set (never-clobber
    stays the default; knowledge.md and non-template files are never
    touched); tauri joins the skills COMMAND_ALLOWLIST (operator-ruled
    security widening — skills:check now exits 0).

  • CleanAPIs and model information (FID-2026-1003-001, medium). CodeCraft
    and CleanAPIs share measured schema normalization with independent keys and
    caches. USD prices normalize to per-token values; unknown limits stay absent.
    Capability, tier, and reasoning-effort metadata reach agent prompts; the CLI
    and runtime fallbacks describe missing provider metadata accurately. Model
    information and provider setup are documented across root, release, and
    workspace READMEs. Generated provider references remain registry-owned.

  • Request token budgets enforced across every model call (FID-2026-1002-003,
    high; closed 2026-10-03).
    A shared provider-model guard covers streaming,
    generation, structured output, subagents, and retries: route catalog limits
    are consumed, final prompts/tools are counted, output is bounded, and one
    recovery attempt re-dispatches against a smaller provider-reported limit
    before delivery. Unknown output caps stay omitted; observations never
    fabricate model capabilities.

  • Knowledge-graph refresh reads only changed files (FID-2026-1002-006,
    medium; closed 2026-10-03).
    A stat pre-filter plus a sha256 baseline means
    the refresh reads, hashes, and parses only new or changed files;
    IMPORTS/EXTENDS edge layers derive from persisted tokens instead of
    re-reading sources, and legacy v1 databases backfill automatically on the
    next pass.

Fixed

  • Verifier output preserves one complete review (FID-2026-1010-002, medium;
    closed and archived 2026-10-10; local implementation a032bdfb).
    Final
    text retains source separators, thinking remains collapsible, replay does
    not duplicate the verdict, and provenance retains the selected final turn.
    Catalog/test and formatting blockers were repaired in c9c30b8f and
    5f8b6e26. Verification: 13/13 FID gates; repository tests 8,697 pass,
    23 skip, zero failures; typecheck, development build, lint, format, quality,
    scope-register and repository validation pass. Native OpenTUI and tmux
    verify 60/100/160 columns, resizing and folds.

  • The every-boot "Selected provider credentials changed" error was a false
    positive on the process-memory revision check (FID-2026-1009-001, medium;
    closed and archived 2026-10-09; local commit f56020b7).
    The route
    persisted in settings.json carries an accountRevision UUID minted by the
    saving process, while providerAccountRevision keeps a process-memory map
    and mints a fresh random UUID on first observation — so every fresh process
    compared two random UUIDs and rejected unchanged, valid env-sourced keys on
    the first message. Adopt-if-unobserved seeding in getModelRouteConfig
    (common) and applyPersistedProviderApiKeys (CLI boot, via the new
    adoptPersistedSelectionRevision) makes a fresh process accept the
    persisted route; an already-observed provider (a mid-session /provider
    save), a credentials.json anchor, and key rotation keep the strict
    comparison. Six declared gates pass with a stamped receipt; independent
    Verifier PASS.

  • The context meter no longer resets to 0/1,000,000 mid-session or on every
    boot (FID-2026-1009-002, medium; closed and archived 2026-10-09; local
    commit f56020b7).
    dampTokenCount adopted any incoming ≤ 10,000 —
    including 0 — exactly, so one non-positive runtime reading wiped an
    established count and the run-end writer made the zero persist; and the
    used-count was never seeded from the restored chat at boot. Fix: non-positive
    incoming is "no reading" and never wipes an established count (the
    FID-2026-0827-001 small-count floor, the ±5% deadband and the 12% ramp
    preserved); the meter is seeded from the restored chat's persisted
    mainAgentState.contextTokenCount; reconcileTokenCount requires a positive
    provider inputTokens before provider truth wins (0/unset falls back to the
    estimator — also keeping the compaction gates honest, FID-2026-1009-003
    Layer 1); and /new gets an explicit resetContextTokens companion. Seven
    declared gates pass; 26/26 tests; independent Verifier PASS.

  • Auto-compact now fires before the context window overflows, and an
    overflowing request recovers instead of hard-failing (FID-2026-1009-003,
    high; closed and archived 2026-10-09; local commit f56020b7).
    A long
    session died on RequestInputBudgetError (input estimate 1,004,611 against
    the 1M window) with no compaction in between. Three layers: the SDK budget
    layer gains an overflow seam — on a budget throw it invokes the host seam
    (the runtime arms agentState.autoCompactDue so the handleSteps generator
    force-compacts the shared session state), trims the oldest non-system turns,
    and retries exactly once (the unwired trim-recovery is the fallback; an
    untrimmable prompt still rethrows); the force margin is proportional
    (max(15k, 2% of window) = 20k at 1M) so a single large tool result cannot
    jump the force trigger; and the force path resets the escalation ladder so a
    successful forced compaction no longer strands proactive passes behind a
    hold baseline the count can never re-cross. Seven declared gates pass; 9 new
    tests; independent Verifier PASS.

  • The identity sweep can emit verdicts from operator-owned control pairs
    (FID-2026-1007-016, low; closed and archived 2026-10-08; register item
    T165 complete).
    Routes with a <provider>/<family> manifest entry run
    controlled (credentials pre-resolved, two-probe verdict rows, probe-budget
    degradation); anything missing stays inconclusive. Verdicts render in the
    console rows and the report table, and the glm-5.3-flash substitution was
    re-captured live to an artifact. Four declared gates pass with a refreshed
    archive receipt. Manifest authorship and the control-armed re-run stay
    registered as blocked under T175.
    Commit pending operator G2 commit (working-tree verified 2026-10-08).

  • The release preflight now audits G2 commit hashes and G5 bundle state
    (FID-2026-1007-014, medium; closed and archived 2026-10-08; register item
    T164-E complete).
    Two blocking checks join runPreAudit: closed FIDs
    whose closure postdates the last release tag must carry the hash in a
    machine-readable surface (field or status-line token), and the
    last-backup marker must resolve to verifying bundle files. Live design
    corrections cut 152 naive findings to 0 without weakening the gate;
    pre-gate history is grandfathered in a baseline with staleness
    enforcement. Three declared gates pass with a refreshed archive receipt.
    Commit pending operator G2 commit (working-tree verified 2026-10-08).

  • The tree-drain manifest's directory coverage is pinned by a regression
    suite (FID-2026-1007-011, medium; closed and archived 2026-10-08; register
    item T164-B complete).
    The dev/build-orders directory entry can no
    longer silently narrow back to exact paths: seven pins over the real
    GROUPS cover forward resolution, the synthetic moved path, the overlap
    class, exact-entry single ownership, and reverse liveness, plus a manifest
    header rule. Two declared gates pass with a refreshed archive receipt.
    Commit pending operator G2 commit (working-tree verified 2026-10-08).

  • **The model picker opens immediately from a warm cache and wires unkeyed
    registry providers through the existing key flow (FID-2026-1008-005,
    medium; closed and archived 2026-10-08; implementation commits 9a07792e

    • 32b222ff; register item T172 complete).** openModelPicker opens
      cached rows before the gateway refresh, then updates a picker that remains
      open; the measured stale-cache wait falls from 10,025 ms to 0 ms. Saving a
      matching provider key activates the staged model once. The provider quality
      and identity gauntlets are documented in docs/provider-gauntlets.md and
      linked from AGENTS.md. Seven declared gates pass with a refreshed archive
      receipt. Harvested-candidate wiring remains blocked on the operator ruling
      under T171.
  • The every-boot digest has a tested decision seam and counted offer
    deadlines (FID-2026-1008-004, medium; closed and archived 2026-10-08;
    implementation commit 742d919f).
    The injected runLaunchDigest posts
    only non-empty summaries and handles reader failures without throwing.
    Offer deadlines survive parsing into a count for the next 72 hours;
    "end within 72h" appears only when the count is positive. Five declared
    gates pass with a refreshed archive receipt. The harvested-candidate
    design remains in the archived record, with verdict and consent decisions
    registered as the blocked T171 remainder.

  • Free-provider launch summaries appear on every boot
    (FID-2026-1008-002, medium; closed and archived 2026-10-08;
    implementation commits d6d544b4 + 742d919f; register items
    T168/T169 complete).
    Removed the same-day early return and the
    orphaned shown-date preferences, settings field, validation branch and
    store pins. Quiet boots remain silent. Three declared gates pass with a
    refreshed archive receipt; boot-decision coverage is supplied by -004,
    registry-only wiring by -005, and the harvested-candidate remainder
    stays registered as blocked under T171.

  • Eval lanes accept a model override and report actual run-total usage
    (FID-2026-1007-013, low; closed and archived 2026-10-08;
    implementation commit 8ead0378).
    --model reaches an inline agent
    definition clone without mutating bundled agents; unresolved ids fail
    explicitly. The existing runtime usage hook accumulates token counts,
    and trace finalization sums the recursive subagent tree while recording
    the effective model. Five declared gates pass with a refreshed archive
    receipt. The per-sample callback and print-mode wire member remain blocked
    under T164-D on a named consumer and the operator's billing and wire
    decisions.

  • GREEN batches verify once and can complete with enforcement credit
    (FID-2026-1007-015, low; closed and archived 2026-10-08;
    implementation commit 4eaf57cc; register item T164-F complete).

    Operator ruling "verify once seems optimal": the other-dirty Law 3 leg
    is advisory only in green; target-dirty, non-green and turn-end checks
    remain enforced. The approved green → complete edge reads the cached
    enforcement instance's verification credit and refuses completion after
    an unverified write. Five declared gates pass with a refreshed archive
    receipt; pins cover the allowed and refused transitions.

  • The model picker no longer renders a free-key lane, and provider groups are
    alphabetical (FID-2026-1007-017, low; closed and archived 2026-10-08; local
    commits df2d88af + 4ccabe17; register item T166).
    Two defects in the
    /model picker. The ⭐ FREE KEY section pushed a
    CHATANYWHERE_API_KEY: ···· (free key set) row beneath its header, so the free
    lane read as ChatAnywhere's section rather than a lane of free models — the
    operator: "it does not need 'chatanywhere api key' first line, it should simply
    show the regular chatanywhere in the model page like normal". And provider
    groups were ordered by the registry order field, not by name: openai
    carries order: 0, so OPENAI sorted first. The section now renders hoisted
    free-token models only (no key lane; the free-key provider appears as an
    ordinary group with its ⭐, and provider groups order alphabetically by
    provider id. getProviderOrder is retained as the registry-derivation
    contract for custom providers. The operator renamed the section header
    ⭐ FREE KEY → ⭐ FREE MODELS and live-confirmed the picker 2026-10-08.

  • The model picker's KiosAPI group serves the full published Model Square,
    not the Free key's subset (FID-2026-1008-001, medium; closed and archived
    2026-10-08; implementation commit 4e1ab59b; register item T167
    complete).

    The catalog source was the key-scoped GET /v1/models, which per KiosAPI's
    docs lists "models available for your API key" — the stored key is a Free-
    group key, so the picker showed 36 free-tier rows while the vendor's own
    page publishes 80 (operator: "the models list … is old/outdated"). Every
    flagship was absent: gpt-5.6-sol, gpt-6-astra, claude-opus-5-5,
    claude-sonnet-5-5, gemini-3.8-flash, grok-4.7, deepseek-v4-pro-0813.
    The source is now the vendor's public, unauthenticated
    https://kiosapi.com/api/pricing feed (the same JSON the Models & Pricing
    page renders), so the list matches the site and no key is resolved for
    listing; window lookups keep the checked-in fallback values unchanged.
    Four declared gates pass with a refreshed archive receipt. The table header
    documents the four grok-imagine-image* ids and openrouter/free as
    deliberately non-applicable; five exact text-id windows remain blocked on
    vendor-published data under T173.

  • The every-boot launch announce reports the configured provider set, not
    the custats-overlap subset, and stops claiming offers are "ending soon"
    (FID-2026-1008-003, medium; closed and archived 2026-10-08; local commit
    a9ae21d0; register item T170).
    The operator reported the announce as
    "broken and very minimal vs what we provide — seeing we only have 2 wired
    is completely wrong." wiredFree counted only providers present in the
    third-party custats catalog AND keyed, so 23 configured providers rendered
    as 2. The announce now prints Configured: N provider(s) from the full
    credential-ready registry set (labels only, never key material), relabels
    the catalog subset Free catalog overlap, and the offers line states the
    feed total with an unconditional "eligibility and deadlines unverified"
    disclaimer instead of the unsupported "ending soon". A test-driven
    correction caught the first draft counting configured providers toward the
    "nothing to say" guard — a configured provider with no free lane stays
    silent under the free-lanes header. The 72h deadline window landed
    separately under FID-2026-1008-004 (B). Receipt 4/4 live at the archived
    path; register item T170 complete.

  • A local circuit breaker no longer refuses a user's model turn (FID-2026-1007-007,
    high; closed 2026-10-07; local commit 7a7f5dee; register item T162).
    The
    operator hit this twice in one session and could not place it — "i don't even
    know what caused it, the model was working perfetly fine?" — and it was entirely
    local. runWithClassifiedRetry gated the top of every attempt on
    breaker.checkCooldown() before params.create() and threw
    ProviderBoundaryBlockedError, so three transient failures across as few as two
    turns opened a 30-minute gate: the saved chat shows KiosAPI refused at 16:15,
    16:22 and again at 16:38 with 14 minutes still remaining, and Unorouter refused
    at 16:46 after a 16:40 upstream rate limit. Because the breaker is keyed per
    provider connection, changing models on one connection could not escape it
    while separate providers each opened their own — which is why it looked random
    and why "the model was working perfectly fine" was true of every model that had
    not tripped its own gate. The pre-request refusal is removed; an open breaker now
    suppresses only an optional automatic retry, so every user turn's first physical
    request runs and what the user sees on failure is the provider's own verdict,
    never a local lockout. Failure classification, the bounded retry budget, the
    429 one-retry rule and success-closes-the-breaker are unchanged. The operator's
    ruling is the acceptance criterion, verbatim: "it should NEVER stop a user from
    using a model." The closure pass re-reproduced the defect rather than trusting
    the earlier run — reverting classified-stream-retry.ts alone restores
    0 pass / 2 fail with the operator's exact message, and restoring it returns
    2 pass and 6 pass. Receipt 5/5 live at the archived path. Two limits are recorded
    rather than hidden: checkCooldown() and ProviderBoundaryBlockedError now have
    no production caller and are retained as tested FSM surface with their comments
    updated, and the upstream sequence that opened the KiosAPI circuit is still
    unproven from the saved chat.

  • ChatAnywhere reaches the /model picker, and the free-key lane stops
    advertising a provider with nothing behind it (FID-2026-1007-005, medium; closed
    2026-10-07; local commit edc761a8; register item T160).
    The operator's report
    — "the 'chatanywhere' list seems to be designed wrong and not matching the rest of
    the list too" — described two defects and both were real. The provider was
    registered, catalogued, window-covered and documented, and the fetchGatewayModels
    fan-out never asked for it: 166 rows from 21 providers and [] for
    chatanywhere
    . A synchronous builder now derives the 27 rows from the checked-in
    chatanywhereModels map (the gateway publishes no window fields on its keyed
    /v1/models, which is the same finding that made intern static) and is merged
    before the custom catalogs; the live census through the shipped function reads
    chatanywhere: 27. The second defect was the ⭐ FREE KEY section: it hoisted every
    free-RELATED row, and isFreeTierEntry covers every row of a free-key provider, so
    a correct wiring would still have relocated the whole roster out of a
    CHATANYWHERE group — which is what "not matching the rest of the list" meant. The
    operator's rule was about the marker, not the placement, so hasFreeToken is now
    the hoisting rule, freeBadgeFor still stars every free-key row in place, and the
    key lane renders only for a provider that actually contributed rows (it used to ask
    for CHATANYWHERE_API_KEY in a list containing no chatanywhere model at all). The
    class is closed two-directionally: catalogPairingIssues fails when a provider
    declaring catalog.modelsRef contributes zero picker rows, or when an audited
    exception starts contributing — with cloudflare (SDK-routed, no CLI builder) as
    the one recorded exception. providers:parity --check exits non-zero on either.
    Gates: cli suite 0 fail, typecheck cli 0, quality PASS, provider-parity-check PASS,
    receipt 8/8.

  • A superseded gateway-catalog build can no longer publish, and the CLI suite owns
    its own config directory (FID-2026-1007-006, medium; closed 2026-10-07; local
    commits d396d091, 8c92d087; register item T161).
    bun run test was red at the
    cli leg — 3961 pass / 1 fail — so the && chain stopped there and eleven
    workspaces were never exercised. The failing assertion received "OpenAI: GPT-5"
    while asserting a mocked "GPT-5", and tracing it corrected the record's own
    draft
    : no test reads the operator's cache (the suite's config dir resolves to
    ~/.savant-code-dev, which holds no catalog), so the suite was doing something
    worse — fetching live and publishing the result into shared module state. Step 1
    named the file by instrumenting the new guard for one bun test src/ run: 82
    claims against 37 suppressed publishes
    , 36 of the claims from
    cli/src/server/gateway.ts:114, the fire-and-forget void fetchGatewayModels()
    boot warm that the server test harness raises 36 times per run. Every publishing
    path now claims a build token first, so a build whose caller has moved on returns
    its own catalog while writing neither the cache, nor the listeners, nor the disk —
    and the in-flight slot is released on settle, which repaired CATALOG_TTL_MS, dead
    code in production until then. Separately, the config-dir override moved out of the
    opt-in per-file harness and into the workspace preload, so no cli test can resolve
    the user's directory for settings, credentials, message-history.json, project data
    or the gateway disk cache. Three pins, all RED-first; the pre-fix suite was 3964 pass / 4 fail and is 3969 pass / 0 fail. Receipt 5/5.

  • The prompt-cache program is reconciled, implemented and closed — one step landed
    by another record, two re-scoped to offline evidence (FID-2026-1006-005, medium;
    closed 2026-10-07; local commits ba4dee65, f0d365fa, 7901568f, 70cec07c;
    register item T155).
    An externally sourced 324-line research report was
    adjudicated against the shipped tree rather than implemented from, and all eleven
    steps are resolved. Phase 1 makes the model-facing tool payload canonical at its
    single assembly seam behind CANONICAL_TOOL_PAYLOAD and normalizeForJson /
    stableHash order-canonical in both twins, so toolsHash moves only on a real
    payload change; the split cache-control seam became one spelling over one provider
    set behind one clearer; the mode-to-TTL policy routes from the run's own enforcement
    axis (Hybrid 5m, FID-bound 1h); both operator-approved ECHO amendments are law.
    Step 11 was not open work — FID-2026-1007-004 had already implemented it, so
    the record was carrying a status drift. Steps 8 and 10 are re-scoped rather than
    deferred:
    the live-endpoint and provider-billing requirement they were blocked on
    was never approved by the operator, and had entered through this record's own
    reconciliation of the vendor report's Approval Point 3. Step 8's evaluation is
    measured in the tree (the tool set is assembled once per run, its one mid-session
    mutation happens before the run's first provider call, so the Anthropic
    tool_addition/tool_removal betas have nothing to smooth — adoption declined
    with its reopening condition stated); step 10 measures the prefix-stability ratio
    the shipped instrument computes (100% over a 12-turn loop with no structural
    change, 81.8% with one warning on a genuine tool change, byte-identical
    model-facing bytes across a reorder under the shipped seam). The provider-side hit
    ratio is an environment boundary rather than a claim. Receipt 8/8.

  • No path discards model-facing bytes it has not provably stored, and no marker
    claims a location it cannot compute (FID-2026-1007-004, high; closed 2026-10-07;
    local commits e9322b38, eb2ee0f3, 49c7bab4; register item T159).
    Savant
    discarded tool output in five places and in every one of them told the model the
    bytes were available somewhere it could not reach.
    truncateToolOutputValue's marker carried
    fullOutput: '[See cache-debug snapshot / rerun the tool for full output]' — a
    fixed string naming two possibilities, while the cache-debug feature it names is
    disabled by default — and the other four (simplifyVerboseToolResults,
    simplifyReadFileResults, simplifyTerminalCommandResults, and the trim pass in
    trimMessagesToFitTokenLimit) dropped the payload with no locator at all,
    the trim pass deleting whole messages and writing no inventory row (the only
    destructive path accountable to no ledger). The store that could answer all of
    it — the per-run evidence spill at .savant/evidence/<runId>.jsonl — was
    unreachable from every marker, its read side gated behind requiresRawEvidence
    (Verifier and Adversary only), its splice firing only on a [compacted] sentinel
    the trim pass never produces, its ceilings refused silently, and its raw output
    persisted unredacted. All seven steps landed: the retention seam returns a handle
    or a named refusal; the four transforms read the boundary's verdict by
    toolCallId and return the payload untouched when there is no handle, so no
    path can take bytes nobody kept; one omitted marker carries
    retained: { file, toolCallId, sha256, bytes, redacted } or the refusal reason,
    and fullOutput's placeholder is deleted; the trim pass writes a
    layer: 'trim' ledger row naming the toolCallIds it deleted; the store resolves
    for whoever holds the handle (the spawn read gate is scoped by need, not by role),
    and credentials are redacted before hashing and appending, so the stored form
    is the redacted form — a Law 12 decision stated on the record and the handle,
    removing bytes only from the store and never from the model's context; and the
    store shards, so its ceilings are a stated bound that is reported when hit instead
    of a silent false nobody reads. 25 new pins across six files;
    packages/agent-runtime 1905 pass / 0 fail across 297 files (was 1880 / 294),
    root typecheck exit 0, eslint . --max-warnings 0 exit 0, prettier clean,
    module-state-check PASS (183 of 188), and all eleven declared gates exit 0 at
    the stamped receipt. The quality gate rejected five files this work had grown past
    the 300-line absolute maximum, and each was split at a real seam with every origin
    re-exporting what moved, so no caller changed. Two deviations from the record's own
    plan are recorded rather than smoothed over, and the loop's heaviest finding ran
    the other way: util/__tests__/messages-trim.test.ts was passing partly because
    of the defect
    — its terminal fixtures were bare JSON strings no
    run_terminal_command schema can produce, so the old transform threw into its
    lossy fallback and collapsed ~2,018 characters to ~40, which is what satisfied the
    suite's own token-budget assertion; the fixture was repaired to the real shape (and
    registers the handles it now requires) and the assertion was kept unchanged. Local
    commit only: no push and no release.

  • Law 15 baseline capture refused its own baseline on a large repository
    (FID-2026-1006-004, high; closed 2026-10-06; local commit ba38c548).
    The worktree
    backstop was inert at this repository's size: captureWorktreeBaseline content-hashed
    the full 5,455-path / 27.1 MB inventory inside CAPTURE_BUDGET_MS = 5_000, and a blown
    budget was refused by design — which reconcileWorktree turned into an unconditional
    cannot-verify, disarming Law 15 for the rest of the session while the only symptom was an
    advisory naming no files. Capture now inventories every path but content-hashes only the
    initially-dirty set, the refusal records which leg failed (enumerate, dirty-set,
    hash-budget, walk-budget), and a refused baseline is retried under a bounded cooldown
    instead of staying permanent. Two further defects sat behind it: the reconcile deletion
    leg ran one statSync per baseline key (5,459 stats) inside a 500 ms budget, and both
    git spawn helpers reported any spawn error as "git failed" — including a measured 13 ms
    spurious ETIMEDOUT against a 500 ms budget. The deletion leg is now change-bounded
    across four terms that each cover a class no other term can see. Measured on this
    repository through the production functions: capture 956-1,128 ms over 5,454 hashes to
    244-254 ms over a 5,464-path inventory with 18 hashes; reconcile 289-344 ms to 110-114 ms
    with degraded: false; the durable checkpoint shrank from a 663,482 B pre-split
    equivalent to 301,304 B. Two new modules (worktree-git.ts, worktree-scan.ts),
    rewrites of worktree-capture.ts and worktree-reconcile.ts, ten deterministic pins
    plus one moved pin, two new suites and one sdk transport leg; fid:verify 10/10 exit 0.

  • kiosapi roster context windows (FID-2026-1003-008, high; closed
    2026-10-04).
    Every kiosapi id missing from the fallback table resolved
    to the 200k default, steering compaction with a 5x-too-small denominator
    while the SDK budget guard used the true window, until a
    qwen3.8-flash-free run died on RequestInputBudgetError (input estimate
    1,347,990 vs the 1M context). The full 77-id Model Square roster is now
    covered by 69 vendor-sourced rows (OpenRouter cross-vote; kiosapi's API
    publishes no window fields), seam-split into their own module under the
    300-line ceiling, with a 5-pin suite plus a seam-wiring census; eight
    image/stealth ids deliberately stay rowless on the flagged default. The
    closure pass also ran the neighboring ladder suites and superseded one
    stale 200k pin (glm-5.3-flash-free) with the sourced row, no-bleed proof
    intact.

  • Model-picker scrolling (FID-2026-1003-004, medium; closed 2026-10-03).
    Fixed model/header rows at one terminal line so logical scroll offsets match
    rendered height. Keyboard, wheel, scrollbar, filter, resize, and full-ID
    selection have native OpenTUI regression coverage. Long names clip visually
    while selection retains the complete model ID.

  • System data-flow audit corrections (FID-2026-1002-002, high; closed
    2026-10-03).
    Full baseline capture fits the real-tree budget; snapshot/
    sidebar and post-await save ownership gaps are closed; active-only FID
    loading no longer reads the archive; byte-only search events stop silently
    losing content; sidebar archive/convergence claims carry evidence; the FID
    gate executor runs workspace tests from their workspace root per the T67
    guard.

  • Desktop sidecar resolves its project root (FID-2026-1002-004, high; closed
    2026-10-03).
    The supervisor passes SAVANT_PROJECT_ROOT env-only with a
    declared build profile; the sidecar fails closed before binding when a
    release launch arrives without a root (Rust git-root tests, argv-exclusion
    pin, release-gate test, cargo probe gate).

  • Turn-end baseline advance uses the captured root (FID-2026-1002-005,
    medium; closed 2026-10-03).
    The advance resolves its root from the
    captured baseline root, matching the reconciliation contract; the old code
    failed both of its assertions and is pinned by a captured-root regression.

  • Gateway approvals survive disconnects; the flush timer retires
    (FID-2026-1002-007, low; closed 2026-10-03).
    Approval deny moved to
    run-settle plus shutdown so a disconnect can no longer lose pending
    approvals; the event flush timer self-stops when the buffer drains and
    re-arms on push (contract re-pinned; new flush-lifecycle suite).

  • Gateway dispatch error containment (FID-2026-1002-008, medium; closed
    2026-10-03).
    The RPC dispatch boundary, the void-ed user_message
    handler, the hello FID-snapshot timer, and the websocket transport are all
    contained on the frozen v1 vocabulary (internalError -32603 /
    run_complete {ok:false}); a handler throw can no longer tear down the
    sidecar or wedge a session. No wire-contract change; fault-injection tests
    run through harness DI seams only.

  • Per-project data directories are collision-proof (FID-2026-1003-003, low;
    closed 2026-10-03).
    getProjectDataDir() keys
    projects/<basename>-<sha256-8> over the realpath-normalized root
    (win32-lowercased), ending same-basename cross-project conversation bleed;
    a one-time guarded rename migrates existing history non-destructively.

  • Model-picker search keeps provider identity (FID-2026-1003-005, medium;
    closed 2026-10-03).
    Provider-scoped React row keys end stale direct-OpenAI
    rows being retained after search when OpenRouter serves the same model IDs;
    colliding-ID native regressions fail before the correction and pass after,
    and both routes sharing an ID remain independently selectable.

Validation: authenticated catalogs returned 33 CodeCraft, 129 xKiro, and
33 CleanAPIs models on 2026-10-03; every upstream ID survived normalization.
Live tool calls passed on all three services. xKiro Messages also passed with
an explicit free-model test override; the mapped Claude route returned HTTP
403 requiring paid account access. Prior implementation suites: common
providers 72 pass, related CLI 170 pass, SDK 577 pass with one POSIX-only skip.
Both FIDs are closed and archived with implementation commits 72af5480
(providers, 23 gates passed) and 27161203 (scroll, six gates passed), satisfying
ECHO G2. Project-wide documentation and model information are updated. T119
retains Claude account access and the possible fourth provider's missing
identity. These local commits are not a published release or remote push.

Validation: the eleven FIDs documented above (FID-2026-1002-002, -003, -004,
-005, -006, -007, -008 and FID-2026-1003-002, -003, -005, -006) were
implemented and verified with receipt-stamped gates, then landed together in
batch commit 9f1b8068 (351 files) on 2026-10-03 after a pristine
full-repository battery: 7,878 pass / 0 fail across all 13 workspaces plus
script gates (sdk 655, cli 3,826 pass / 18 skip, common 749, agent-runtime
1,648, desktop 427; typecheck 14 legs exit 0; ESLint, markdownlint, Prettier,
and quality all clean). The custom-endpoint auth seam was hardened in the
same commit: a custom INFERENCE_BASE_URL endpoint is authorized by
INFERENCE_API_KEY only — no active-provider key-chain resolution and no
fail-closed throw naming an unrelated provider (handoff matrix 6/6; child
cases 4.2–5.7s, previously 10–22s while the master-key exchange was in
play). All eleven FIDs are closed and archived to dev/fids/archive/ with
the closure commit, satisfying ECHO G2. These local commits are not a
published release or remote push.

2026-10-02 — EHEL enforcement restored end-to-end: effect-based mutation classification, worktree-reconciled Law 15, Law 2 scope gate, and fail-loud code_search (2 FIDs archived)

The ECHO laws are no longer bypassable — enforcement by effect, reconciliation against the worktree, and the Law 2 scope gate (FID-2026-1001-003) — closed 2026-10-02

The operator-ordered review confirmed the laws were defeated by a single terminal command: enforcement was selected by tool NAME (isWriteTool matched exactly three tools, and both the pre-write gate chain and the write bookkeeping the Law 15 backstop reads hung off that one predicate), so one run_terminal_command (sed -i, >, python -c) defeated Law 1, Law 3 and Law 15 simultaneously and left no trace. All eight steps are implemented:

  • Terminal bypass closed (step 1): one effect-based classifier (packages/agent-runtime/src/echo/enforcement/helpers.ts → classifyMutation) replaces four by-name predicates and routes all consuming call sites through the same code path; mutating terminal commands now traverse the full pre-write gate chain, their classified targets fold into dirtyFiles/filesWritten, and Law 15 sees the bypass. The optional PreToolUse defence-in-depth hook SHIPPED: protocol.config.yaml declares deny-mutating-terminal (packages/agent-runtime/src/hooks/deny-mutating-terminal.ts), decided by the same classifier.
  • Law 15 reconciles against the worktree (step 2): a durable content-hash baseline lives on the grounding checkpoint (never on EnforcementState, per the Adversary mandate); turn end enumerates the CHANGED set cheaply via git status --porcelain and hashes only candidates, merges unaccounted mutations into dirtyFiles, and blocks — deletion is a distinct outcome (livelock guard), the baseline advances over verified batches, and a cost defect found at closure (full-inventory hashing, ~6s on this 5,140-file repo) was corrected to candidate-based reconciliation (6.2s → 460ms, inside the operator-confirmed 500ms budget).
  • Law 1 read-state is durable (step 3): reads mirror into a bounded ledger on the grounding checkpoint (GroundingCheckpoint.readLedger) and hydrate across session restores — the three-times-reproduced re-block is dead; write credit never hydrates.
  • Law 3 restored + escalation (step 4): the other-dirty pre-write leg BLOCKS again (the FID-2026-0918-005 demotion was self-authored and structurally void), with a verification-escape clause (a block never fires on its own cure, via the same predicate the credit path uses) and N=3 strike escalation keyed law|tool|target that arms turn termination — a harder response, not a different message.
  • Law 2 write-time scope gate (step 5a): every mutating target resolves against SCOPE.md's new machine-readable register (## Machine-readable scope targets); no pattern covers → block with "present it first". Governance surfaces the protocol mandates are gate-level exemptions (operator ruling); targets outside cwd are outside the gate's jurisdiction (closure correction, pinned).
  • Laws 4/7 surfaces (steps 6/7): Law 4's wiring detector requires a real export declaration in code files (a markdown fence quoting export no longer registers a feature, and the false-registration livelock is evicted at turn end); validateFidStepStatus scans for unresolved implementation claims document-wide with a verified implementation_started assertion.
  • Prompt-content CI gate (step 8): agents/__tests__/detective-prompt-content-gate.test.ts pins the Detective's source-of-the-claim rules mechanically.

Gates: receipt stamped via fid:verify --write — all 14 declared gates PASS from the repo root (agent-runtime typecheck + 11 suites incl. the new terminal-bypass-pipeline, law3-escalation, law2-scope-gate, deny-mutating-terminal, worktree-reconcile, law1-read-state-durability, law4-wiring-scope, fid-validator, the Detective prompt gate, and quality); full suites agent-runtime 1,641/0, sdk 551/0 (1 pre-existing skip), common 738/0; root typecheck chain exit 0; eslint --max-warnings 0; lint:md 0; validate:repository PASS. Commit SHA pending operator git execution.

code_search fails loud — silent "Found 0 matches" is no longer indistinguishable from a genuine absence (FID-2026-1002-001) — closed 2026-10-02

An evidence tool lying by omission: a pattern with 65 ground-truth hits returned Found 0 matches with Exit code: 0 — internally inconsistent for ripgrep (0 = matches existed), pointing at silent event loss in the collector. Fixed at both layers: the collector now accounts for every unparseable event line (droppedEventLines + first-dropped-line diagnostics, with protocol events begin/end/summary correctly exempt) and flushes the trailing remainder; the executor classifies the run outcome at close (sdk/src/tools/code-search/anomaly.ts → classifyCodeSearchOutcome, rg exit semantics as ground truth) and settles hard anomalies (exit-0-with-zero-collected, drop-explained zeros, error exits) through the error channel carrying stderr and drop counts; the display formatter renders "Found 0 matches" only for a verified clean zero (options.emptyResultText). Drops alongside real matches settle with a visible warning suffix. Stated limit: the fix makes every loss LOUD; it does not recover lost lines — a recurring decode-level drop becomes a follow-up with real evidence. Gates: sdk typecheck 0; new suite sdk/src/__tests__/code-search-fail-loud.test.ts 14/0; common typecheck 0; common/src/util/format-code-search.test.ts 4/0; full sdk 551/0; quality PASS; receipt stamped via fid:verify --write. Commit SHA pending operator git execution.

Free-provider discovery reaches users (FID-2026-1001-002) — closed 2026-10-01 (commit 5ea0e0a)

The free-compute discovery pipeline (FID-2026-0914-003 + 0928-011/012) shipped healthy but reached
nobody: the MQ4 boot harvest is repo-gated (its own comment says ordinary users outside the repo never
fetch), the MQ5 announce reads a gitignored dev-side ledger shipped users never have, and
/provider free was on-demand with zero proactive discoverability — the operator ran the CLI for four
months without ever seeing a notification.

Two surfaces, both pattern-copies of existing ones. discloseFreeOptionsNoticeOnce()
(cli/src/cli-boot-steps.ts) prints a stderr-only one-time pointer to /provider free, retires on a
persisted freeOptionsNoticeShown flag, is wired ahead of the headless dispatch so --print /
--auto / piped / CI runs see it too, and is skipped in SavantFree where /provider is not
registered. announceFreeOptionsSplit() (cli/src/chat/use-chat-bootstrap.ts) joins the existing
deferred discovery effect and announces the cached wired/not-wired free-lane split once per
content-set via a sidecar key, kicking a fail-silent background refresh when the cache is absent or
stale while the announce path itself never fetches.

Supporting work: readCachedFreeOptionsReport() reads the local cache only; buildMachineContext
is shared by the refresh and the reader (one truth); liftCatalog was extracted to
free-options-catalog.ts to keep every module under the 300-line ceiling with one import surface
preserved. docs/features.md gains a Free AI Options Discovery section stating that the boot summary
is interactive-TUI-only, so headless runs get the notice and the command.

The record ran four loops: a Verifier audit and self-correct (the quality ceiling rejected the first
receipt stamp; the fetchedAt guard was then fixed in both the announce renderer and its
command-output sibling), an operator-requested Adversary meta-verification that overturned the
Verifier's verdict on five evidence points and raised a new FAIL-class omission — both surfaces were
TUI-only, so headless users got neither — and the record's own unauthorized n/a deferral of the
Adversary phase; then a delta-scoped Verifier pass that closed with no FAILs and two doc-accuracy
corrections. Gates: typecheck cli 0; 19/19 pins (2 boot-notice + 6 cached-reader/renderer + 11
pre-existing); eslint --max-warnings 0; prettier --check clean; quality:report PASS;
markdownlint 0; Law 4 grep on both call sites; fid:verify receipt stamped and re-checked.

First-class OpenAI platform provider + /provider picker ordering (FID-2026-1001-001) — closed 2026-10-01 (commit f099ded)

OpenAI's platform becomes a first-class registry provider on a second credential lane: a platform sk- key
(OPENAI_API_KEY, /provider openai) routes openai/<id> — and bare slugs while OpenAI is active — to
api.openai.com over the Responses API, while the ChatGPT-subscription Codex OAuth lane keeps precedence for its
allowlisted models (the OAuth gate at sdk/src/impl/model-provider.ts is untouched; skipChatGptOAuth still forces
the platform lane). The single-protocol responses protocol is now legal without a protocolMap — the new total
resolveEntryProtocol (no-map path) returns the entry protocol with a narrow union, resolveProtocol stays internal
for map-dispatch, and the bare-slug default-inference path dispatches on the active provider's resolved protocol
instead of hard-coding chat/completions (map-dispatched active providers keep their legacy construction via a
protocolMap === undefined guard — api.openai.com 400s on chat/completions for reasoning+tools). The /provider
picker sorts by label within the built-ins and customs segments (add-row sentinel last) via a testable
buildProviderPickerEntries helper, and /provider list renders under the same label-sort contract via the extracted provider-list.ts module); the live /v1/models roster joins the gateway catalog fan-out
(openai.ts wrapper on the shared fetcher, positional-contract ladder extracted to gateway-live-results.ts under
the 300-line cap, test reset, provider-audit manifest exception). Generated provider docs plus nine hand-maintained
doc surfaces and the provider runbook are updated. New suites: registry validation for the openai entry (3), the
SDK OpenAI lane (6 — key gating, Responses URL/Bearer/body, OAuth precedence, bare-slug dispatch, byte-identical
non-OpenAI leg), provider setup + picker sort (4), and the live-catalog fan-out (4); two pre-existing OAuth
fallback legs re-armed with the platform key. Gates: fid:verify 8/8 (typecheck common/sdk/cli, the four suites,
quality); root typecheck 13 legs 0 errors; sdk 536/0; cli 3772/0; eslint --max-warnings 0; lint:md;
validate:repository PASS; generate:provider-docs:check up to date.

Connector tool surface — the catalog reaches the agent vocabulary (FID-2026-0930-003) — closed 2026-10-01 (commit 7187d1e)

The connectors catalog is no longer dead code from the runtime's perspective: it is exposed as a fixed-size 4-tool
meta-family (connector_search / connector_describe / connector_invoke / connector_credentials) following the
composio precedent. common carries the names union, params (zod, with mode: live|replay on invoke), the
clientToolCallSchema options, and per-tool safety metadata (catalog reads allow, invoke network/prompt — the
sole vendor-egress entry, credentials read reporting env NAMES + presence only, values never crossing the tool
boundary). packages/agent-runtime gains five DI-shaped handlers (BundleProvider injection; handlers do no fetch of
their own) consuming the checked-in compiled bundle via a tool-facing runtime entry (loadLaunchBundle/
catalogSearch/describeEndpoint/executeEndpoint) — the typescript-importing compiler stays out of the runtime
graph by construction, and the package root gains the previously dangling src/index.ts barrel. The SDK answers
connector_* calls honestly (no local executor) beside the composio branch. Implementation surfaced and repaired two
cross-workspace import mechanisms: the vendored @shared/* tsconfig alias (connectors-private; unresolvable in any
consumer program — 49 errors at the agent-runtime leg) de-aliased to intra-package relative imports across 54 files
with the alias mappings removed and the substitution ledgered in PORT-NOTES.md, and the SDK's rejection of .ts
import extensions (281 × TS5097 — the SDK path-maps agent-runtime to source, transitively compiling connectors)
resolved by accepting the flag in the SDK's no-emit/declaration-only configs plus externalizing
@savant-code/connectors in the bundled d.ts. Four offline test suites (26 tests): tool-params registration,
catalog-tools-surface (bundle load, doc-as-contract, replay invoke settling {credits:{}, evidence:{}}), handler
DI dispatch with a no-value-leak credentials pin, and the SDK honest-error branch. Gates: repo typecheck 14 legs
0 errors; repo test 13 suites 0 fail (sdk 600 incl. the new pin); quality PASS (1498 baselined files); eslint
--max-warnings 0 (tooling override extended to packages/*/scripts/**); lint:md; validate:repository PASS;
build:catalog regenerates the committed artifact (3 providers, 9 endpoints); receipt stamped 7/7 gates.

Connector layer — the monid port lands as packages/connectors (FID-2026-0930-001, FID-2026-0930-002) — closed 2026-09-30 (commit 9816bbd)

Savant gains a declarative tool-connection layer: a sync-only copy-and-strip port of the MIT monid connector layer
(vendored at resources/monid-main/) into a new packages/connectors workspace (192 files, +15,248). Connector defs
compile to a deterministic content-addressed bundle; the engine executes sync endpoints end-to-end (validate input →
input.toRequest → transport with credentials injected at the boundary, never visible to fn code → usage settle →
map + validate output) and replays recorded vendor fixtures offline. Launch catalog: tinyfish, exa, firecrawl
(scrape/search/map + the sync -status endpoints), with recorded fixtures. The hosted async/resource/billing
surfaces are stripped — resource lifecycle, webhooks, relay transport, credit-pool settlement, KV store, catalog
publish — and async endpoint DOCS now fail closed at LOAD (ASYNC_UNSUPPORTED) instead of failing open mid-run
(deviation ledgered in packages/connectors/PORT-NOTES.md); MIT attribution preserved
(packages/connectors/LICENSE-monid). Every file meets the 300-line ceiling: compiler split into 12 modules,
engine into engine/settle/resolve/link, testing into 4, categories into facade+core+extended, lifecycle into 2,
firecrawl schema/search into 4 each. Registered across all four gate surfaces (root workspaces + typecheck/test
gains, VALIDATION_WORKSPACE_POLICY, protocol.config.yaml mirror; AGENTS.md count corrected to 13 workspaces).
Gates: workspace tsc 0 errors; 3 FID-declared suites 10/10 offline; eslint --max-warnings 0; repo typecheck 13
legs 0 errors; repo test 13 suites 0 fail (connectors 10/0); lint:md; quality PASS (1498 baselined files);
receipts stamped for both FIDs (8/8 gate executions exit 0); validate:repository PASS.

Gut the backend stage 2 — the backend-mode surface retired across CLI and SDK (FID-2026-0929-005) — closed 2026-09-30 (commit 06220bc)

Stage 2 of the gut-the-backend program (operator ruling 2026-09-29: "we need to gut this whole 'backend' idea, we
don't have a backend to fall back to"). Direct mode stops being a mode and becomes the product. Deleted across four
stages: the SAVANT_CODE_API_KEY opt-in (cli env branch + stub bypass token; common CiEnv snapshot, type, and test
fixtures); the sdk backend client surface (apiKey constructor requirement, healthz checkConnection,
impl/database/* agent-run + user-info reporting + fetch-with-retry, the composio relay, the remote:true
validation branch, getWebsiteUrl, and the backend-as-inference fallback — INFERENCE_BASE_URL now fails fast
naming the var; end-to-end apiKey/userId threading removed, userId pinned 'local'); and the cli backend-billing
UI (backend-mode 402 branch, OUT_OF_CREDITS_MESSAGE, the 'outOfCredits' input mode + open-buy-credits keyboard
chain, out-of-credits/usage/subscription-limit banners, the usage/subscription/streak query family, and /subscribe
with all aliases including the vestigial strong). Fourteen e2e suites rewired onto a keyless setupMockClient()
seam; four example scripts de-credentialed; a four-pin receipt suite (FID-id path, T67-guarded against vendored
stale copies) pins the deletions. The loop-2 audit caught the residue the bulk stages left (common env reads, sdk
env orphans + the child-shell allowlist entry, the e2e credential seam, 29 dead-local lint warnings) and closed it
with direct file edits. Gates: typecheck 13 legs 0 errors; sdk 529/0; cli 3746/0; agent-runtime 1551/0; common
723/0; eslint --max-warnings 0; lint:md; quality; scope-register; all five absence-greps clean.

Provider identity leak brand guard — the harness asserts its own identity (FID-2026-0929-001) — closed 2026-09-29 (commit bc3b31d)

On the APInex free lane (apinex/free/mimo-v2.6-pro), the agent greeted the operator as "I'm Savant V2.6 Pro, running via APInex (apinex.bond)" — a supplier-branded persona synthesized from the upstream identity instruction APInex documents for its free tier. Fix: an identity counter-clause in the shared base system prompt (agents/savant/system-prompt.ts) covering all 6 modes — the agent's name is Savant on every model and provider; never synthesize a persona from the model id; never adopt supplier/gateway branding; never volunteer infrastructure names; direct questions still get honest, brief answers. Regenerated bundle carries the clause in 13/13 savant chunks; 9-test pin (agents/savant/tests/system-prompt-identity.test.ts). Pulled from the shelved idea-shelf note at operator request; the gateway-edge response scrub remains a gateway-layer requirement for the day a free lane ships to users.

Direct-provider 402 honesty — no more phantom backend billing (FID-2026-0929-002) — closed 2026-09-29 (commit c49d388)

In direct-provider mode, a provider 402 was rewritten by isOutOfCreditsError() into "Out of credits. Please add credits at https://savant-code.com/usage" plus outOfCredits input-mode lockout — backend-branded billing for a backend that does not exist (the transcript incident). Fix: both 402 branches (handleRunCompletion, handleRunError) now gate on isDirectProviderMode(); direct mode renders the provider's own message with provider label and a /health//provider pointer via providerOutOfCreditsError() + the quotaHint seam (widened to match bare 402s); no input-mode flip, no backend usage poll. Backend mode byte-identical (its regression pin untouched and green). Full cli suite 3881/0 at implementation.

Boot-mode precedence — only the explicit env backend key defers routing (FID-2026-0929-003) — closed 2026-09-29 (commit 742f361)

A third-party diagnosis claimed the CLI booted in backend mode for lack of the DIRECT_PROVIDER pair — adjudicated claim-by-claim and largely refuted by a live names-only probe (authToken: false; activeProvider persisted; boot re-arms direct mode), but it surfaced a real unruled precedence: both boot re-arm gates were vetoed by getAuthToken(), never ruled for persisted interactive selections. Operator ruling: "we need to gut this whole 'backend' idea, we don't have a backend to fall back to." Implemented hasEnvBackendCredentials() as the one predicate boot routing may consult — true only for an explicit SAVANT_CODE_API_KEY; a stored login token is residue and defers to nothing; the stub bypass token never counts. All three boot gates re-keyed (provider-key-store.ts x2, ollama-onboarding.ts); 8 new pins. This machine's observable boot is unchanged.

Gut-the-backend stage 1 — the dead login surface deleted (FID-2026-0929-004) — closed 2026-09-29 (commit 4b54e80)

The backend login surface was dead code: the LoginModal render gate is unreachable (boot always arms DIRECT_PROVIDER, falling through to the openrouter default even on a virgin machine) and the savant-free login command dead-ended on a host with no backend. Deleted: LoginModal, LoginUrlSection, 4 login hooks, login-flow, plain-login, login-store, and 4 test suites. The misnamed cli/src/login/{constants,utils}.ts — actually the brand logo, sheen, and URL assets consumed by 8 live components — relocated to cli/src/branding/ with modal-only exports dropped. /login slash command and the login CLI argument removed; modal plumbing (requireAuth, hasInvalidCredentials, handleLoginSuccess, useLoginMutation) stripped from app.tsx, app-with-async-auth, use-auth-state, and use-auth-query. Logout and stored-token handling survive for later stages. cli workspace 3867/0 post-deletion.