Skip to content

v0.0.36

Latest

Choose a tag to compare

@savant0x savant0x released this 19 Oct 07:47
· 26 commits to main since this release

0.0.36 — 2026-10-12

v0.0.36 — development line, package release not yet published.
Verified source progress is committed and pushed to main automatically;
package publication and release tags remain separate operator actions.
This bump opens the dated heading so post-release work
accumulates in one place, per the no-unreleased-accumulators ruling: the
researcher-acceptance and lesson-feature-pipeline closures, the managed
scratchpad and provider-inventory passes, and everything else that lands before
the v0.0.36 cut. Release notes are written here at cut time; nothing in this
section is a package-release claim until then.

Release-audit closures (closed 2026-10-19)

  • FID-2026-1018-010 — low — Preserve clickable child identity. The shared
    clickable normalizer scopes React child identity with React.Children.toArray
    before flattening, so static Button/CommandPalette and FollowupLine
    siblings stop reporting missing unique keys while explicit keys inside nested
    arrays stay distinct. Host children stay non-selectable and no fragment is
    introduced. Implementation: 0c50fa8e; focused suite 5 pass / 0 fail, CLI
    typecheck and scoped ESLint clean.
  • FID-2026-1018-011 — medium — Bound shared UI event subscriptions. Renderer
    resize/focus/blur and ancestor scrollbar change now share one native
    subscription per emitter and event, with independent consumer tokens; dispatch
    snapshots its initial subscribers, skips removals and postpones additions, and
    the native listener is released with its last subscriber. Thirty real animation
    consumers keep their resize/focus behavior and return to baseline listener
    counts across three mount/unmount cycles. Implementation: 106ee6f8; 5 pass /
    0 fail, 41 assertions. No operator-terminal observation is claimed by the
    native render tests; LIVE-004's warning residuals stay tracked separately.
  • FID-2026-1018-013 — medium — Audit lifecycle and tooling hygiene. Standalone
    probes execute only at their entrypoints, the console-capture and
    exit-provenance diagnostic resets are wired into the CLI preload, and
    object/native-FFI state carries exact self-validating lifetime exemptions
    instead of a global audit suppression. Skill-evolution output moved under the
    managed scratchpad active tree, audit-evidence tests run from their own
    workspace, and two stale exact ledger-size pins became the audited minimums
    they already described. Implementation: 20b2f55c; scripts suite 1,122 pass /
    0 fail.
  • FID-2026-1018-014 — high — Dependency advisories and unused packages.
    Removed seven unused backend/native packages, upgraded vulnerable direct and
    transitive pins, kept the compatible Zod 4.4.3 pin, adopted the
    ESLint-9-supported typescript-eslint line while preserving the prior
    catch-binding policy, and replaced two type-only runtime schemas with static
    types. Persisted Bun patches bound the braces parser depth at 128 and map
    gray-matter's YAML-4 engine names; a durable hostile-input probe now runs first
    in the pristine-install bundle gate. The registry audit fell from 25 affected
    names to one patched braces@3.0.3 finding with no upstream fix — mitigation,
    not a zero-advisory claim — and the SDK distribution stays unpublished.
    Implementation: 60c50a67.
  • FID-2026-1018-012 — medium — Release-audit reconciliation. Current docs now
    match shipped behavior: the wheel/scrollbar picker claims that the allocator
    repair removed are corrected, SDK installation is described as source-pinned
    while its distribution stays unpublished, the scaffold examples are named with
    their real consumer, and the ignored local dev links were replaced with
    reachable sources. Archived records gained machine-readable commit evidence,
    the configured recovery destination is reported instead of an unobserved
    "OneDrive-synced" claim, and SCOPE.md was reconciled with the closed children.
    The 0.0.36 heading moved above its own recent entries as a byte-identical
    relocation, so extractChangelogSection no longer drops the newest picker,
    worktree and provider notes from generated release text. Implementation:
    789ec02c.

Committed slices re-ran the hard gates: 14-workspace plus scripts typecheck exit
0, CLI 4,233 pass / 18 skip / 0 fail, scripts 1,122 pass / 0 fail, ESLint 0
warnings, Markdown lint exit 0, validate:repository PASS.

Session-summary month organization (closed 2026-10-19)

  • FID-2026-1019-001 — low — Group session summaries by month automatically.
    dev/session-summaries/ held 367 dated artifacts (22 in 2026-07, 93 in
    2026-08, 78 in 2026-09, 174 in 2026-10) in one flat directory. The SessionEnd
    review now moves every dated root-level file into its YYYY-MM/ bucket —
    canonical YYYY-MM-DD-* names and the pre-convention YYYY-MMDD-* shape
    alike, and dated logs/screenshots with them — without renaming or rewriting
    one byte. Planning is pure, so --check and --dry-run report exactly what
    the apply path does; an existing destination is reported and never
    overwritten; a second run is a no-op; the step fails open so organization can
    never break the review. Records that cite a summary by its old flat path
    (LIVE-003 evidence, the canonical learning rules, LF-005, live docs) still
    resolve through a directory-scoped fallback, so historical citations were not
    rewritten. The 12 summaries tracked in git moved as 100% renames. Gates: 13
    unit tests pass, scripts suite 1,135 pass / 0 fail, scripts typecheck and
    ESLint clean, validate:repository PASS (six pre-fix reference failures
    gone), and a probe summary was grouped by a real SessionEnd run.
    Implementation: 53c270da.

Repository hygiene and docs/data parity (closed 2026-10-18)

  • FID-2026-1018-007 — medium — Audit storage and reconcile current guidance.
    Corrected README development callouts, SDK/local-agent examples and API docs,
    testing guidance, malformed/dead links and design-generator version metadata.
    Preserved old scope history outside the active register and untracked a
    174,027-byte regenerable Sigma intermediate while keeping its local copy.
    Audit: docs/reports/repository-hygiene-audit-2026-10-18.md.
    Implementation: 463d8096; 11/11 declared gates and SDK build pass; all 166
    JSON-family files validate with their domain parsers, all 74 design resources
    pass production integrity checks, and current-doc link checks pass. Large
    ignored reference/dependency trees stay; external-home diagnostics remain
    operator-owned. This is source progress, not a release or publication claim.

2026-10-19 — Stop /model from blanking the CLI (FID-2026-1018-008, critical)

Opening the model picker emptied the screen while the process kept running and
painting frames. The console channel was blocked: OpenTUI replaces
console.error during activation, so the failure text went to an overlay the
app never opens. Re-wrapping console capture on top of OpenTUI named it —
mounting 4,075 native rows returned null from createTextBuffer, React threw
in completeWork, the error boundary's <text> fallback failed identically,
and React unmounted the root. The picker now mounts only the window
getPickerViewport already computes. Measured with a new dwell probe on the
real catalog: before, the picker never appeared and render-tree-empty fired at
8 s; after, it opens, survives a 26 s dwell, and the session quits through its
normal exit path at 408 MB. Implementation: 24cf1bae. Operator acceptance
(LIVE-004): five /model opens on the same catalog during a live session with
three bashers running, none blanked, no render-tree-empty and no
TextBuffer failure recorded.

2026-10-18 — Credit a windowed boot read that reached EOF (FID-2026-1018-009, high)

A read_files call that carried limit earned no grounding credit even when
the whole file came back: limit: 2000 on the 923-line ECHO.md was read as a
partial window, so the required harness grounding set never completed, the
completion gate blocked three times, disarmed, and the turn ended with no tool
call. Credit now follows the window's effect — an offset past line 1 is
always partial, and a limit is partial only when the response used it up.
Three suites pass (27 tests), typecheck, ESLint, Prettier, Markdown lint and
validate:repository are clean. Implementation: 59d6226f.

2026-10-18 — Clarify worktree busy-lock recovery (FID-2026-1018-006, low)

Busy advice now requires confirming no live lifecycle writer remains before
removing a confirmed abandoned, empty lock. An empty directory does not prove
abandonment. Lock behavior stays fail-closed; the existing suite checks advice
and preservation of empty/populated locks. Implementation: a9413a69;
3/3 declared gates, scoped Prettier and SDK build pass.

2026-10-18 — Validate worktree acceptance artifacts (FID-2026-1018-005, medium)

The instrument now wraps its proof, lints before commit and after merge,
uses a covered tracked-file change for discard, names shells for lock steps,
and reconciles unique-row counts. Run-4 report and qualified assessment are
preserved durably. Implementation: 72aefe15; 2/2 declared gates and Markdown
lint pass. Future runs require a new authorized active converged vehicle.

2026-10-18 — Accept the demonstrated live lane lifecycle (FID-2026-1017-008, low)

Run 4 demonstrated create, isolation, scoped writes/refusals, fast-forward merge,
first-attempt graph refresh, dirty refusal, explicit discard and busy refusal.
Proof merged as a99db5b8; MD013 repaired as e0d29fb0. All 15 acceptance
gates pass. The report's 34-PASS headline conflicts with 43 PASS table labels
and one substituted SKIP. The covered-file substitution and extra repair commit
remain explicit deviations; closure does not certify unchanged-instrument
conformance or the declared untested live paths. Retained branch/stash preserved.

2026-10-18 — Repeatable parallel-worktree acceptance preconditions (FID-2026-1018-004, medium)

Run 3 reached the live tool but used an already tracked proof, so the lane
stayed clean and disposal correctly succeeded. The next instrument uses a
run-unique proof with a matching scope grant and exact graph lookup, requires
observed dirtiness before refusal tests, checks both checkout states and refs
immediately before merge, and requires exclusive main access. Reports go under
scratch active. Retained branch/stash stay intact; preparation documents a
separately approved normal branch fast-forward when ancestry permits it.

Implementation: 59a0c0e5; 2/2 declared gates and scoped markdownlint pass,
with positive/negative read-only graph controls. Run 3's report/FID handoff is
preserved. Run 4 has not run; FID-2026-1017-008 remains converged and unaccepted.

2026-10-18 — Keep the model picker stable during agent updates (FID-2026-1018-003, high)

The model picker revisited the entire catalog on unchanged parent updates.
React memo now skips that work while changed queries, catalogs, selection and
store subscriptions remain live. The native regression failed before repair
and passes afterwards; existing keyboard, mouse, resize and open tests pass.
Implementation: dd57660c. Verification: 5/5 declared gates exit 0.

The reported blank screen with three active bashers was not reproduced. This
repair reduces confirmed render load; it does not establish the incident's
cause or certify live recovery. Initial mount still allocates the full catalog.
Original incident acceptance remains tracked as LIVE-003.

2026-10-18 — Worktree results use traffic-light chrome (FID-2026-1018-002, low)

fid_worktree was absent from the CLI renderer registry and fell through to
the generic tool block. It now reuses the existing structured traffic-light
panel through loading, results, refusals, folding and empty output. Native
ToolBranch coverage exercises all four actions and narrow width without
performing lifecycle mutations. Implementation: 50f5877f. Verification:
4/4 declared gates exit 0; the related MCP native fixture also passes.

2026-10-18 — Document that Zylo's catalog needs no key (FID-2026-1018-001, low)

The SDK environment reference annotated the BlazeRail and River keys but not
ZYLO_API_KEY, which hid the one property that distinguishes it: the live
catalog is fetched publicly and the key authenticates inference only. The
reference now says so beside the variable, naming
https://api.zyloai.net/v1. Generated artifacts are untouched — the provider
doc generator reports all four unchanged.

Implementation: 00fa0959. Verification: 3/3 declared gates (provider-doc drift
probe, registry setup suite, quality), markdownlint and Prettier pass.

2026-10-17 — Add Zylo AI as a text-only public gateway (FID-2026-1017-016, medium)

Zylo is available through /provider zylo with ZYLO_API_KEY and
OpenAI-compatible chat at https://api.zyloai.net/v1. Its catalog is
keyless: the public /models roster supplies all 126 text rows, including
sparse capability metadata, while image and custom sub-model arrays are
excluded. Every published row keeps a positive finite window, the fetch sends no
Authorization header, and the provider takes ladder slot 18 ahead of the custom
tail. The census is preserved in docs/reports/zylo-provider-live-check.md.
Plan entitlement and live inference were not obtained and are tracked as an
internal follow-up, so no access claim is made.

Implementation: e22c06bf. Verification: 10/10 declared gates pass; full
repository test chain, typecheck, ESLint, markdownlint, Prettier and repository
validation pass.

2026-10-17 — Add River AI as an authenticated gateway (FID-2026-1017-015, medium)

River is available through /provider river with RIVER_AI_API_KEY and
OpenAI-compatible chat at https://api.river.ai/v1. Its live catalog is the
account's own model list, kept with exact upstream IDs under the river/
routing prefix; the three documented 1,048,576-token windows are pinned and
undocumented windows stay unknown rather than invented. Exception ownership,
window coverage, fan-out, cache reset, setup/SDK contracts and generated docs
ship in the same change, at ladder slot 17. The identity gauntlet remained
inconclusive, so route reachability is reported without an identity claim.

Implementation: e22c06bf. Verification: 12/12 declared gates pass; full
repository test chain, typecheck, ESLint, markdownlint, Prettier and repository
validation pass.

2026-10-17 — fid_worktree is callable again (FID-2026-1017-014, high)

The second parallel-worktree acceptance run could not invoke the tool: every
call was refused before dispatch with invalid_union. fid_worktree was the
only tool whose parameter schema had a discriminated union at the root, and the
AI SDK serializes that as { oneOf: [...] } — no top-level type: 'object',
no properties. The provider therefore advertised no fields, the model emitted
{}, and the runtime correctly rejected it. The schema is now one flat strict
object (action enum, optional fid_id / discard_changes) with the
per-action rules in superRefine, which never reaches the wire schema. Every
refusal the union encoded is preserved: unknown keys, missing fid_id,
discard_changes outside dispose, malformed ids. A new class guard fails any
tool whose provider-facing root is not an object, so this shape cannot return.

Implementation: 0dad50e5. Verification: 6/6 declared gates (params suite,
object-root guard, agent-runtime tool and provision suites, real-git probe,
quality), dispose/merge/environment suites, root typecheck, ESLint and
markdownlint all pass. The live lane lifecycle is still unexercised — the third
A–Z run is the acceptance step.

2026-10-18 — Add BlazeRail as a built-in gateway (FID-2026-1017-013, medium)

BlazeRail is available through /provider blazerail with the registry-managed
BLAZERAIL_API_KEY and OpenAI-compatible chat at https://api.blazerail.com/v1.
The public catalog supplies 183 filtered chat/coding rows; media rows are
excluded, published windows/output limits/pricing are retained, and unknown
windows stay unknown. Tests confirm exact upstream namespaces and :free /
:nitro suffixes remain intact. No key or inference request was used, so account
authentication and live model acceptance remain unverified.

Implementation: 8741613e. Verification: all 10 declared FID gates pass; full
repository typecheck and test chains pass, along with ESLint, markdownlint,
Prettier, repository validation, provider-doc drift and quality checks.

2026-10-17 — Parallel acceptance run is repeatable (FID-2026-1017-012, high)

The unsafe-root guard could not tell "git never ran" from "git reports another
root": both refused with the same message, and 3 of 18 live lifecycle calls were
refused in the acceptance run. The guard now retries once only when the process
could not run (status: null); a reported root must still match, and a non-zero
status still fails closed. The A–Z instrument is corrected for the four
divergences its own run recorded (empty baseline, force-added FID record,
schema-first invalid-id refusal, dispose recovery warning), and a paste-ready
video draft is exempted from MD013 so the mandatory lint gate runs again.

Implementation: 4f989510. Verification: 5/5 declared gates (agent-runtime
typecheck, tool suite 7/7, provision suite 5/5, real-git probe, quality), ESLint
0 warnings, markdownlint exit 0, repository validation PASS. Lane prep: the
contained stale branch was deleted and the blueprint stashed for restoration
after the run.

2026-10-17 — Post-merge graph refresh survives real assets (FID-2026-1017-011, high)

The parallel-worktree merge landed but its main-graph refresh threw, so the
merged file stayed out of .savant/graph.db until an operator ran
/graph refresh. Two defects were reproduced in sequence. First, the index
scan applied the 1 MB cap to the UTF-8-decoded string: invalid bytes decode to
U+FFFD (three bytes each), so four tracked assets under 900 KB on disk expanded
past the cap and aborted the scan. Second, the write phase collided on
file_extends (file_id, parent) because one file may declare several children
extending the same parent; six tracked files do exactly that. The cap now
governs on-disk bytes only, and extends relations dedupe by parent to match the
persisted key. Two regression fixtures were added; the live refresh completes
in 8,894 ms and the merged lane proof is present in the graph.

Implementation: 774eb705. Verification: fid:verify ran 7/7 declared gates
with exit 0 (knowledge-graph and agent-runtime typechecks, refresh-safety,
edges-from-tokens, fid-worktree-environment, the real-git lane probe, and
quality). The open BLOCKER-2 from the FID-2026-1017-008 live acceptance run is
repaired; that run's own record still awaits the operator re-run.

2026-10-17 — Coding-focused free options (FID-2026-1017-010, high)

Boot and /provider free now share purpose, expiry and duplicate filtering.
Specialist model tasks, unrelated offer categories, expired/unresolved deadlines
and unsafe offer links stay in the broad discovery report. Structured text/tool
metadata survives cache round trips; missing metadata remains explicitly
unverified. Correct the existing VL-name boundary for whitespace and :free.

Expanded boot output and Copy share a preview capped at five models per provider
and five offers, while header counts retain the complete selected totals and
filtered reasons. The artifact retains the full discovery evidence and hash
contract. Implementation: cc0c2913; ten declared gates pass, with native-render
coverage, 78 focused tests, CLI typecheck and SDK build. No live capability,
quality-ranking or account-quota verification is claimed.

2026-10-17 — Preserve dependencies during lane disposal (FID-2026-1017-009, critical)

Windows Git follows dependency junctions during worktree removal and can delete
main-checkout package files. Detach symbolic links and junctions without following
their targets before recursive lane teardown; refuse cleanup if detachment fails.
The protection also covers recordless cleanup and initialization rollback.

Implementation: ab021ebf. Four new regressions reproduce the original failure
and pass after repair; the combined lifecycle suites pass 19 tests. All six FID
gates, full root typecheck and SDK build pass. Restored the local installation
from the unchanged frozen lockfile and verified CLI help starts successfully.

2026-10-17 — FID-bound parallel worktrees (FID-2026-1017-007, high)

Complete the eight-step worktree feature: lane-local Law 2 scope with validated
git registration and symlink containment, an Orchestrator-only fid_worktree
tool, clean fast-forward integration with conflict/divergence refusals, stable
execution slots and isolated command environments, WAL-aware graph snapshots,
post-merge graph refresh, orphan reporting and the shared operator CLI. Child
commands retain the SDK environment allowlist. Lane selection is explicit;
conflicts are never resolved automatically and no speedup is claimed.

Implementation: 11dd667d, following the lifecycle foundation at 7618b5b4.
All 15 declared FID gates pass, including the two-lane real-git/SQLite probe;
the full root test chain, root typecheck, SDK build and repository checks pass.
The operator guide is docs/design/parallel-worktrees.md. The source/built
ripgrep regression pins also check the resolved binary's SHA-256, so building
the SDK no longer creates a false gate failure.

FID closure and archive: dc2953f0. Session-end review completed; the final
verification and closure record is
dev/session-summaries/2026-10-17-fid-worktrees-completion.md.

2026-10-17 — Boot free-options panel renders natively (FID-2026-1017-006, high)

Every boot replaced the free-options panel with the transcript error fallback
— "This content could not be displayed. Your session is still active." —
followed by the block serialized as raw JSON. The panel opened
TrafficLightPanel with a literal {' '} string child; OpenTUI's reconciler
rejects text outside a <text> node, so FreeOptionsPanel threw
Text must be created inside of a text node and the boundary printed
JSON.stringify(blocks) as its preview. The spacer is gone; the panel mounts
on the reconciler that actually renders it.

The suite shipped with FID-2026-1017-005 could not see the defect because it
renders through react-dom/server, where box and text are custom elements
and host invariants are not enforced. A native-render suite now mounts the
panel collapsed and expanded on @opentui/core/testing and rejects the
fallback, the serialized block and a missing header — proven red with the
child restored (2 fail) and green without it (2 pass). The operator's real
cached report (146 models on 3 wired lanes, 2 not-wired tiers, 1 local lane,
223 offers) was also mounted natively at 120 columns in both states: header,
counts and every expanded section rendered with no fallback and no raw JSON.

Implementation: 907e04f8. Verification: fid:verify ran all 5 declared
gates with exit 0 (typecheck cli, both panel suites, the collapse suite,
quality); static panel and collapse suites 15 pass / 0 fail.

2026-10-17 — Fresh, complete free-options boot panel (FID-2026-1017-005, medium)

The boot digest was reading the free-options cache synchronously before the
provider refresh it depended on had run, so an expired boot showed expired
values; it then printed two offer titles and pointed at free-options.md by
bare filename. It is replaced by a TrafficLightPanel transcript block that
resolves freshness before posting: a cache no older than 12 h is shown with its
exact age, an older or absent cache gets one bounded refresh (6 s over the
existing 5 s fetch timeout) through the existing single-flight, and a failed
refresh serves the cache labelled STALE instead of current. The panel is
collapsed by default and expands to every wired and not-wired model id, every
local lane and every advertised offer.

The panel, the markdown export and /provider free now derive from one
buildFreeOptionsView, so their counts and payloads cannot diverge. The
artifact carries its resolved path, generatedAt, fetchedAt and a body hash;
the boot reader verifies path, catalog vintage and hash, and a copy in another
config directory is rejected. A failed export is returned and rendered in both
the panel and the command instead of being swallowed on the false premise that
the command output was already complete, and the command names the resolved
absolute path rather than a bare filename.

Implementation: 33a58d63, plus 7db948bd for fail-silent boot setup.
Verification: fid:verify ran all 10 declared
gates with exit 0 (cli typecheck; the boot, view, panel, collapse and renderer
suites, 62 pass / 0 fail; the durable boot-artifact probe; the scripts
typecheck probe; quality); the full CLI suite is 4174 pass / 28 skip / 0 fail,
the root typecheck is exit 0, and validate:repository passes. No live TUI
smoke ran because tmux is not installed in this environment; the boot path is
pinned at the resolver/handler boundary and the panel through a static render.

2026-10-17 — Bounded research spawn contract (FID-2026-1017-004, medium)

spawn_agents now accepts an optional typed research plan and enforces it on
the production path. A plan pins the objective, turn identity, captured source
bytes and snapshot digest, per-step sources and dependency edges, and an output
ceiling. Validation is all-or-nothing against real bytes; dependency stages run
in order behind the existing aggregate barrier; the host injects each
predecessor artifact and accepts a step only on verified read_files bytes and
that exact artifact's presence in the child history. Plan steps are read-only
research roles, so implementation, audit and effectful roles are refused before
dispatch, and a stale turn or an over-budget ceiling is refused too. Rejected
and cancelled steps report an explicit error and keep the credits they spent.
Spawns without a plan keep the previous behavior, partial filtering included.

Implementation: 267be888, plus a follow-up that forwards the plan's output
ceiling into every child request (the tighter of the plan ceiling and the run
budget applies). Verification: fid:verify ran all eight declared
gates (typecheck common and packages/agent-runtime, the three plan suites, the
deterministic probe, the scripts-tree typecheck probe, quality) with exit 0;
the full agent-runtime suite is 2218 pass / 0 fail. The plan's source contract
covers local files only; web sources and nested plan descendants remain outside
it, and no latency, reliability or monetary claim is made.

2026-10-17 — Bounded research workflow selection (FID-2026-1017-003, low)

Added equal-final-brief comparisons for consolidated investigation, independent
fan-out and the dependent research chain. Real Apixo gpt-6.1-sol results:
41.230 s / one send, 90.202 s / four, and 91.603 s / four, respectively. All
selected evidence checks passed; the fastest draft was rejected semantically
for proposing that stale costs be ignored. Fan-out's timing difference is
inconclusive. Actual tool-result bytes are now required for every assigned
source, rather than attempted read paths alone. Twenty-five controls pass.

Executed two fresh draft/review trials after the operator authorized four
additional sends: 89.142 s and 63.511 s, two sends each, all source-read/handoff
checks passing. Review retained cost and mandatory-review constraints, but
residual parent-overlap and Forge-for-research proposals prevent blind semantic
acceptance. Selected a host-enforced bounded research contract and documented
the product integration/acceptance map in docs/design/parallel-workflow-decision.md.
Research implementation/evidence commits: bfcb3640, e0f113a5; seven declared
gates pass. FID closed and archived; scope released. The cumulative 64-request
ceiling is exhausted. Closure covers research and the executable prototype;
no production installation, general speedup or monetary saving is claimed.

2026-10-17 — Validated parallel handoffs (FID-2026-1017-002, low)

The isolated research scheduler now validates a complete returned wave before
publishing results or releasing dependencies. Host-issued source references bind
exact citation locations/text; predecessor digests come from actual handoffs.
Downstream reviewers receive predecessor source files. Raw drafts and rejected
mode outcomes are retained. Implementation: 0292beba; six FID gates pass,
including 19 control tests / 87 assertions.

A real Apixo gpt-6.1-sol pair completed with zero selected citation/handoff
failures: batch 96.997 s, completion 89.762 s, four inference sends each. Exact
predecessor artifacts reached the appropriate downstream histories. B finished
before A in both modes, so there was no useful overlap or demonstrated speedup.
An intermediate five-send pair rejected altered quotes before publication.
Cumulative sends are 51/60; nine unused. Mechanical consistency does not establish
semantic correctness or production async readiness. Details and next candidate:
docs/design/parallel-agent-slice.md. No production migration or release.

2026-10-17 — Live parallel-agent research slice (FID-2026-1017-001, low)

Added an isolated executable comparison using the actual SDK, spawn handler,
source-read tools, Apixo gpt-6.1-sol, and experiment-owned SQLite. The store
checks duplicate delivery, transactional consumption, cancellation generations,
and interrupted attempts; transport caps actual sends and holds concurrency
permits through stream completion. Five declared gates pass, including ten
control tests. Implementation: 8244dc9c.

Both real four-task schedules completed: batch 233.895 s, completion 166.292 s,
four inference sends each. B finished before A in both modes, leaving no
early-release opportunity; the timing difference establishes no scheduling gain.
Batch failed 13 quotation checks; completion failed seven quotation checks and
one exact handoff digest. The report retains those failures. The runner now
returns a failing exit status for failed evidence after preserving both modes.
Total inference use, including earlier upstream failures: 38 of 60 permitted
sends. No measured dollar cost or production-readiness claim is made.
Reproduction, results, and limitations: docs/design/parallel-agent-slice.md.

2026-10-17 — The trusted skill catalog and its trigger cases are reconciled (FID-2026-1016-019, medium)

Five failures in the evals lane were pre-existing but sat inside the pre-push test chain, so they refused
the FID-018 delivery. Three trusted skills had shipped (FID-2026-1016-015 lane) without a trigger case
file; release-workflow's case still pinned the pre-rewrite description hash; and the quarantined-drafts
assertion required draftCount > 0 although the operator ruling deliberately emptied .quarantine/.
This change authors the three case files with behavioral rubric items, re-pins the intentional description
hash, and restates the draft rule as a contract (drafts, when present, are advisory — never a CI error)
instead of a catalog-state expectation. Verification: fid:verify receipt 6/6 PASS, evals lane 229 pass /
0 fail, eslint and prettier clean; commit 8d735d34. Prettier-only formatting also lands on four files.

2026-10-17 — Ashna joins the built-in registry as a keyed live gateway (FID-2026-1016-018, medium)

ashna.ai is now a first-class provider end to end. Live probes measured the
vendor contract (keyed-only catalog — 401 keyless, 200 authenticated, 104 rows
with no window or name fields, roster moving between probes) and a plan-gated
inference leg (429, envelope recorded verbatim in the FID; unblocks with zero
code changes on a paid plan). The change adds the registry entry (openai
protocol, strip transform, order: 4), the keyed parser wrapper with local
retrieval/image exclusions (78 of 104 retained), the 17-slot settled-ladder
fan-out + merge spread + reset seam, the table-section window registration
with 28 cross-gateway consensus rows and 50 documented no-row ids, the
live-catalog manifest owner, derivation legs, generated + hand doc surfaces,
and the census regen (ashna: 78). Verification: fid:verify receipt 17/17
PASS; full suites common 912/0, cli 4147/0, sdk 719/0; probes reconciled;
commit cc544ea3.

2026-10-17 — Acceptance is recorded per run, and every rule's authority reference is resolved (FID-2026-1016-016, FID-2026-1016-017, medium)

The second ruling round selected both unselected lesson features. They shipped in one commit
(ec60a108) but under two records, because the feature register admits one owning FID per
candidate — LF-005 and LF-006 could not share an owner, and the register said so rather than letting a
merged record imply otherwise.

Added

  • Acceptance is now an artifact, not an inference from tool success (LF-005). Every tool call in a
    run can return while the feature is still broken for a person: the report confirms a command exited,
    never that the terminal rendered, that resize reflowed, that the transcript folded, that an export kept
    its last row, or that a resumed session showed what it claimed. Regression tests do not close that gap
    either — cli/src/components/__tests__/transcript-recovery.render.test.tsx proves the deliberate-error
    path, a different claim from "this run behaved for a human". Acceptance is therefore a run-bound record
    at dev/tracking/acceptance/<runId>.json, built from a template that claims nothing
    (bun run acceptance:check --template <runId> <sessionId>) and read back by bun run acceptance:check
    (scripts/production-acceptance.ts, scripts/acceptance-check.ts, docs/production-acceptance.md).
    Each of the five UI surfaces — resize, input-responsiveness, folding, copy-export,
    resumed-history — carries exactly one outcome, so no aggregate "it works" stands in for a surface
    nobody looked at; a claimed outcome carries its observation and resolvable evidence; unverified
    carries no observation at all, which is what keeps the word honest; a record with any claimed surface
    must contain at least one operator/native check; automatedRegression entries must name a test file that
    exists; runId must match the file name; and sessionId + callLedger bind the record to the ledger
    holding that run's failures and fallback steps. validate:repository runs the same collector, so a
    malformed record fails the repository gate.

Changed

  • The canonical rule catalog is re-resolved against the tree (LF-006). dev/LEARNING-RULES.md names,
    for each rule, the artifact that authorizes it and the check that validates it — and nothing resolved
    those references, so a boot rule could keep citing a deleted file or a FID that never existed. A dead
    artifact or FID reference is now an error in a current (boot/reference) rule and a warning in
    a historical one; that asymmetry is the visible distinction between dated guidance and current
    authority, and hiding the historical case would have thrown the information away while failing it would
    have treated history as policy. A rule whose tier disagrees with the status of its linked lessons is
    refused in both directions, and rules with no linked lesson are deliberately not judged (23 of the 35
    real rules). Measured before wiring: 62 artifact and FID references across those 35 rules, 0 dead, so
    the check fails only on real decay (scripts/learnings-staleness.ts, wired into bun run learnings:check).
  • Admission refuses to re-implement what an implemented candidate already owns. The register already
    refused an identity collision and an FID shared between two candidates, but a new candidate with a
    new identity and a new FID naming the same work passed every check. Titles are now compared
    normalized against the implemented archive and the refusal names the owner
    (scripts/lesson-feature-admission.ts). Stated as a boundary rather than a guarantee: a title rule is a
    detection floor, not a proof of non-duplication — a duplicate worded differently still passes.

Notes

  • The LF-006 record exists separately from the LF-005/LF-006 authoring record for the reason above, and
    carries its own stamped receipt over the same implementation commit.

2026-10-17 — Skill drafts carry the lesson, four drafts trusted, the live-comparison item retired (FID-2026-1016-015, medium)

Changed

  • Auto-drafted skills now teach the lesson instead of the failure message. Before trusting the four
    quarantined drafts the operator ruled on, reading them showed that
    library-complete-needs-a-named-consumer contained no lesson at all: its description was read_files'
    error string sliced at 60 characters (…retry the tool cal) and its Procedure was its own name. The
    drafter in scripts/lessons-to-skills.ts built every draft from the recurrence row — description and
    "When to Use" from the error text, Procedure from the canonical rule's slug — while its own comment
    already claimed it carried "the candidate's REAL content … the actual lesson". The lesson's invariant
    and guard were parsed and then dropped, so they never reached the isolated drafting turn either
    (CandidateHandoffInput had no fields for them). They now travel candidate → proposal payload → drafting
    prompt → draft body, and descriptions come from the rule, clipped at a word boundary under the
    60-character agent-authored cap (the cap is why the old code sliced, and slicing is what cut the word in
    half).
  • One lesson yields one candidate. findCandidates emitted one candidate per recurrence ROW, so a
    single lesson reached the draft path as six proposals with fragmented counts (48×, 27×, 25×, 21×, 14×,
    11×) and six payload hashes — which is also why the store's documented one-proposal-per-session contract
    had never been exercised there: nothing looked like a second proposal. Counts now aggregate onto the rule
    and distinctSessions stays the strongest single row's figure, because summing sessions would inflate the
    promotion gate's own number.
  • All four quarantined drafts are trusted (operator ruling). release-workflow 0.1.0 → 0.3.0 (no
    baseline pin, so trusted without drift verification — stated in the result rather than implied),
    minisign-pubkey-vs-secret-key v0.1.1, fid-gates-unfenced-parser-contract v0.1.1 and
    library-complete-needs-a-named-consumer v0.1.0, each with a trust entry in its VERSIONS.jsonl and
    its reason naming the ruling. .agents/skills/.quarantine/ is now empty. The corrupt draft was
    re-authored from dev/LEARNINGS.md first, with its invariant, its two-step guard and Law 4 verification;
    the pipeline cannot regenerate it, because that lesson's rule is deliberately unmapped from any failure
    class (it is about FID closures, not a tool failure), and findCandidates returns 0 against this tree.

Retired

  • LIVE-001 closed NOT-PLANNED (operator ruling). Live provider comparisons are not planned: no paid
    run happened, nothing was measured, and no comparison result is claimed — retiring the item is not
    evidence of one. Reopening needs a future ruling that names the comparison references and numeric
    call/spending limits. Recorded in SCOPE.md and in the follow-up store whose status vocabulary has only
    open/completed, so the disposition is spelled out in the summary rather than left to a status word.

2026-10-16 — Operator-ruled follow-ups: the Step-4 surface mounted, one robot design stated (FID-2026-1016-014, low)

Operator rulings on all nine open questions from the entry below, and their implementation.

Changed

  • The skill-lifecycle traffic-light notice is mounted. FID-2026-1005-003 Step 4 wrote
    cli/src/components/skill-lifecycle-notice.tsx and listed it as a CLI consumer, but nothing
    rendered it — a mechanically created draft appeared only in session-end:review and
    /skills activity, so the declared surface and the mounted surface disagreed. It now renders in
    cli/src/chat/panels.tsx, in the ghost-message slot whose contract it shares: an empty row when
    this surface has no unseen event, acknowledgement only after the render commits (at-least-once
    replay on a crash), no raw tool or model prose (validated metadata fields only). The new suite
    proves the render and pins the mount site, because the defect was an unwired component that
    every unit test passed on.
  • The office cast states one design: CAST_MODEL_URLS plus castModelUrlForPad (a rotation
    over a single model after the duplicate was removed) is now the CAST_MODEL_URL constant, and
    the orchestrator's "other model" offset is gone — Savant reads as distinct through its 1.55×
    height and role accent. A genuinely different CC0 model would come with its own licence row in
    ASSET-MANIFEST.md, as a new record.
  • Three hand-run probes moved to the documented durable probes home, scripts/probes/:
    desktop-cargo-test-probe.ts, learnings-prefix-probe.ts, learnings-truncation-probe.ts
    (the cargo probe's crate resolution climbed one directory; the dev/LEARNINGS.md citations were
    updated with it). scripts/orphan-sweep.ts now names scripts/probes/** as an exclusion class
    with its reason in the header — a probe is invoked by hand and cited from the untracked dev/
    records, so "no mentioner" is not evidence there — and its advisory report drops from 17
    candidates to 6
    , all of which are convention-loaded fixtures, examples or smoke assets that are
    deliberately retained.

Removed

  • coding-standards/x402.md — the changelog already recorded its deletion (FID-2026-0717-003,
    "agent payment standard, belongs in Savant core"); the file was still present. Removing it executes
    that record rather than re-litigating it.

Deliberately unchanged (operator rulings, recorded so they are not re-opened)

  • The other quality: keys (max_function_lines, max_complexity, max_line_length, max_params,
    max_comment_density, max_nesting_depth) stay advisory; only max_file_lines is gated.
  • Both copies of the language standards stay (coding-standards/*.md and
    .agents/skills/coding-*/SKILL.md); they agree on the enforced ceiling, which is single-sourced
    from protocol.config.yaml.
  • WINDOWS.md's Issue #NNN links stay marked unverified rather than presented as checked.
  • website/index.html and the two untracked operator files stay where they are — the operator:
    "they are the official website design files being kept in the repo".

2026-10-16 — One tracked file-length ceiling, the duplicate robot model removed, 19 dead files triaged out (FID-2026-1016-013, medium)

Changed

  • The file-length ceiling is one tracked number (operator ruling: 400 for every language). It was
    read from the untracked dev/quality-baseline.json (300) while protocol.config.yaml's comment
    merely claimed to own it, so the most consequential quality number in the repository was
    machine-local and unreviewable. scripts/quality-report.ts now resolves quality.max_file_lines
    from the tracked config and fails closed — a missing block, a missing value or a non-positive
    integer throws, because a ceiling nobody can see is worse than no ceiling — and the local baseline
    no longer carries the key at all, so exactly one file states the number. Measured honestly: no
    source file exceeded 300, so the old value was enforced and never bit; this change is about where the
    policy lives, not about relaxing a violated gate.
  • The per-language override tables were fiction and are now removed. Six coding-standards/*.md and
    six .agents/skills/coding-*/SKILL.md files documented overrides (csharp/go/java 350, python 400,
    rust 300, typescript 400) for a mechanism the report has never had; the TypeScript skill was the only
    one telling the truth ("no file-length exemptions"). Each now shows one honest limits table: the
    single 400 ceiling, enforced by bun run quality:report, every other setting marked advisory. The
    same correction landed in docs/adding-a-provider.md and the self-improving-architecture plan.
  • SKILL_MAX_FILE_LINES was a third real ceiling (common/src/constants/skills.ts, 300, enforced
    by skills:check on every SKILL.md). Now 400, mirrored from the config because common cannot read
    YAML at runtime, and pinned by a test (SKILL_MAX_FILE_LINES === readQualityCeiling()) so the two
    values cannot drift apart silently.
  • The duplicate robot model is gone and its attribution corrected.
    desktop/public/floor-assets/robots/robot.glb was byte-identical to RobotExpressive.glb
    (SHA-256 047f5e5f…, 463,988 B) while ASSET-MANIFEST.md credited it to the Quaternius pack — and
    both files' glTF JSON names the Khronos sample model's own meshes and clips (Foot.L, Torso,
    Idle/Dance/Wave…), so the false row was the Quaternius one. robot-cast.ts presented the pair
    as "two distinct designs" alternating across the pad ring, with Savant getting the other model from
    its specialists — a distinction that never existed visually, because the bytes were one model. The
    duplicate is deleted, ROBOT_MODEL_URL, the cast comment, the loader comment and the asset test
    follow the kept name, and the manifest now records the removal and why.
  • scripts/orphan-sweep.ts resolves two more reference spellings: the emitted-JS extension (this
    tree imports its own TypeScript as './audit-rebrand-corruption.js', so seven live modules were
    reported as orphans) and directory-relative mentions (cli/bunfig.toml → ./src/polyfills/x.ts).
    Both deliberately trade false positives for false negatives: a human deletes files from this report,
    so a missed candidate costs one stale file while a wrong one costs a deleted module.
  • The sweep now recurs: bun run session-end:review prints one advisory line (count + the command to
    run, never an exit code) and AGENTS.md documents the sweep. Measured cost 3.1 s, inside the
    SessionEnd hook's 60 s timeout. It runs from the CLI entry point, not from runSessionEndReview, so
    tests against temp roots never walk the real repository.
  • WINDOWS.md verified line by line against the source and linked from the README (it previously had
    zero inbound references outside this changelog): the bash requirement and SAVANT_CODE_GIT_BASH_PATH,
    the release-metadata failure, proxied release downloads and the update message all check out, and the
    document now says which file:line each was verified against. One claim was false — see below.

Fixed

  • WINDOWS.md documented a launcher message that does not exist. The troubleshooting section
    described Update available: error → [version] and explained error as a placeholder version; the
    launcher prints Update available: ${currentVersion || 'unknown'} → ${latestVersion}
    (cli/release-core/launcher.js:1236, :1278), so the placeholder is unknown, printed when the
    installed version cannot be read. The section now says that, and the document records the correction
    rather than quietly rewriting itself. Its Issue #NNN links were not re-checked and are marked
    unverified in the document instead of being presented as accurate.
  • 19 dead files deleted, after fixing the report that was supposed to find them. Every deletion was
    checked twice: statically against a whole-working-tree corpus scan (git-tracked files plus untracked
    dev/) using the sweep's own tokenizer, where the only mentioners were historical records
    (archived FIDs, session transcripts, baseline line-count history) or the triage probe; and
    dynamically, by typechecking and running the full suites of all four workspaces that contained them
    (cli 4140 pass, common 911, desktop 473, packages/agent-runtime 2198 — 0 failures). Deleted:
    cli/src/components/referral-quiet-line.tsx + referral-copy-button.tsx (the referral surface has
    no other mention in cli/src), cli/src/hooks/use-fingerprint.ts,
    cli/src/hooks/use-sheen-animation.tsx, cli/src/polyfills/bun-strip-ansi.ts,
    cli/src/utils/{error-messages,format-session-units,format-validation-errors-for-message}.ts,
    cli/src/utils/syntax-highlighter.tsx, common/src/constants/{grant-priorities,subscription-plans}.ts,
    common/src/util/{agent-file-utils,agent-name-normalization}.ts,
    desktop/src/components/diff/parse-diff.ts,
    packages/agent-runtime/src/find-files/custom-file-picker-config.ts (imports a module literally
    named old-constants), and four superseded ESLint fixtures (probe2.mjs, rule-test2.mjs,
    debug-ast.mjs, unknown-good.ts — the live rule tests spawn their own probe since
    FID-2026-1013-012 W3-5).
  • The local dev/quality-baseline.json had its maxFileLines key removed and 13 entries pruned for
    deleted files, so the history ledger no longer names files that do not exist.
  • README.md's Windows note now points at WINDOWS.md.

Retained on purpose (17 orphan candidates, each with a reason)

Kept because a name index cannot see the reference, and deleting them would remove a capability rather
than a liability: hand-run smoke tools and probes whose invocation is manual and/or cited as evidence
by archived FID gates and dev/LEARNINGS.md (cli/scripts/graph-smoke.ts,
cli/scripts/hud-preview-browser-check.ts, scripts/desktop-cargo-test-probe.ts,
scripts/learnings-{prefix,truncation}-probe.ts,
scripts/providers/audit-probes/t62f1-commandcode-probe.ts,
scripts/__tests__/validation-manifest.parity-probe.ts); files loaded by convention
(evals/playwright.config.ts, evals/graph-export-e2e/playwright.config.ts, the two desktop
browser-smoke fixtures, common/src/templates/initial-agents-dir/examples/*); documentation examples
shipped to be read rather than imported (sdk/examples/readme-example-1.ts); and
cli/src/components/skill-lifecycle-notice.tsx, which is a declared-but-unmounted surface from
FID-2026-1005-003 Step 4 — the CLI renders skill-lifecycle events as plain text lines, so the traffic-light
component is dead code today, but deleting it would erase the evidence that the step was declared and
never wired. That gap needs an operator decision (wire it or drop it), not a hygiene pass.

2026-10-16 — Code search resolves the pinned vendored ripgrep again (FID-2026-1016-012, high)

Fixed

  • FID-2026-1016-012 (high): resolveCodeSearchRipgrep handed getBundledRgPath its own
    import.meta.url (sdk/src/tools/code-search/executor.ts), but every vendored candidate in the
    resolver is expressed relative to native/ripgrep.ts's directory (esm-dev =
    <moduleDir>/../../vendor/ripgrep/…). From the wrong base all of them pointed at <sdk>/src/vendor/…
    and missed, so code search fell through to a cwd fallback and a spawnSync PATH probe instead of
    using the pinned binary the same module documents as "the supported configuration" with priority.
    Measured in one process with the resolver's debug sink: the correct base resolves esm-dev →
    sdk/vendor/ripgrep/x64-win32/rg.exe; the production call site resolved path-probe →
    C:\ProgramData\chocolatey\bin\rg.exe, this machine's own install. On a machine without rg on
    PATH, from-source code search failed outright; with one, it silently ran an unpinned ripgrep.
    The call site now passes no URL, so the resolver uses the base its candidates were written for and
    the vendored binary wins on the first candidate. Rejected the alternative of also trying the
    module's own URL — a candidate list correct for two different bases keeps the trap.
  • The sdk suite failure that blocked every push is resolved as a consequence, not by touching the
    test: the failing case was a symptom. With the vendored candidates skipped, each cold resolution
    ran spawnSync('where rg') under a 1000 ms timeout, and sdk/test/setup-test-isolation.ts clears
    that probe's memo in a beforeEach, so every test re-probed; under multi-file load the probe
    exceeded its timeout (observed at 1016.81 ms) and resolution threw. Suite: 714 pass / 1 fail →
    717 pass / 0 fail, and the new regression test dropped from 144.90 ms to 0.66 ms because the
    subprocess probe no longer runs.
  • The regression test was written first and observed red (Expected: true, Received: false) so it is
    known to catch the defect rather than merely agree with the fix. Three competing explanations were
    tested and refuted before the fix: a multi-file import.meta.url difference, part-c's
    child_process mock leaking into the PATH probe, and "any second test file".

2026-10-16 — Diagnostic logs are bounded, FID evidence stays durable, and the disk audit becomes repeatable (FID-2026-1016-011, medium)

Changed

  • FID-2026-1016-011 (medium): a full disk audit measured ~15.5 GiB of reclaimable artifacts against
    ~30 MB of tracked content, and found one genuinely unmanaged sink. trimOversizedChatLogs covered
    only the production per-chat log.jsonl, while the dev sinks wrote debug/cli.jsonl (45 MB) and
    debug/trace.jsonl (166 MB) with no size cap, no rotation and no production reader — 287 MB
    across three project roots. One cap constant now lives beside the paths it governs
    (cli/src/utils/logger/file-sink.ts), dev writes go through a bounded append that rotates into a
    single .1 generation, and startup reclaims oversized idle debug files beside the existing
    chat-log sweep, so each root is bounded at ~40 MiB. chat-history.ts imports the shared cap
    instead of holding a second copy (Law 13).
  • The FID template and the verification-gates module taught a scratchpad evidence path
    (- gate: probe dev/scratchpad/…) — a tree that expires 24 h after its last change and is
    untracked. Measured: 18 archived records declared scratchpad gates and 3 of 4 sampled probe
    files were already deleted by expiry
    , so those gates outlived their own evidence. The examples
    now point at the tracked probes home (scripts/probes/), the protocol bundle is regenerated, and
    scripts/hygiene.ts reports the shape as ephemeral-evidence for active records — scoped to
    active because a closed record is outside the gate contract and re-reporting history would make
    the rule permanently red.
  • The scratchpad's own rules were made true: the README.md that docs/scratchpad.md,
    common/src/util/scratchpad/scan.ts and the hygiene rule all named but that did not exist was
    created; docs/scratchpad.md and AGENTS.md now state the root shape, the 24 h expiry, the
    <session|fid-id>-<what>.<ext> naming rule and that scratch storage is never evidence; and the
    two inert .gitignore lines (dev/scratchpad/*, !dev/scratchpad/.gitkeep) were removed — git
    cannot re-include a path below an excluded parent, verified with git check-ignore -v.
  • scripts/orphan-sweep.ts makes the hand-run orphan analysis repeatable: 46 candidate files among
    4,940 tracked, reported advisory-only because a name index cannot see runtime-built references.
    Both defects found in it before it was trusted are covered by regression tests —
    extension-sensitive matching missed every extension-less import (1,339 false candidates), and
    removing a candidate's path from a shared corpus erased the references proving it was used.

Fixed

  • The scratchpad's content was pruned and its durable artifacts promoted: 71 uncited build/runner
    logs (5,529,850 B) and a stray console-output file removed, the duplicated teacher-sandbox tree
    and the 4.9 MB of session transcripts relocated to dev/research/ — after checking every
    promotion for citations, so nothing referenced was destroyed. Measured 10,544,830 B → 1,923 B.
  • sdk/examples/readme-example-2.ts failed eslint --max-warnings 0 on main (two import/order
    warnings), which rejected every push through the fail-closed pre-push hook; import order fixed,
    behaviour unchanged.
  • eslint.config.js ignores dev/research/** alongside dev/scratchpad/** — the promoted one-off
    probes and session analyses are the same class of local, untracked ad-hoc tooling.

Reclaimed

  • 302,209,052 B of stale dev debug output removed — root debug/ (86,609,790 B), cli/debug/
    (212,636,135 B) and desktop/debug/ (2,799,127 B), the three directories left by running the CLI
    from three different project roots. All gitignored runtime state, so nothing tracked was touched.
    This was step 5 of the audit and it was not executed when the record was first closed: the
    closure gate verified the nine declared gates (all green) but never checked step statuses against
    the filesystem, so the record claimed "all nine steps implemented" with step 5 unrun. A
    post-closure check found the directories still present, the step was performed, and the premature
    closure is recorded in the FID rather than quietly corrected. The .1 generations found in
    cli/debug/ are live evidence that the new rotation fired inside a real CLI run, independent of
    the unit tests.

Push sequence

This change and its governance commits were held briefly by the pre-push test gate, then pushed
once the cause was fixed — see the FID-2026-1016-012 entry above, which is the resolution of the
blocker described here as it stood at the time. --no-verify was not used at any point: the
credential scan, agent-attribution scan, ESLint, markdownlint, typecheck, the full test chain and
prettier all ran on the pushed range and passed.

Known issues (audit findings, deliberately unresolved)

dev/ is untracked by design (operator ruling 2026-10-16), so the audit's FID record is local-only
and the unresolved findings are restated here for anyone reading only the repository:

Superseded by FID-2026-1016-013 (2026-10-16) — the operator ruled on each item in this list;
the resolutions are recorded above. Kept here as the audit's own record of what it found.

  • desktop/public/floor-assets/robots/RobotExpressive.glb is byte-identical to robot.glb in
    the same directory (463,988 B, verified by md5sum), while ASSET-MANIFEST.md attributes them to
    different upstreams — Quaternius and the Khronos glTF sample models. Both are referenced
    (desktop/src/floor/office/robot-cast.ts:39-40) and both are CC0, so there is no licence exposure;
    the manifest attribution is what is wrong. Either correct the attribution or drop the duplicate
    from the cast. No file was changed. → resolved: the duplicate was dropped and the false
    Quaternius attribution removed; robot.glb was the copy.
  • coding-standards/*.md and .agents/skills/coding-*/SKILL.md have diverged into two sources of
    truth for the same standards.
    After normalising line endings the bodies differ by 18 substantive
    lines (TypeScript), and the difference is not cosmetic: coding-standards/typescript.md declares
    a max_file_lines 400 / max_function_lines 60 TypeScript override, while
    protocol.config.yaml:51-55 sets 300/50 and calls that the "LIVE quality policy — the quality
    report enforces the 300-line absolute ceiling". ECHO.md:156 says a language override wins, so
    one of the two documents would relax a live gate. ECHO.md still points at
    coding-standards/{language}.md in 8 places, and coding-standards/x402.md exists although the
    changelog records its deletion (FID-2026-0717-003). Choosing the canonical copy is a governance
    decision, so nothing was edited. → resolved: one tracked ceiling of 400, no override mechanism
    claimed anywhere, both enforcement sites aligned and pinned by test.
  • WINDOWS.md has zero inbound references outside this changelog. It reads as real product
    documentation, so deleting it needs an operator decision rather than a hygiene pass. → resolved:
    verified against the source, one stale message fixed, linked from the README.
  • The orphan sweep reports 46 candidate files among 4,940 tracked. Six were spot-checked against
    git grep; the remainder are unverified by design, which is why the sweep is advisory and exits 0.
    → resolved: two more reference-spelling defects fixed, every candidate triaged, 19 deleted and 17
    retained with a stated reason; the sweep now recurs at session end.

2026-10-16 — Advertised offer deadlines are read from the feed, and the offer dump is bounded (FID-2026-1016-010, medium)

Changed

  • FID-2026-1016-010 (medium): the free-options discovery surface reported a deadline it had
    already parsed as unknown. Every CLI consumer of an offer deadline — the display label, the
    72 h "ending soon" window and the offer-expiry inbox facts — read expiryTimestamp, a
    vestigial ISO branch written against an earlier feed shape, while the live feed emits a human
    date into expiryDate. Measured read-only against the machine's own cached feed (219 offers,
    no fetch): 0 offers carry an ISO timestamp, 12 carry a parsed date, all 219 display lines
    read "deadline unverified", and the window count was structurally 0 — so no expiry fact could
    ever be created and the list was uncountable for the operator. One shared
    resolveOfferDeadlineMs now prefers the ISO instant and otherwise resolves a date-only
    deadline to END OF DAY UTC, so an offer is never called expired on its own advertised day;
    the label, the window and the inbox facts all consume it, and the registry-host map the
    refresh loop built inline (and the display discarded) is now one shared helper. After the
    repair the same feed reports 12 resolved deadlines, 1 inside the 72 h window, and a label
    histogram of 207 "no advertised deadline" / 12 "advertised deadline" / 0 "deadline
    unverified".
  • The offer category lifted from the FIRST em-dash in the description, so multi-dash prose
    filed run-ons such as not an ongoing free tier — Coding as the category — which the harvest
    leg's /api provider/i class filter then read. The tail now lifts its final dash segment, and
    the parser keeps the tail's own expires statement even when its date does not resolve, so a
    consumer that cannot read a deadline says "unverified" instead of "no deadline". Review
    against live data caught the inverse defect in the first draft of that label: keying on the
    word "expire" anywhere in the prose relabelled 18 offers whose tail says ongoing — several
    reading "credits never expire" — as unknown, and the shipped rule reads the tail's statement
    instead. Both corrections came from measuring the real feed, not the plan's census.
  • The display printed every offer as one flat, unattributed line — 219 of free-options.md's
    339 lines — with no bound, grouping or attribution even though matchOfferHosts attribution
    was already computed for the facts and thrown away. Offer rows are now structured (title,
    category, deadline label, registry labels, url) and attributed through that same matcher: the
    /provider free output lists the attributed offers bounded to 10 with a remainder count and
    one per-category count line, free-options.md keeps every offer grouped by category with
    counts and known-provider marks, and the boot announce previews titles. The catalog delta the
    envelope already lifted (newModelIds) now reaches both headers, omitted when empty. The
    presentation lives in a new cli/src/utils/free-options-offers.ts because the renderer was
    already against the repository's 300-line ceiling — and the gate refused the work twice more
    before it passed: quality failed two suites at 367 and 309 lines, and both were repaired by
    decomposition (the display pins moved to free-options-offers.test.ts, the pre-existing
    attribution pins to custats-attribution.test.ts) rather than by exemption. New suite
    cli/src/utils/__tests__/provider-offers.test.ts (10 cases); 10/10 declared gates stamped.

2026-10-16 — Implemented candidates retire, and the exposure instrument is armed (FID-2026-1016-009, medium)

Changed

  • FID-2026-1016-009 (medium): a learning-pipeline review found the lesson-feature register
    had no terminal state, so seven implemented candidates — every one carrying a closed FID
    and a recorded commit — sat in the active queue while the only two open drafts were buried
    among them. bun run validate:repository was green throughout: admission validates a
    candidate's evidence, and for implemented its rules require exactly the closed FID and
    commit a finished record already has, so nothing ever asked whether the work was still
    open. Implemented candidates now retire verbatim to dev/feature-pipeline/implemented.json;
    admission fails an active entry whose state is implemented (naming the archive), an
    archived entry that is not implemented, and an identity collision between the two files.
    The archive is read for the lesson-to-feature mapping and is part of the report
    fingerprint, so retirement still suppresses a duplicate proposal rather than re-opening
    the class LF-006 exists to prevent. The admissions pass moved to
    scripts/lesson-feature-admission.ts and the archive to scripts/lesson-feature-archive.ts
    after the repository's own 300-line ceiling refused the first attempt — the validator
    caught two files at 338 and 350 lines and both were repaired by decomposition, not
    exemption. New suite scripts/__tests__/lesson-feature-archive.test.ts (6 cases).
  • The same review found dev/experiences/fix-boundaries.json empty, which was not a cosmetic
    gap: the declared exposure-capture hook has a documented fast path — with the manifest
    empty it returns "without a write and without spawning anything" — so the sink had never
    stamped a receipt and OBS-001 had no instrument for the production observation it owes.
    Four boundaries are now declared, each pinned to a repair commit verified to exist, to be
    an ancestor of HEAD, and to contain that class's fix: run_terminal_command:timeout
    (63d08c34), read_files:read-incomplete and run_readonly_command:command-exit
    (5b994ca0), and web_search:research-unavailable (f591e40f). The other four OBS-001
    classes stay unarmed with the reason recorded — read_url:http-404 and read_url:http-403
    are truthful upstream outcomes that the incident review forbids relabeling or bypassing,
    and read_url:fetch-unextractable and spawn_agents:incomplete-arguments have no commit
    that can be pinned to their repair. The census reads the armed classes as
    incomplete-observation and --assert-repaired=FID-2026-1015-006 still exits 1: the
    14-day, three-session window has not elapsed, and no class repair and no production
    observation is claimed
    .

2026-10-16 — No coding-agent credit in the governed records (FID-2026-1016-008, high)

Changed

  • FID-2026-1016-008 (high): the 2026-10-14 attribution rule now covers the
    records agents write, not only commit messages. Commit trailers were never the
    only place a coding agent got credited — a sweep found attribution fields and
    watermark lines inside session summaries, archived FIDs, a build order and the
    third-party channel, invisible to every gate that existed, and the new scanner
    reported ten further credits in the tracked, published changelog itself. The
    naming families now live in scripts/attribution-patterns.ts so both judges
    read one list; the record scanner is scripts/attribution-document-guard.ts;
    scripts/attribution-guard.ts keeps the commit surface, the aggregate
    collector and a --documents mode. Fenced blocks and inline code spans are
    read as quotations, and Savant's own credit, a human credit, an ECHO role and
    Savant's own provider id are never findings. Always on: validate:repository
    aggregates both surfaces, .githooks/pre-push scans the working tree (the
    records are gitignored, so no pushed range can contain them) and the
    attribution-guard workflow gains a document step. Every credit the sweep and
    the scanner found is stripped, keeping each verification claim intact.
    Implementation: 302ffe69, root-resolution fix 04b02c0b, content strips
    579e781f; four declared gates passed; closed and archived.

2026-10-16 — Batch pushed-range credential scan (FID-2026-1016-007, high)

Changed

  • FID-2026-1016-007 (high): exact pushed content is now acquired in bounded
    batches instead of per-path Git subprocesses. Two historical 6,207-file
    delete/restore commits made the fail-closed pre-push credential scan require
    roughly 24,828 launches and stall past eleven minutes with the mirror still
    empty; one ls-tree -r -l -z per commit plus SHA-only cat-file --batch
    reads chunked to an 8 MiB bound replace them. Range coverage, deletion
    confirmation, the 2 MiB size cap and path/blob identity pins are unchanged,
    and malformed, truncated, oversized, wrong-type or SHA-mismatched framing
    still fails closed before any byte reaches a writer. Measured on the exact
    38-commit range the push carries: 6,548 files scanned in 26 s, exit 0.
    Implementation: 6b2d9d91; seven declared gates passed; closed and archived.

2026-10-16 — Implementation closure and internal follow-ups

Changed

  • FID-2026-1016-006 (medium): separate implementation closure from internal
    observation and live comparisons. The validated local follow-up register
    retains owners, provenance, next actions and evidence, appears in the agenda,
    and keeps production-repair assertions strict. Repository and shipped agent
    guidance close committed, code-verified FIDs immediately and automatically
    push verified progress to main; handoffs and observation windows do not
    hold progress pushes. Release publication remains separate. Implementation:
    dbb8de12; 10 declared gates passed; closed and archived.
  • FID-2026-1015-006 (high): closed and archived the committed recurrence
    repairs after all 19 declared gates passed live. Windows descendant
    containment, native argument diagnostics, primary-content extraction,
    keyless search parsing and tool guidance are implemented. Qualified
    production observation continues independently under OBS-001.
  • FID-2026-1012-022 (critical): closed and archived the coordination program
    after all 37 children completed. Observation windows and the independent
    live-comparison task (LIVE-001) no longer hold implementation closure.
  • Reconciled selected lessons-pipeline candidates against production code:
    LF-003 (628375ff), LF-004 (d71b9065), and LF-007/008/009 (6b847099)
    are implemented. Fresh focused audit: 64 tests passed, zero failed.

2026-10-16 — Remove MarsAI (FID-2026-1016-005)

Removed

  • FID-2026-1016-005 (medium): removed the MarsAI built-in provider,
    14-model catalog, context-window coverage, CLI setup/picker wiring and
    current provider documentation. Generic custom-provider support remains
    available. Historical integration records and credentials are preserved.
    Registry/setup inventories now contain 47/46 providers. All 75 affected
    provider tests and 11 declared gates pass; references are current.
    Implementation: 87c2f87a; closed and archived.

2026-10-16 — MarsAI gateway provider (FID-2026-1016-004)

  • FID-2026-1016-004 (medium): added MarsAI as a built-in gateway provider —
    https://marsai.click/v1, openai protocol, keep dispatch, credential
    MARSAI_API_KEY. Static 14-id free-tier catalog from the operator's
    dashboard census (console-verified; the live /v1/models probe is blocked
    from this network — DNS hijack + TLS reset, recorded in the FID). The
    window seam carries 10 cross-gateway-sourced rows and 4 documented no-row
    ids; generated and hand-maintained provider docs synced. Implementation:
    62a72076; 14 declared gates passed; closed and archived.

2026-10-16 — Reconciliation closeout and repository untrack

  • FID-2026-1016-001 (low): hardened the sandbox temp-workspace cleanup — the
    kill path awaits a bounded child exit before removing the workspace and the
    cleanup assertion compares against a run-scoped baseline. Implementation:
    403262ee; 3 declared gates passed; closed and archived.
  • FID-2026-1016-002 (medium): identity-pinned exemptions (path + git blob id)
    for the five required ripgrep binaries at all three fail-closed refusal
    points; unpinned or swapped-content over-cap blobs still refuse.
    Implementation: 61e27b34, coverage split 2e889b75; 7 declared gates
    passed; closed and archived.
  • FID-2026-1016-003 (low): dev/ untracked from the index (1,241 paths;
    files remain on disk; anchored /dev ignore); docs/ retained per the
    same-day operator ruling. Implementation: aaa83b96; 2 declared gates
    passed; closed and archived.
  • FID-2026-1015-006 (high): re-stamped — all 19 declared gates pass live; the
    record remains verified and open for the observation window (no class is
    declared repaired). Repair package committed: 63d08c34, 0a516b26,
    aa8c6a2f, f591e40f, 5b994ca0; parity probe 2f2d4e31; scope-targets
    comment 4e6247e6; runbook pointer 3df0606c.
  • Final root test chain: 9,203 PASS / 23 SKIP / zero FAIL (9,226 ran), exit 0.

2026-10-15 — Runtime boundaries and product retirement

  • FID-2026-1015-002 (medium): retired Savant-Free product paths and build
    registrations; preserved ordinary model/provider routing; added scripts/tmux
    to root gates, six approved skill versions and the provider reference draft.
    Implementation: 001e36c6; 11 declared gates passed; closed and archived.
  • FID-2026-1015-005 (high): reject vacuous verification, break repeated settled
    checks, recover retained evidence, improve skill diffs and baseline pins,
    clamp subagent writes, sanitize reports and expose pure preset stepping.
    Implementation: d71b9065; 10 declared gates passed; closed and archived.
  • Final root test chain: 9,187 PASS / 23 SKIP / zero FAIL, exit 0. Root
    typecheck, ESLint, Markdown lint, formatting, quality and SDK build passed.
    Class repair remains unproved; post-cutoff findings continue under active
    FID-2026-1015-006 and master FID-2026-1012-022.

2026-10-15 — Durable session save and resume with nested runtime state (FID-2026-1015-004, high)

Fixed

  • Added one shared ancestor-aware, cycle-safe JSON serializer for SDK RunState
    transport and database session persistence.
  • Preserved each caller's omission policy while replacing unexpected cyclic
    back-references with a bounded, non-sensitive marker.
  • Added common, SDK, database, and CLI regression coverage for nested state,
    repeated references, reopen-compatible reads, and user-message preservation.

Verification and archival

  • Four workspace typechecks, four declared targeted suites, quality, targeted
    Prettier and ESLint, root typecheck, Markdown lint, and repository ESLint pass.
    The repaired full database suite passes 54/0.
  • Implementation commit: 628375ff.
  • The full root test suite passes 9,162/23 skipped/0 failed with a 10-minute
    execution budget. The initial repository validation run reported the locked
    clean-Linux scratch artifact plus eleven ENOENT findings from Savant-Free test
    paths deleted by concurrent FID-2026-1015-002 removal work. Commit dea54d85
    staged those approved deletions; the current validator reports only the
    locked scratch artifact, and neither finding is caused by the declared LF-003
    gates.
  • FID closed and archived on 2026-10-15.

2026-10-15 — clean Linux rebuild (FID-2026-1015-003, high)

Fixed

  • Clean Linux tests load the shared environment defaults before workspace
    isolation and use real search directories and local environment fixtures.
  • CLI release tests declare their tar dependency. Desktop tests compile their
    native sidecar before exercising the live gateway contract.
  • Shared path containment rejects sibling-prefix escapes, dangling symlinks
    and symlink loops. Windows path spellings normalize before Linux resolution.

Changed

  • Docker pins Bun and Node images by digest, includes npm for packaging tests,
    reaps child processes through tini, and provides non-secret CLI boot defaults.
  • Docker contexts exclude nested environment files, local credentials and backup
    bundles. Runtime display paths are repository-relative.
  • README documents native Linux prerequisites and exact build, test and run
    commands. Bun remains pinned to 1.3.14 and installs use the committed lockfile.

2026-10-15 — failure-class implementation completion

Fixed

  • FID-2026-1012-017 (critical): retained the observed rejection cause through
    stream settlement, later retries and exhaustion. Rejected arguments receive
    schema-correction guidance; truncation retains size guidance and existing retry
    limits. Six production-loop regressions pass; implementation f6224816.
  • FID-2026-1012-021 (high): recurring failures have explicit owners, missing
    ownership fails repository validation, repair proposals are idempotent and
    operator-routed, and class-repair lessons require qualified observation.
    Thirteen declared machinery gates pass.
  • FID-2026-1012-023 (medium): validated timeout budgets, caller/executor
    identity and producer-authoritative cancellation metadata survive SDK dispatch
    and module-copy boundaries. Sixteen declared gates pass.
  • FID-2026-1012-024 (high): stable class identity, bounded result inspection,
    producer-authoritative expectedness, failure capture and boundary-bound exposure
    receipts are implemented. All seven historical producer mechanisms have been
    investigated; seventeen instrument gates pass.

Verification and archival

Root tests: 9,206 passed / 23 skipped / zero failures. Root typecheck, ESLint,
Markdown lint, formatting, SDK build and repository validation pass. The four
implementation records close and archive on 2026-10-15 with local commit evidence.

Q25 permits named archival waivers for implementation-complete lanes; it does
not prove class repair. The capture still has 591 records / 59 stable classes /
zero ownership issues, all unresolved. Historical rows, repair boundaries and
exposure receipts remain unchanged. Each class owner retains its named waiver
and actual final implementation cutoff in dev/experiences/closure-waivers.json.
The master remains active for its registered operator/external-input holds.

2026-10-15 — Approved resume decisions (FID-2026-1015-001, medium)

Fixed

  • A selected provider now owns transport and token-budget catalog identity even
    when a model ID starts with another registered vendor's name. Custom endpoints
    retain their own credentials; explicit model replacements retain their own route.
  • Session-end skill notices use an independent cursor, acknowledge after output,
    preserve interactive delivery, and leave overflow or failed output unread.
  • Numeric task allocations persist after closure. Scope and repository validation
    reject identity reuse, missing allocations, and mutation of committed history;
    legacy numbers through 190 remain reserved.
  • Preserved local session exports byte-for-byte in an ignored archive and restored
    formatting in the two approved SDK process fixtures without changing their behavior.
  • Registered a newly captured file-read failure with the active taxonomy owner;
    no immutable capture row or production repair claim changed.

Verification

  • All thirteen configured workspace suites pass: 9,120 passed, 23 skipped,
    zero failures. Delivery/review/ledger suites: 23 passed. All fourteen declared
    FID gates, root typecheck, ESLint, Markdown lint, formatting, quality, scope,
    and repository validation pass.
  • SDK build succeeds. The aggregate build still fails at the existing Savant-Free
    build; its operator-owned removal remains active under T122.
  • Implementation commits: 83f1712d and ca94b6f1; final verification record:
    6fe1ca49. Closed and archived 2026-10-15 after a full CHANGELOG read.

2026-10-14 — Tier 1 first-party provider parity wave (FID-2026-1012-026)

Added

  • Registered the eighteen measured first-party labs — Anthropic, Google, xAI,
    DeepSeek, Groq, Cohere, Together, Cerebras, DeepInfra, Perplexity, Alibaba,
    Moonshot, Z.AI, MiniMax, Meta, Fireworks, Baseten and Venice — across the
    provider registry, routing, setup, picker, favicon, window-coverage and
    generated-documentation surfaces.
  • Added sixteen coding-harness-compatible static catalogs and dedicated live
    catalog parsers for DeepInfra and Venice. The static source contains 288
    curated chat/text rows with provider-specific window provenance; non-chat
    modalities and incompatible task-only rows are not exposed by the picker.
  • Added the shared live-catalog filter and regression coverage so live catalogs
    preserve coding-capable rows while excluding image, video, audio, embedding,
    translation, OCR, ASR, TTS, safety, deep-research and multi-agent-only rows.

Changed

  • The 2026-10-14 devoverride records keyless endpoint/catalog accessibility
    as acceptance evidence. No paid inference request or provider credit was
    required; keyed inference remains the user's BYOK leg.
  • Regenerated the provider catalog census and synchronized the hand-maintained
    provider documentation surfaces. The assembled parity census now contains
    3,648 runtime rows, while the curated static Tier 1 source remains 288 rows.

Verification

  • Tier 1 and window-coverage suites: 10 pass / 0 fail; selected common
    provider suites: 44 pass / 0 fail.
  • bun run typecheck, providers:parity:check, window-coverage:check,
    quality:report, lint:md, generate:provider-docs:check, the declared
    FID gates, and the refreshed FID receipt all pass. Scoped ESLint and
    Prettier checks pass; git diff --check is clean.
  • FID-2026-1012-026 closed and archived 2026-10-14 at local commit
    f6ce2109; no push or release was performed.

2026-10-14 — refusal authority, guard audit and agent-attribution enforcement

Fixed

  • FID-2026-1014-001 (high): the read-only command guard refused legitimate
    read-only work — the POSIX null sink 2>/dev/null in three spellings and
    input redirection < file in two — measured 5 of 56 corpus commands, while the
    EHEL mutation classifier already treated /dev/null as a non-mutation target.
    Fixed to 0. The same audit found the SEC-3 whole-segment redirect waiver live
    at HEAD (2>&1 forgave every other metacharacter, so the read-only tool
    accepted cat .env > /tmp/exfil.txt 2>&1), even though FID-2026-0919-010
    closed with that fix marked DONE and a promised suite no commit ever
    contained. The span-scoped strip-then-rescan is restored, the promised suite
    exists, and one exported non-global predicate is shared with the mutation
    classifier. 7/7 gates; corpus false positives 5 → 0; suites 18/0, 4/0, 10/0,
    15/0 and 644/0 across the three affected directories. The guard's measured
    under-breadth class (git push, git clean -fd, bun -e, bun x,
    bun run release:public, deno eval, find . -delete, kill -9 1) is
    reported and registered, pending the operator's routing ruling.
  • FID-2026-1014-003 (high): no coding agent may be attributed in this
    repository — one rule (scripts/attribution-guard.ts), enforced by the
    commit-msg hook, the pre-push commit-range scan and a CI job, and now wired
    into bun run validate:repository so the rule travels with every clone rather
    than living in layers a --no-verify bypass can skip. The two divergent copies
    of the pattern list are gone; watermarks are anchored to line start (the first
    whole-history run flagged the guard's own explanatory commit) and the emoji
    prefix works (it was inert without the u flag). 4/4 gates; whole-history scan
    exit 0; hook fail-closed on an unreadable message (exit 2). The 2026-10-02
    session summary that invited footer removal "per the operator's own co-author
    policy" carries a dated amendment; branch protection remains operator-owned.
  • FID-2026-1014-002 (medium, closed + archived 2026-10-14): registered that
    a closed FID (FID-2026-0919-010) asserted an implementation and a test file
    that no commit ever contained. Added the active-record declared-artifact census,
    explicit absence-marker contract, and informational archive audit mode. The
    active gate passes with 7 records, 34 named paths and 0 missing paths;
    the Q24 read-only Git-history audit classified 44 historical missing paths
    without rewriting archived FIDs. Implementation commits: 1d60b9a8,
    33f5c2f2; evidence and closure record: ad5c18d7.
  • FID-2026-1013-005 (low, closed + archived 2026-10-14): verified local
    Ollama availability at HTTP 200 with three models and documented Cloudflare's
    public Workers AI catalog plus its account-scoped REST credential boundary.
    Q27 makes the Account ID/token an audit limitation rather than a completion
    gate for the curated static catalog. No account-specific roster query or
    credential use is claimed. Public-boundary commit 9d6fe794; completion
    evidence commit e834228f.

2026-10-14 — three failure-class lanes archived under Q25

Fixed

  • FID-2026-1012-018 (high): classified every read_url outcome, preserved
    the original capture first lines, added actionable next steps, canonicalized
    URL identity, and isolated negative caches per SDK run. Implementations
    64ea8c06 and d9cee722; 7/7 declared gates pass. Q25 records that the
    recurrence window remains unproved; no repair or silence claim is made.
  • FID-2026-1012-019 (high): added the shared capability-degradation contract,
    truthful research exhaustion and code-search flag outcomes, and run-start
    capability preflight. Implementations 09f0c892 and 3ee91a35; 10/10
    declared gates pass. The named Q25 waiver preserves the unresolved observation
    boundary and does not claim the host-side resolver class repaired.
  • FID-2026-1012-020 (medium): added bounded edit diagnosis, separated mismatch
    from no-op outcomes, removed unsafe patch/error payloads, and corrected the
    frozen client-result mutation path. Implementations 0e7b3414 and be66e79f;
    11/11 declared gates pass. Q25 archives the implementation-complete lane
    without claiming qualified production observation.

FID-2026-1012-017 remains active: its four measured post-fix classes are rejected
by the recurrence gate and are not excused by the Q25 waiver.

2026-10-14 — QOL hardening program completed (five FIDs archived)

Fixed

  • FID archive alignment: Backfilled fifteen missing October 13 archive-index
    entries and eight existing implementation hashes in the G2 pre-audit's
    canonical metadata field. Historical verification evidence remains unchanged.
  • FID-2026-1013-010 (high): Write-tool paths survive compaction and reach
    graph evidence; Law 1 resolves against the project root; evidence shards cache
    by size/mtime; micro-compaction reports actual savings and preserves tiny
    results; failed structured-output diagnostics and logs redact before truncation.
  • FID-2026-1013-011 (medium): Shared display, truncation, coercion, render,
    nameplate and SQLite primitives replace duplicated implementations, with
    production consumers and registry enforcement preserving compatibility.
  • FID-2026-1013-012 (medium): Type-safety and lint-rationale enforcement,
    scanner literal/comment handling and ceiling decompositions are complete.
    Closure review replaced the quote-sensitive scanner with the pinned compiler
    parser/scanner and regression controls for regex, templates, division and TSX.
  • FID-2026-1013-013 (medium): Desktop tool attribution, diff/output previews,
    approval notes, walker lookup and cursor ownership, plus CLI collapse-timer
    cleanup and shared empty-ad state are complete.
  • FID-2026-1013-009 (high): Coordinator closed after all four children;
    all 24 allocated findings are committed in b959019e. The shared
    renderer/reducer dependencies ship as one coherent program. All 52 declared
    child gates, full root tests across thirteen workspaces, root typecheck,
    ESLint, Markdown lint, SDK build and repository validation pass. Fresh live
    TUI/WebView visual smoke is unclaimed. No push or release was performed.

2026-10-13 — The bundle restore drill gets a budget it can meet (FID-2026-1013-008)

Fixed

  • The scripts suite is green on a loaded machine, not only a quiet one. Its fifth independent
    failure was a clock, not an assertion: git bundle backup > restore drill measured 4261-5462 ms
    across three isolated runs — real baseline clone plus incremental fetch through spawned git —
    against bun's 5 s default, with siblings in the same file at 1.0-3.3 s. The file now declares
    GIT_CHILD_TIMEOUT_MS beside the measurements that justify it, following the convention already in
    this tree (FID-2026-1010-004); assertions untouched. Implementation 4be4de9e;
    cd scripts && bun test 960 pass / 0 fail, exit 0.

2026-10-13 — Both suite-health records close (FID-2026-1013-006/-007)

Fixed

  • The scripts suite is green from its declared cwd (FID-2026-1013-006). Four independent
    deterministic failures, none of them load flakes: two live-repository checks resolved the
    repository root from process.cwd() — which is scripts/ under the FID-2026-1013-001 gate
    contract — so they read scripts/CHANGELOG.md; the boundary probe rejected every cross-origin
    redirect, including the apex→www hop its own re-POST logic exists for (the guard is now the
    site: same scheme and port, base host, subdomain or parent, so an unrelated host still fails
    closed); and two git-fixture tests that spend 4-6 s in process spawns on Windows were held to
    bun's 5 s default. Implementation 722d1c03; no assertion was removed or weakened.
  • The graph leg absorbs Windows lock codes and its own fixture cost (FID-2026-1013-007). The
    refresh-safety teardown retried EBUSY only, for 250 ms, while Windows reports EBUSY, EPERM,
    EACCES or ENOTEMPTY; the fabricated 10,001-entry enumeration test now carries a budget that
    matches what it deliberately performs. Implementation 2f003aed. The root bun run test chain is
    green across all 13 legs, and bun run validate:repository passes.

2026-10-13 - The AIHubMix gateway joins the built-in registry (FID-2026-1013-004)

Added

  • AIHubMix (aihubmix, AIHUBMIX_API_KEY) is a built-in gateway provider on
    https://aihubmix.com/v1, single openai protocol and strip id transform, using the
    vendor's richer keyless catalog at /api/v1/models - probed 2026-10-13: HTTP 200
    with 869 rows, of which 698 carry the exact comma-delimited llm type token. The
    wrapper filters on that token, preserves sparse-endpoint rows rather than dropping
    them, and uses catalogLimit without fabricating any limit the vendor omits.
  • Window coverage is declared runtime-partial - of the 698 LLM rows only 358
    publish a positive context limit and 306 a positive output limit, so zero, missing and
    non-positive values stay unknown and no fallback is invented. The exception manifest
    owns the live-catalog behaviour and the census records the measured row count.
  • ProviderConfig.extraHeaders - a registry-owned carrier-header field. AIHubMix's
    documented APP-Code grants a standing discount, and no seam existed for a
    provider-specific request header (the codebase's only precedent was a provider id
    hard-coded by name in two factories). The new optional field is applied on all four
    generic-factory protocol branches and plumbed through the DIRECT_PROVIDER bare-slug
    path, so a declared header cannot be dropped by a protocol dispatch or a routing mode.
    The custom-INFERENCE_BASE_URL branch is deliberately excluded: an operator-owned
    endpoint must never receive a registry provider's identity headers.
    MFSO2605 is a public discount code, not a secret, so it is registry data and never
    an env var.

Fixed

  • Two import/order violations in gateway.ts and gateway-live-results.ts, where
    the new ./aihubmix import sat after ./apinex, plus an over-wrapped
    positional-contract comment.
  • A stale register entry. The archived Apixo FID's SCOPE.md item outlived its
    closure and was evicted here.

Known limitation

  • A free-model inference probe returned HTTP 200 with an account-policy apology, not a
    substantive completion
    . This is recorded as transport and credential reachability
    only; it is not an inference-acceptance claim, and a later substantive completion
    would be stronger evidence rather than a correction.

2026-10-13 - The Apixo gateway joins the built-in registry (FID-2026-1013-003)

Added

  • Apixo (apixo, APIXOAI_API_KEY) is a built-in gateway provider on
    https://api.apixoai.online/v1, single openai protocol, strip id transform, and
    a keyless live catalog (/v1/models) — probed 2026-10-13: HTTP 200 both keyless
    and keyed with byte-identical bodies, 35 rows, and one real completion on
    deepseek-v4.1-flash. The /provider picker, /model catalog, routing prefix,
    credential readiness and favicon all derive from the registry entry; the new wrapper
    carries a dedicated parser for the vendor's context_window /
    max_output_tokens row shape, which the shared OpenRouter-shaped parser would have
    read as zero windows (the measured Vercel mis-parse class).
  • Window coverage is declared runtime-published — the catalog publishes a window
    on every one of its rows, so the runtime value is the source of truth and no
    fallback-table section is owed. The exception manifest owns the live-catalog
    behaviour, and the live census records the measured row count.

Fixed

  • Two registry-enumeration tests that the provider runbook does not name
    (common/src/providers/__tests__/provider-registry.test.ts) now carry apixo in
    the registry-key, setup-key and order-4 lists — a new provider fails those before
    any pipeline gate sees it.
  • Pre-existing prettier drift in three files this change does not own
    (packages/agent-runtime/src/hooks/exposure-capture.ts, its suite, and
    scripts/__tests__/experiences-proof.test.ts) was repaired in the same pass so the
    hard format gate is green. Formatting only; no behaviour changed.

Verification

All eleven declared gates exit 0 (receipt stamped 2026-10-13T18:01:05.201Z); full root
typecheck exit 0; every workspace suite green — cli 4155, common 871, sdk 672,
agent-runtime 2103, desktop 450, evals 229 plus six smaller workspaces, all 0 fail;
quality:report PASS; eslint, markdownlint and prettier exit 0;
generate:provider-docs:check, providers:parity --check (apixo: 35) and
window-coverage:check clean. validate:repository was not run by operator ruling
2026-10-13 (recorded verbatim in the archived FID); the sub-checks this change owns were
run individually. Closed and archived at 6c32495.

2026-10-13 — The learning-store and harness lanes close (FID-2026-1012-010/-011/-012/-013/-014/-015/-016/-027, FID-2026-1013-001/-002)

Fixed

  • The lessons ledger has a size contract and its boot read is bounded
    (FID-2026-1012-010, FID-2026-1012-011). The 1,200-logical-line and 100,000-character
    ceilings moved from the retirement tool into the validator, so learnings:check and
    therefore validate:repository fail on either breach and report headroom while green;
    retirement emits a machine-readable move record and now recovers from an interruption
    mid-move. The boot read is a generated 24,000-character rule digest, and grounding credit
    is refused for windowed, truncated or status-only reads.
  • Retirement no longer strands by-title references, and lesson evidence stops rotting
    (FID-2026-1012-012, FID-2026-1012-013). One locator spans the live ledger and the retired
    archive and resolves supersession with replacement notices; the seven admission issues that
    left lessons:features --check red are resolved. Reproduction references are structured,
    ephemeral roots are rejected, and historical pins must validate their actual commit and blob.
  • The rule catalogue and the ledger are kept in step (FID-2026-1012-014, FID-2026-1012-016).
    Every catalogue rule carries a tier and a reason, every non-historical lesson names exactly
    one catalogue rule, and the shipped subset is a deterministic projection of the boot tier.
    The consolidation inventory is exact-merge only: 74 unique titles, zero eligible proposals,
    zero mutation, zero boot saving claimed.
  • The lesson-to-feature pipeline is gated by its own independent collector
    (FID-2026-1012-015); lessons:features --check passes over the reconciled store and its
    report fingerprints the live, retired and manifest inputs, publishing deterministic red
    reports instead of a stale green one.
  • Coverage of a fixed record's own surface is now a checked relation
    (FID-2026-1012-027). scripts/fid-surface-coverage.ts joins each enforced record's declared
    gates to its SCOPE.md write surface; it found and repaired two real omissions and
    fid:verify --write refuses an uncovered stamp first.
  • Script test gates resolve from the scripts root (FID-2026-1013-001), so receipt
    execution no longer runs repository-root substring discovery over script suites.
  • Partial assertions no longer mutate the evidence they check (FID-2026-1013-002).
    Three inline toMatchObject calls replaced received fields with matcher objects under
    Bun 1.3.14; they now use a non-mutating equality/partial-object composition, with a shared
    AST collector wired into repository validation.
  • All ten records re-ran their declared gates green on the closure tree (13+6+8+7+12+5+5+6+3+10
    = 75 gate executions, every one exit 0), then were closed and archived at their
    implementation commits. FID-2026-1012-011's recovery commit is ca1f359d. The failure-class
    remediation master (FID-2026-1012-022) remains active: its class lanes still await
    exposure-qualified observation.

2026-10-12 — Verification harness drift repaired (FID-2026-1012-025)

Fixed

  • Wire the existing model-picker and compliance-capture resets into their workspace
    test preloads. Preserve the operator-approved Tauri allowlist with positive and
    forbidden-command controls, and point the window-census test at the loader's durable
    measured fixture rather than a removed scratchpad file.
  • Standalone provider probes now run only through guarded entrypoints. Import-safety
    tests first reproduced attempted requests with a fetch blocker, then pass without
    requests or credential reads. Both programs share a typed credential reader.
  • Closed and archived at implementation c4018491fcf0ff7183c009d9bf5b559c84dc329f.
    Ten declared gates pass; full root typecheck, lint and quality pass. Sequential broad
    suites: scripts 451 PASS, agent-runtime 2,037 PASS. No timeout budget was raised.
    The failure-class remediation master remains active; this closes its harness finding.

2026-10-12 — Truncated tool calls are steered to split the payload (FID-2026-1012-009)

Fixed

  • A payload cut by the output budget was answered with a re-send that
    truncates identically (FID-2026-1012-009).
    The output-cap discriminator
    FID-2026-0909-008 built — finishReason === 'length' selecting "split the
    work into smaller calls" — was unreachable from the path that actually
    produces these failures: classifyInvalidToolCall (the vendor-SDK
    transformer for anthropic, google and the rest) received ai core's
    invalid: true tool-call part and rebuilt the error by hand as
    { type: 'native-incomplete', toolName }. The stream's finish part arrives
    after that classification, so no finish reason exists there to branch on. Every
    one of the 48 read_files native-incomplete failures recorded between
    2026-10-02 and 2026-10-12 carried the generic "retry the tool call with a
    complete arguments object" text and none the cap text — advice that cannot
    work on arguments the model never finished writing.
  • The vendor path now carries the discriminator it alone holds. ai core
    already separates the two cases: safeParseJSON returns a JSONParseError
    when the arguments never parsed (the document did not close, i.e. the payload
    was cut) and a TypeValidationError when they parsed but missed the tool's
    schema, and doParseToolCall attaches that result as the
    InvalidToolInputError's cause. isTruncatedToolInput reads it, and
    classifyInvalidToolCall marks the error argumentsTruncated. Schema/type
    failures, a missing cause and unrecognised shapes stay on the generic retry
    text, so the fail-closed default is unchanged and no execution path, argument
    rewrite or strike budget was touched. Message and ladder selection only.

Added

  • NativeToolCallError and the native-incomplete StreamErrorChunk carry an
    optional argumentsTruncated?: boolean, with isNativeToolCallError
    rejecting a non-boolean value — the same hostile-shape discipline its
    finishReason field already had. Both truncation causes (a provider's
    output-cap finish reason, and a parse failure the classifier observed itself)
    select one shared advice sentence with a truthful cause clause per case
    (Law 13), so the wording cannot drift apart between them.

Verification

  • sdk/src/impl/__tests__/llm-native-tool-call.test.ts 12 pass / 0 fail (five
    new cases: a parse-failure cause selects the split advice; a schema failure
    and a missing cause keep the generic text; a false flag keeps the generic
    text; a hostile non-boolean flag is rejected by the guard).
  • packages/agent-runtime/src/tools/stream-parser/__tests__/error-chunk-steering.test.ts
    10 pass / 0 fail, including a new pin that the truncated body survives the
    runtime and still gains the read_files strike-1 steering.
  • Root bun run typecheck (13 workspaces + scripts/), ESLint --max-warnings 0
    over the changed files, Markdown lint, quality:report and the record's five
    declared gates all exit 0. Implementation: 682399fd.
  • Boundary recorded rather than claimed: the classification and both message
    selections are proven at unit level. The eight-day ledger stores only each
    error's first line, so it cannot retro-attribute its 48 records to cause; the
    next occurrences must be read from dev/experiences/raw-traces.jsonl to
    confirm the class text changes, and the capture-side errorClass/truncation
    field remains open as a follow-up.

2026-10-12 — Researcher acceptance and the lesson feature pipeline closed (FID-2026-1012-003, FID-2026-1012-004)

Changed

  • FID-2026-1012-004 (verified → closed) on the operator's directive. The
    feature pipeline itself is unchanged and stays verified: 74 headed lessons
    (55 schema-governed), six reviewed candidates, the read-only report/check
    command with its explicit write mode, and bounded routing notes on the
    production SessionEnd hook. Closing also landed its own output — see the
    section above for the two implemented candidates.
  • FID-2026-1012-003 (verified → closed): the researcher-acceptance and
    render-recovery repairs (MCP schema preservation, typed argument recovery,
    the shared traffic-light panel for namespaced tools, rich-text normalization
    and per-group transcript containment) close on their eight declared gates,
    all exit 0 at the archived path. Two boundaries are recorded rather than
    claimed: the exact original offending subtree was never logged, so the repair
    is pinned by the shapes it covers, and the operator's original prompt still
    needs their live acceptance on the repaired build.
  • The cited build blocker was measured rather than restated: the aggregate
    bun run ci red is the FID-2026-0805-002 integrity gate refusing this
    machine's repo .env.local (dev NEXT_PUBLIC_SAVANT_CODE_APP_URL), and the
    Savant-Free leg builds green under the documented clean-shell condition
    (SAVANT_FREE_MODE=true bun --no-env-file cli/scripts/build-binary.ts savant-free 0.0.0-dev
    → exit 0). T122 remains an open, operator-owned item — repair the
    Savant-Free feature or remove it; nothing in this pass resolves it.
  • SCOPE.md drops the two closed items and their machine-readable targets, as
    the register's own rule requires.

2026-10-12 — read_files windows and child-agent context propagation (FID-2026-1012-007, FID-2026-1012-008)

Added

  • common/src/util/read-window.ts — one newline-exact line-window extractor
    shared by the SDK's read boundary and the runtime handler. A window that ends
    before EOF keeps its separator, so consecutive pages of a large file
    concatenate back to the original content byte-for-byte (asserted with a
    matching SHA-256 over a >100k-character file).
  • RequestFilesFn (common/src/types/contracts/client.ts) accepts an optional
    offset/limit window, forwarded by
    packages/agent-runtime/src/get-file-reading-updates.ts and served by
    sdk/src/run/tool-call.ts → sdk/src/tools/read-files.ts. An
    overrideTools.read_files implementation receives the window in its input and
    owns its response.
  • resolveChildContextWindow (spawn-agent-utils.ts) — the model-route guard
    that propagates the run's resolved context window to a child agent running
    the same model, mirroring resolveChildOutputBudget.

Changed

  • subagentContextParams now carries the run's compression policy into every
    child agent. The policy is model-independent, so a pinned-model child inherits
    it too; the model-scoped window is deliberately kept out of the extractor and
    travels through the guard instead.
  • Embedded grounding reads are windowed locally by the read_files handler; the
    handler no longer slices a filesystem response, because re-slicing an
    already-windowed response silently drops lines.
  • sdk/src/run/require-cwd.ts — requireCwd moved verbatim out of
    tool-call.ts to keep the dispatcher under the 300-line absolute maximum.

Fixed

  • read_files returned nothing for a window past the read cap
    (FID-2026-1012-007).
    offset/limit were applied after the SDK truncated a
    file at READ_FILES_MAX_CHARS, so the tool's documented large-file escape
    hatch was unreachable: dev/LEARNINGS.md has 2,147 lines, its capped prefix
    holds 1,552, and offset: 1750 came back empty while the lines were on disk.
    The window is now served from the complete content at the fetch boundary and
    the response is still capped; traversal, ignored-file and 10MB rules are
    re-pinned for windowed reads. Commits 303c6838, e3bea01e.
  • Child agents compacted by default and sized thresholds from a fallback
    (FID-2026-1012-008).
    The spawn boundary's field whitelist dropped the run's
    compression configuration and resolved contextWindow, so a child built its
    ContextCompactor from undefined: micro-compaction defaulted ON
    (microCompactEnabled ?? true) while the run had it off — clearing fetched
    research records mid-synthesis at 11% of the threshold — and the window fell
    back to 200,000 regardless of the model. Both now reach the child through the
    routes their scoping demands. Commits 7fbecd99, e3bea01e.

2026-10-12 — Managed temporary scratchpad (FID-2026-1012-006)

Added

  • dev/scratchpad is now managed temporary storage rather than an unmanaged
    drawer. A native lifecycle manager in common expires idle files after 24
    hours and prunes above 32 MiB / 1,000 files with a one-hour grace, never
    follows links, never removes anything outside the scratch root, and preserves
    the root README/.gitkeep.
  • /scratchpad status and /scratchpad clean give the operator the same
    policy in the CLI; clean is not a force-delete command. Both variants get
    the command because it rides CORE_SLASH_COMMANDS.
  • Live native runs hold a whole-root lease, so an executing agent never loses
    its own temporary files (including terminal-created flat files the sweep
    never scanned). Dead owners are reclaimable, a reused PID conservatively
    protects, and malformed coordination data blocks deletion with an explicit
    diagnostic instead of guessing. Injected filesystems never trigger host
    housekeeping, and housekeeping failures warn rather than crash a run.
  • The sweep runs at CLI startup, every five minutes while idle, and
    before/after native SDK runs, releasing protection on success, failure and
    cancellation.

Changed

  • scripts/hygiene.ts now reports only root-level scratchpad clutter; expiring
    nested files is the runtime manager's job, not the lint's.
  • Agent instructions and docs/scratchpad.md state that scratch is temporary
    including the legacy archive directory — "age archive into another
    archive" does not bound growth — and name the durable homes for reports
    (dev/test-prompts/archive/, dev/session-summaries/) and reusable probes
    (scripts/providers/audit-probes/).

Fixed

  • The probe that moved out of the gitignored scratchpad into the typechecked
    scripts tree had no module marker, so its top-level await (TS1375) broke
    the scripts typecheck — which also failed FID-2026-1012-004's declared
    scripts-typecheck-check gate. The marker and the probe's stale
    run-path documentation are both corrected.

2026-10-12 — Tiarina Cloud is a built-in gateway (FID-2026-1012-005)

Added

  • tiarina (Tiarina Cloud, https://ai.tiarina.cloud/v1, TIARINA_API_KEY)
    is registered as a hosted gateway: it appears in /provider, routes
    tiarina/<model-id>, and shows up in the generated .env.example block,
    README.md, cli/release/README.md and docs/providers.md registry table.
    No adapter and no SDK change — the request router is registry-driven, which
    the new keyed round-trip through the production chain proves end to end.
  • The catalog is the checked-in 19-id allowlist the keyed /v1/models probe
    returned rather than a live fetch — the same call the repo made for
    ChatAnywhere, for the same measured reason: not one of those 19 rows publishes
    a context window, so a live catalog would still need the identical
    fallback-table section. The suffixed :free and :cloudflare ids are rowed as
    the separate roster entries they are.
  • Window coverage: a new context-window-table-tiarina seam carries 18 rows,
    each read off existing cross-gateway rows for the same upstream model (two of
    them pinned at the conservative minimum of two disagreeing >=2-row groups),
    plus one documented no-row id that keeps the flagged 200k default.
    NO_PUBLISH_GATEWAY_IDS membership is what mechanically enforces the seam
    file and its window-truth suite.
  • The provider's own tests: fid-2026-1012-005-tiarina.test.ts (windows compared
    against an independent oracle, never against the table the builder reads) and
    window-truth-tiarina.test.ts (roster windows, variant inheritance, total
    19-id coverage, seam-wiring census). The suite also asserts what this shape
    does NOT have: zero exception-manifest entries.

Changed

  • The closed-world registry pins widened from twenty-six providers to
    twenty-seven (twenty-five setup providers to twenty-six).
  • provider-catalog-census.json was regenerated with providers:parity — the
    committed copy was a stale 2026-10-06 subset, so the file now carries the full
    current assembly including tiarina: 19.

Fixed

  • docs/adding-a-provider.md's live-catalog example resolved its key with
    process.env.MYPROVIDER_API_KEY, while every shipped wrapper calls
    resolveProviderApiKey(providerId) — the seam that also sees a key entered
    through /provider. Following the runbook literally produced a catalog that
    401s for every wizard-configured user.
  • Still open for the operator: .env.example:152 cites task T146, which is not
    registered (the register carries that work as T147); every .env* surface is
    operator-owned under no-write-dotenv, so the one-character fix is left to them.

2026-10-12 — Scholarly research through the public Scholars Reading List MCP service (FID-2026-1012-001)

Added

  • Medium-severity capability gap resolved: researcher-web connects to the
    public, keyless Scholars Reading List MCP service for paper search, record
    lookup, similarity search, and shared-reference citation traversal. The native
    web tools remain available when the literature service cannot be loaded.
  • Definition and runtime regression coverage pins the remote HTTP contract,
    all four model-visible MCP tools, and native-tool fallback on server failure.
    The bundled agent is regenerated from its definition.

Fixed

  • Literature questions follow MCP-first research and verify citations against
    fetched paper records; the old unconditional web-search and three-page rules
    now apply to web research. Paper claims beyond abstracts require full-text
    verification. Parameter guidance follows the live MCP schema: string-valued
    abstracts, result limit, and citation breadth.
  • Researcher capability summaries now include scholarly literature. Completion
    review verifies the committed implementation and live tool round trips,
    records the verification receipt, and closes the FID with archive/register cleanup.
  • Remote HTTP/SSE MCP calls now carry network effects with prompt permission;
    the executor admits discovered tools offered by the current step from the
    agent's own configured servers. Unowned, unoffered and safe-mode calls stay
    blocked; stdio tools retain mixed effects. Error recovery checks the actual
    offered tool set, including MCP tools, rather than only the native name list.

2026-10-12 — Unavailable-tool calls are no longer misdiagnosed as argument truncation (FID-2026-1012-002)

Fixed

  • The OpenAI-compatible stream transform answered two questions with one predicate:
    isCompleteKnownToolCallArguments returned false for a tool name the request never declared
    before it looked at the arguments, so a call with perfectly well-formed JSON was emitted as
    native-incomplete and the model was told to send a complete argument object — a remedy no retry can
    satisfy. The vendor path lost the same distinction one layer later, where classifyInvalidToolCall
    read only the tool name and discarded the ai-core NoSuchToolError that said otherwise. A new
    tool-unavailable class now carries the name-only failure end to end, with its own honest message
    and a one-retry budget (TOOL_UNAVAILABLE_RECOVERY_MAX_STRIKES = 2; the counter includes the current
    step) instead of the truncation ladder's three strikes.
  • A tool-restricted subagent was also invited to call tools it does not have: the subagent addendum's
    phase-gating sentence named run_readonly_command and read_files/glob/list_directory/
    code_search as "available in ALL phases" inside a message whose first sentence said the opposite.
    The note is now derived from the child's own allowlist, and the allowlist-blind drift check in
    packages/agent-runtime/src/tools/stream-parser/error-chunk.ts compares against the agent's tools,
    so the class is visible in logs and the ledger instead of silent.
  • Protocol markup reaching the user as prose: the parser recognized only the canonical envelope and one
    legacy name, so an observed <SAVANT_TOOL_CALL> block — a name that has never existed in this
    repository's history — was passed through with its cb_tool_name JSON intact. Known aliases and case
    variants now normalize to the canonical envelope, and any other tool-call-shaped envelope is
    discarded rather than rendered.
  • The reported run died at loop-iteration.ts naming a read_files payload problem for an agent whose
    tool list is sequentialthinking/end_turn. The RED-first probe
    (dev/scratchpad/active/fid-1012-002-unavailable-tool-probe.ts) failed with four named issues before
    the change and passes now; three pre-existing suite fixtures that called tools their template never
    declared were corrected to declare them, since the truncation ladder they pin applies only to a tool
    the agent actually has.

2026-10-12 — System review: twenty findings repaired and verified (FID-2026-1011-006)

Fixed

  • Knowledge graph: the default parser read relative to the process cwd, so a project
    outside it silently lost symbol/CALLS evidence; directed reachability rebuilt path order
    by position from rows that carry no such contract; blast-radius traversal enumerated
    simple paths, re-exploring every alternate route and blocking its caller synchronously
    (166-173 ms at nine nodes on an adversarial dense fixture); cluster counts reported file
    anchors as node counts; a same-content mtime change never advanced the stat baseline; an
    unchanged refresh still rebuilt edges and clusters; the edge clear committed outside the
    replacement transaction; and an incomplete enumeration was treated as proof of deletion.
    Repairs are per-vertex bounded traversal, a completeness certificate on the tree scan, and
    one whole-refresh transaction that verifies its baseline before writing.
  • Parser: the output caps were applied after the work — twelve files were read to return
    one — and an oversized file was read to completion before its size was checked. Admission
    now precedes every read and counts UTF-8 bytes.
  • SDK/runtime: a handler rejection bypassed settlement cleanup, so snapshots kept running
    after the host had a rejected run; the retry and recovery wrappers drove their sources
    without closing the owned iterators.
  • Connectors: live invocation ignored its fetch override (the injected function saw zero
    calls while the global one ran), and the bundle cache keyed on nothing and retained a
    rejected load.
  • Desktop: a superseded socket's callbacks could close the current connection and reject its
    requests, and a transport firing its handlers synchronously hit an unassigned socket.
  • Persistence: a stable message id kept its first content forever; a failed steering-audit
    write was dropped while the code documented a retry; every label row counted as a
    completed compaction boundary; a throwing commit observer turned an already-committed
    write into a reported failure; and the persisted import resolver could escape the project
    root.
  • Catalogs: a reset could be overwritten by an earlier in-flight fetch, and a credential
    rotation was served from a cache assembled with the previous key.

Added

  • Regression suites at each repaired seam (refresh-safety, edges-from-tokens,
    gateway-client-generation, session-entry-persistence, live-catalog-generation) and
    the FID's declared gate set: 36 gates, all passing, with the verification receipt stamped.
  • invalidateGatewayCatalog() drops the merged catalog, the in-flight slot, the on-disk
    warm-start snapshot and every per-provider cache when a credential changes, wired to both
    provider-key save paths; activateProviderRouting moved to its own module at the quality
    ceiling.

2026-10-11 — cli-bundle-resolution runs against a pristine install (FID-2026-1011-005)

Fixed

  • cli-bundle-resolution bundled the CLI in the working tree, so bun build resolved
    imports against whatever node_modules the machine had. Measured on this machine: an
    import no manifest declares and no lockfile install provides — present only in a stray
    C:\Users\spenc\node_modules — let the gate exit 0, the same mechanism that supplied
    ajv/dist/2020.js at v0.0.35. The gate now materializes the release file set into a
    scratch tree, installs the frozen lockfile there, runs the release build's own prebundle
    steps, and fails when any module the bundler loaded resolved outside that tree (or when
    the module graph records nothing). Cost: ~1m49s, in the release battery only — the
    pre-push hook does not run the gate contract.
  • The root gate contract now invokes the probe (bun run scripts/cli-bundle-resolution-check.ts), the engine's rules are pinned by
    scripts/__tests__/clean-install-bundle.test.ts (15 tests), and the operator can run it
    by hand as bun run bundle:resolution.

2026-10-11 — Release gate for undeclared imports (T188, FID-2026-1011-004)

Added

  • undeclared-imports — a release gate that grades every tracked-source import against
    the repository's own declarations and NOT against the installed tree, so a mutated or
    stale node_modules can no longer make it pass. That is the class
    cli-bundle-resolution cannot see: at v0.0.35 that gate ran green locally on a leftover
    ajv v8 dist/ tree while CI, resolving the committed lockfile, failed on the same
    import. scripts/undeclared-imports.ts (pure detector) and
    scripts/undeclared-imports-audit.ts (collector + probe) read only git ls-files, the
    26 manifests and bun.lock. transitive (no manifest declares it; only a transitive
    dependency hoists it — the v0.0.35 ajv) and absent (not even in the lockfile — the
    v0.0.24 @noble/hashes) fail; cross-workspace and root-declared imports resolve and are
    not reported.

Fixed

  • The audit found four packages that no manifest declared. Declared them: picocolors in
    cli (four files under cli/src are bundled into the shipped binary and nothing owned
    the dependency — it arrived only through pino), picocolors and js-yaml in
    scripts/tmux, and globals, playwright and playwright-core at the root (the eslint
    config, the HUD browser check, and the desktop browser-smoke fixtures), then regenerated
    bun.lock.
  • cli/release-core/launcher.js: a failed background update is now reported instead of
    swallowed. v0.0.35 published to npm while its release assets were missing, so the
    launcher resolved the new version, failed the download, and said nothing — every
    existing install kept running its stale binary with no signal. Still non-fatal: the
    session starts normally.

2026-10-11 — v0.0.35 shipped without binaries: phantom ajv in connectors (FID-2026-1011-003)

Fixed

  • Restored the five missing binary assets on the v0.0.35 GitHub release, which had
    shipped empty and left every existing install silently unable to auto-update.
  • packages/connectors imported ajv/dist/2020.js and ajv-formats without declaring
    either, so they resolved only from a root node_modules/ajv holding ajv 6.15.0 plus
    stale ajv v8 files from an earlier install. Every local release gate ran green while
    all five CI Build binary jobs failed after npm had published. Declared ajv ^8.17.1,
    ajv-formats ^3.0.1, and — found by this FID's own import sweep — @savant-code/common
    (workspace:*), then regenerated bun.lock (ajv hoists to 8.20.0 and eslint's ajv 6
    nests under eslint/*). Backfilled the tarballs from main (4d2369bd, workflow run
    38184652261) with no version bump, per docs/public-release.md.
  • The install-independent guard for this class is registered as T188, blocked on the
    operator ruling for the release gate battery (T186 precedent).

2026-10-11 — Public release validation excludes the unpublished SDK (FID-2026-1011-002)

Changed

  • Scoped public release build, typecheck, test, and committed-head validation
    to the CLI release and its repository dependencies. The default release
    publishes only savant-code, but validation ran the SDK build, typecheck,
    and test chain — so an unpublished workspace could fail the release gate.
    Added build:release, typecheck:release, and test:release to
    package.json (12 workspace legs each; build:sdk filtered at
    scripts/validation-gates.ts:276, root chains swapped for the release
    chains at :279,282). The full root workspace gates remain available for
    development and CI and are unchanged — release coverage is exactly root
    coverage minus the sdk leg, omitting the same savant-free, scripts/tmux
    pair as the root chains (T186). Verified: fid:verify --check 3/3 PASS
    against the final archived bytes, the recomputed fingerprint matching the
    stored sha256:22f98686… at closure entry, and the focused suites at
    21 pass / 0 fail.

Truncated to GitHub's 125000-character release-body limit; the complete section (126098 characters) is in CHANGELOG.md.