flutter_agent_harness 1.0.681
flutter_agent_harness: ^1.0.681 copied to clipboard
Cross-platform AI agent harness for Dart and Flutter: streaming provider adapters, agent loop with tools, session persistence, context compaction.
Changelog #
Older entries: CHANGELOG_ARCHIVE.md — moved out
on 2026-10-09 (gh-1452): pub.dev server-rejects a publish whose
CHANGELOG.md exceeds its 262144-byte content cap, so this file keeps a
bounded recent window and scripts/check_changelog_size.sh fails fast when the cap is
approached. Since gh-1522 this file is CURATED-ONLY: add new lines under
## Unreleased and the release folds them into the tag's section at
publish-staging time — the published artifact's changelog is generated
(and trimmed under the cap by stamp_staged_release.sh), and the
publish job only WARNS on this repo file, so this file's size can never
block a release again.
1.0.681 #
-
fix(gh-2003): the Copilot picker filter is tier-aware. Individual-tier
/modelsresponses omitmodel_picker_enabledentirely, so phase 1 dropped every such entry as «picker flag absent» and individual/OAuth accounts still listed zero usable models. When the response comes from the individual tier — the individual host (api.githubcopilot.comor pi-mono'sapi.individual.githubcopilot.comspelling) or a no-proxy-ep token (individual by design) — an ABSENT flag is now selectable: absence ≠ an explicitfalse, which still drops everywhere (embeddings, completion-only). Business/enterprise answers keep the strict picker list unchanged, and the keep is never silent: the fetch note names it («2 of 2 models kept via the individual-tier fallback (picker flag absent)») through the existingfetch notes:surfacing. pi-mono parity: the trigger mirrorsallowPolicyFallback = baseUrl === "https://api.individual.githubcopilot.com"inpackages/ai/src/auth/oauth/github-copilot.ts. -
fix(gh-1990): the Copilot
/modelsdialect never answers a silent empty list again. Every silent-empty exit names its branch through the newfetchModelsForEndpointReportdispatch (ModelsFetchReport+ModelsFetchDiagnostic): the token-exchange HTTP status (with the OAuth device-flow / fine-grained PAT remedies for classicghp_…keys), the/modelsHTTP status or timeout (with the seat + per-tier host hint), proxy-ep-less individual tokens aimed at a business/ enterprise configured host (the tier-misrouting hint), and the picker filter with per-model drop reasons (picker flag absent,picker flag false,policy disabled,no tool_calls,endpoint unsupported) — «12 models fetched, 12 filtered (picker flag absent)». A failed primary credential path retries the other path ONCE before declaring empty (dual-path fallback, gh-1606): an exchange-401 classic PAT tries PAT-direct (the provenance note names which path answered), a fine-grained PAT never falls into the exchange, an OAuth token never becomes a direct PAT Bearer. Surfacing:/modelsprints afetch notes:section per provider, the/provider copilotconnect flow prints the named failure before manual entry, the app's model quick-select (EndpointModelsController.emptyReason) renders it under the field, and the Copilot connect sheet shows the reason above the manual model id. The legacyfetchModelsForEndpointanswers are unchanged (parity); the filter criteria themselves are unchanged (pi-mono parity — only the reporting is new). Review round 2: thefetch notes:wiring covers the unsaved sibling paths too (the active-catalog and env-keyed Copilot fetches surface the same named failure instead of a silent seed fallback), the connect flow'sno models:line reusesModelsFetchReport.reasonText(the last hand-rolledmessage — hintjoin), and theModelsFetchReportdocs scope the diagnostic contract to the dialects that name their failure branches. -
feat(network): channel payload sender block — app members' channel messages carry
{"text": …, "sender": {"name": …, "id": …}}(public base64 JSON and keyed fanet1 plaintext alike), so DAP agents can attribute the HUMAN author behind the fa_network relay's hub id. The harness unwraps it tolerantly (raw text passes through), rides the name asAgentMessage.fromNamethrough the fabric, and the CLI steering line greets people again:from Uladzimir (<relay id>) in #channel: helloinstead offrom 3cfaee1aa054fe6e…. The app falls back to the payload sender for bubble names when the envelope carries none; DMs also name hub peers from the whois cache. Legacy payloads without the block decode exactly as before. -
feat(gh-1956): reply auto-spill — oversized child
reply/agent_messagepayloads spill to anagent://artifact automatically; the parent receives a bounded excerpt + pointer + completeness marker with char AND byte counts. Manual chunking degrades to a documented fallback, restorable across parent resume via durabledeliverable_artifactrecords, behind thesubagents.replyAutoSpillkill switch (default on; honored on the CLI and the app host alike). Rework round: the salvage hook (output-truncated deliverable calls) restores the durable ids before allocating its own (no post-resume pointer shadowing), durability losses emit a[deliverables]diagnostic line, the app host honors the kill switch, the spill-reach gate is renamedspillAppliesTo(wasspillApliesTo), byte counts are encoded once per spill, andDeliverableRecord.artifact(bytes)is optional again so external constructors keep compiling. -
fix(#1947):
schedule_messagefrom the orchestrator no longer misroutes into a finished subagent's mailbox. A background shell job started by a CHILD registered its settle continuation inside the child's subagent zone; when the job settled after the child's run ended, the CLI's settle-wake (_onShellJobSettled→_startRun) started MAIN's reaction run still carrying the finished child'sactiveSubagentId(), and every identity consumer of that run misattributed it — the reported shape was a self-reminder scheduled "in -
fix(gh-1948):
task_observeworks on a RUNNING background subagent instead of crashing with an uncaughtSessionExceptionon the<parentSessionId>/<agentName>placeholder. Three legs: the executor flushes each child's transcript incrementally at every turn boundary (the JSONL exists and grows mid-run — also crash-resilience for aborted children),task_observeresolves a placeholder handle's real session file from the sessions tree (the sameagent: subagent/parent:/id:header scan the boot adoption uses) and heals the handle onto the found path, and every read failure degrades to a structured "transcript unavailable" / "no transcript available yet" message instead of an uncaught tool error. The child-transcript reader rides the transient-ENOENT retry (issue #427) — it reads while the executor appends. -
fix(#1941): the selected CodeMie project now rides EVERY model request. The header is baked into
Model.headersonly by the connect-time switches (gh-1809), so every other rebuild silently droppedx-codemie-project— and the backend bills a header-less request against the user's DEFAULT project (codemie-codeheader-injection.plugin.tscontract): the reported symptom is limit-exhausted from the exhausted default project despite picking a budgeted one. Rebuilds now re-resolve the project from the saved entry through one helper (projectHeaderForBaseUrl): the boot folder-state restore (JWT entries previously booted header-less — the SSO cookie patch was the only boot carrier), the session-resume re-apply (_buildRestoredModel), the roles-chain failover (ModelRef.project, mirroring the #964 authHeader leg), the roles-mode/model+ settings-flow pins, and the generic/providerswitch. The models list (/llm_models, SSO + JWT + guided setup + entry dispatch) and the quota adapter (dark until pinned) scope themselves to the same project, so display and billing can never diverge. Tests pin the header VALUE on the wire (real adapter over a fake endpoint) for the restored and failed-over models. -
feat(network): private networks created outside the app surface after sign-in.
GET /api/networks/mine(fa_network#16) is synced into the wallet after OAuth/dev sign-in and both restore paths — best-effort, silent on older backends (404) and any failure, and never destructive. Synced memberships keep the server's name/class, preserve local passwords/join facts, and land without a password (the endpoint never returns one) until the first join. Entering such a network — sidebar, ⌘K/⌘3-9, or a restored selection — opens the join sheet prefilled with the network id instead of a resume error or endless spinner; joining by name now keys the wallet/session by the echoed canonical id and migrates legacy name-keyed rows (password + channel keys) instead of duplicating them. A malformed/minerow is skipped, not the whole list. -
fix(gh-1931): one render per tool call on the non-TUI console. Line mode and the headless
-plog printed every executed call twice — a start row (• bash · cmd, no elapsed) followed by the end row (✓/✗ bash · cmd 0s). The duplicate start-row print is gone from_onToolExecutionStart; the end row (command, status glyph, elapsed, failure news) is the single render per call. The TUI keeps its running card + settled card, start bookkeeping stays (_toolStartsfeeds the end row's detail/elapsed, the waiting coordinator still arms per-call liveness), and persisted artifacts (session JSONL, trajectory records) are untouched — rendering-only change. Long foreground calls keep the gh-1055 liveness reminders pastwaiting.toolLivenessSeconds(default 60s). -
fix(gh-1929): esc during the pre-flight auto-compaction no longer crashes the CLI. The compaction layer's deliberate abort (#1085) used to escape
_runPromptoutside its guarded body and reach the root zone handler via an unlistenedwhenCompletechain —fa crashed: CancelledException+ crash.log + a lost session view. The pre-flight window (submit on an over-window transcript) now translates the cancel into a user-cancel outcome: neutral dimsubmission cancelledreceipt (nevererror:), the TUI composer hands the typed text back (sendInputText) so a resubmit is one Enter away, headless exits 130 with the same receipt, and the next prompt works (the funnel's local-trim recovery or a retried compaction). Cancels DURING the run — in-flight relief, settle funnel — keep their pinned loud-abort surfaces, and the post-run window keeps itscompaction interruptedreceipt via the shared_renderUserCancelhelper. -
feat(1923): stall-proof steering. Steering arriving while the loop awaits an UNPRODUCTIVE provider submit (zero bytes, or silent past the steering stall window) now cancels the attempt via a
SteeringInterruptFirecancel, injects the pending steering into the rebuilt request, and resubmits — the #1916-class submit stalls can no longer queue user or agent mail invisibly. Productive streams keep next-boundary semantics; the interrupt never consumes a retry attempt, and the run latch re-arms in place so watchdog replays and user aborts keep working.task_resumecaps its foreground wait (liketask_send) and continues in the background; video polling honors soft-yield checkpoints (remote render never restarted, honest hand-back text) and media generation honors run cancellation; SLO-breached undelivered child mail surfaces intask_status(UNDELIVERED … past the 2s delivery SLO); the TUI printssteering queued — provider stalled Ns, interrupting to deliverplus the delivered ack. -
feat(1916): image-heavy submits no longer livelock — byte-based
images.maxBytesPerRequest(default 8MB, layered onto the count cap;/imagesnames both drop reasons), legacy text-embedded data-URL screenshots in history fold into the once-only registry instead of replaying raw forever, stall watchdog windows scale with the outbound payload (capped at 2x; explicit connect clamps untouched), abandoned connect attempts answering during the retry backoff are adopted, and repeated identical-payload stalls fire ONE actionable /compact + image-budget advice. TUI stall banner + docs/images.md carry the image-heavy playbook. -
fix(gh-1912): Add an agent → DAP now turns a retired hub's unknown
enroll_createresponse into an actionable upgrade message instead of exposingbad_frame. Independent enrollment never falls back to the legacy same-name credential rotation endpoint, and existing credentials remain untouched on failure. -
fix(gh-1913): Add an agent is usable on narrow phone screens: scope and format choices wrap without per-character labels, enrollment controls stack at full width, and actions remain reachable by scrolling. Desktop keeps the segmented layout; phone/desktop light/dark goldens guard both.
-
fix(gh-1825): DAP agent enrollments carry a stable, independent
agentInstancethrough app/CLI bundles, persistence, direct boot and reconnect. Independent same-name agents keep distinct identities and stay online together, while legacy bundles retain their project-scoped identity. -
feat(gh-1825): DAP private-channel sends now use self-describing
fanet1frames (sender X25519 key in the frame, channel-bound AAD) viafa_hub_client0.2.11, so fa_network app members decrypt them without a whois/senderKey round-trip. Inbound channel frames openfanet1first and fall back to legacydap/1payloads. Verified live in both directions between a headless DAP agent and the Flutter app. -
feat(gh-1825): the network offline banner now has a Reconnect now action which restarts the socket and reloads the channel/member snapshot. Fresh sockets also clear a stale offline flag (the server sends no historical drain to a socket that was away during recovery).
AgentNetworkController.startstops after disposal instead of notifying a dead controller. -
feat(gh-1825): the roster sheet shows access-scope badges (whole network vs N channels, decoded additively from Member.access in snapshots and presence.changed) and owner/admins can drop an agent (DELETE /api/networks/{id}/agents/{agentId} with confirmation; the server tombstone keeps it out of future snapshots). Guests and store members are removable too via DELETE /api/networks/{id}/members/{id} (sessions revoked server-side); owner/admin/self rows stay protected.
-
feat(gh-1825): channel/network management in the app — rename a channel (PATCH), delete a channel or an owned network (REST DELETE with confirmation and state/navigation cleanup), and unnamed CLI/hub-created channels show a short friendly label instead of the raw 64-char id.
-
feat(gh-1825): pasting a DAP invite no longer demands a passphrase on macOS — importing NEW channel secrets auto-provisions a random passphrase into the per-channel Keychain item (decryption of existing envelopes never auto-generates; env/prompt/headless behavior unchanged), and passphrase warnings now name the concrete recovery (re-paste the invite to re-encrypt, or set DAP_KEY_PASSPHRASE).
-
feat(gh-1825): the network online counter opens a live-first roster sheet (names, member class, presence), and the channel composer offers roster-filtered @-mention autocomplete — the draft keeps the literal @displayName for DAP agents and the envelope carries the resolved member ids. On the CLI side the DAP channel notice names the agent's own identity (display name + agentId), and inbound channel mail that @-mentions that name (case-insensitive, word-boundary — no email or @name2 false positives) is marked "[mentions you — you are @name]".
-
fix(gh-1825): the app's network roster no longer reads as permanently empty ("0 online"): fa_network sends roster.snapshot with an OBJECT payload ({members: [...]}) and the app only accepted a bare list, so every snapshot silently decoded to zero members. Both shapes are now accepted, with a production-shape regression test. The DAP paste hint names web alongside CLI/macOS/iOS (plain-web join is supported).
-
fix(gh-1825): resumed CLI sessions rejoin their DAP channels and receive channel mail again — session replay now re-arms membership synchronization (plugin session-ready listeners on boot/resume and in-process switches) and idle channel probes complete deferred joins before inbox peek/drain. The post-replay sync also dials the membership's OWN hub with its enrolled credential before joining: a resumed session-scoped agent used to stay on the zero-config local URL forever, and because a disconnected fabric probe short-circuits before the sync, the remote dial never happened — the session-ready listener now drives it directly (throttled to one attempt per 10 s). App channel history no longer flashes raw payloads on first open: decoding waits for startup's channel listing instead of caching an undecoded guess until a manual switch.
-
feat(gh-1825): the fa app consumes the same DAP enrollment block as the CLI — paste it into the agent chat composer (macOS/iOS/Android; the smart-paste .txt chip path included) and the channel join happens without the block ever reaching
sendText, analytics, or session records. Native joins ride the live agent-fabric hub repository: per-project scoped identity, invite pub/priv import, keyless public channels, reconnect-persisted membership in a dedicated secure enrollment store (Keychain/Keystore where available). Harness additions:HubMessagingRepository.joinChannel/waitForConnectionwith rejoin-before-drain on reconnect, keyed channel decrypt (hubDecryptPayloadWithKeyPair), public showcase payloads, andHubBearerTransport(nativeAuthorizationheader or the browser?token=equivalent; authed dials never stringify transport errors into logs). Plain web joins through the browserWebHubTransport(?token=bearer equivalent, IndexedDB identity); the browser extension rides the service worker's existing DAP client (hub.joinop), never a panel-local second connection. Add agent now defaults to the DAP tab with a paste-into-chat hint; web gains ai-native provider sign-in through the existing popup/callback OAuth flow. -
fix(fa_network#4): the app inserts hub agents arriving via
presence.changedinto the roster (additive displayName/class fields) instead of dropping them, so the online counter no longer sticks at 0 when an agent comes online afterroster.snapshot; legacy frames without those fields create no phantom members.roster.snapshot/REST contents are logged for decisive presence debugging. -
feat(gh-1825):
/network+ scoped DAP channel membership — join by paste (invite url / url+keys / bare channel id / wholefa dap importcommand) with session/project/global scopes, live join without restart, per-scope leave + copy invite, and the composer-paste shortcut into the same wizard. Session scope rides adap_channel_membershipcustom record (leave tombstones, branch resume); project scope is.fah/dap.json(committable,dapkey1PBKDF2+ChaCha20-Poly1305 encrypted keys); global keeps the legacy~/.dapfiles. Headless CI:DAP_CHANNELS_JSON(+DAP_HUB_URL,DAP_CLIENT_SECRET,DAP_KEY_PASSPHRASE) joins at boot with zero prompts, plaintext or encrypted privs mixed. Passphrase chain: env → per-channel macOS Keychain item → one prompt with save default. -
feat(gh-1844): media slots never fall back to the main connection implicitly — SDK/CLI, app store, and the JS bridge resolve a slot without an override as UNCONFIGURED with an actionable "configure the slot" error; the main connection serves a slot only via the explicit per-slot
useMainConnection: trueopt-in (YAMLmodels.slots.<slot>.useMainConnection/ app's "Same as main connection" pick, preserved throughmedia_models.json). Image and video generation accept multimodal input (text + reference images: sandbox paths, http(s) URLs, base64) on capability-declaring OpenRouter endpoints (input_references+ declared/probedinput_modalitiesgate; unsupported endpoints fail before any network call); the OpenRouter video job API is a first-class video dialect (submit → poll → mp4). Newdecidetool: structured decisions via OpenRouter's Decisions API (/v1/systemone) — bool/choice/score questions with calibrated probabilities, structured error results, no streaming. -
feat(gh-1834): the FinalizeGate contract counts a parity/conformance claim as verified only with negative + combination self-checks — new numbered step 2.6 in
prompts/cli/finalize_gate.md(refused incompatible/mutually exclusive options, empty/corrupt inputs, boundary values, must-NOT-work cases, alongside happy paths; a blanket "everything matches" is not verified). Universality: abstract example only, no benchmark/task/flag names in the prompt; the step is conditional, so tasks with no conformance claim see no gate change. Ledger/verdict wire formats unchanged; validated end-to-end by the scripted IT-4 replay (real CLI + real bash) whose persistedtask_ledgercarries the rejection rows. -
fix(gh-1832): release v1.0.635 published without
fa-extension.zip— the landing-page download 404'd. The extension's only producer (the dailybuild-macos.ymlbuild-extension leg) derives its tag as "latest+1 at its own dispatch moment"; on 2026-10-24 thev1.0.635tag was cut byauto_releasebefore those legs ran, so the extension (and the DMGs) landed on an orphanedv1.0.636draft while the tag train published v1.0.635 — every leg green, nothing asserted the published asset set. Nowscripts/release_required_assets.txtis the single source of truth,scripts/assert_release_assets.shgates therelease-provenancepublish flip (a missing asset leaves the release a draft and fails the run loudly) and a newrelease-asset-smokeci.yml job post-publish probes every landing-page release link + the full required set (red on non-200). Remediation: the exact-tagfa-extension.zip(built from the v1.0.635 tree by run 40064876732) was uploaded to release v1.0.635 — the landing link serves 200 again. -
fix(gh-1820): the arm64 DMG leg's stale size floor is reseeded onto the shipped v1.0.634 shape — run 4004758753 (post-#1815 SPM-lane adoption) passed the min-platform gate and the full build, then failed the
size_manifest.py+5% budget onApp.framework/App+5.1% (25,020,112 → 26,284,144, the accumulated Dart AOT of #1793/#1794/ #1796/#1805/#1806); the committedscripts/size_budget/fa-macos-arm64.tsvwas still the pre-#1096-diet floor (TOTAL 210.5 MB vs the artifact's 116.4 MB), so the documented intentional-growth remediation applies: the floor is now the exact--reseedoutput for the failing run's artifact manifest (26 rows ≥ 64 KiB + TOTAL 116,386,369, from the run log's printed table — the zip never uploaded past the gate), locking in Fa 23.4→18.6 MB, quickjs_bridge 950→844 KB; newtest/ci_1820_macos_arm64_size_floor_test.dartgates the shape green through the REALsize_manifest.py checkand pins the committed floor byte-identical to a--reseedround-trip. -
fix(gh-1814): the desktop DMG lane ADOPTS the SwiftPM lane — Flutter 3.47.7 removed the FLUTTER_SWIFT_PACKAGE_MANAGER disable knob (flutter/flutter#193978), so the gh-180 pure-CocoaPods pin became a no-op and the min-platform gate (which forbade any SwiftPM state) failed both DMG legs on every pinned-3.47.7 run (39991663029, 40022900373); the #1813 escape (pin 3.47.4) is unreachable on the ~60kB/s runner link.
scripts/assert_macos_min_platform.shnow ASSERTS the SPM lane instead: SwiftPM state expected afterflutter build macos --config-only, generated package floor ≥ the app floor (the silent bump must not skip — the original gh-180 killer), no SwiftPM product above the app minimum, vendored inappwebview manifest floored at 14.0 if it ever reappears. Floors were audited and need no raising: Runner pbxproj 3×14.0, Podfile:osx, '14.0', generated floor 14.0 on 3.47.7, vendored podspec 14.0 (its Package.swift stays deleted — the plugin rides the CocoaPods half of the hybrid lane via Podfile.lock). The dead env pin left the build-macos job env; the SDK pin reverts #1813 back to 3.47.7. The ci.yml macOS debug leg gets the same treatment (gh-1814 review): its FLUTTER_SWIFT_PACKAGE_MANAGER=0 pin — a silent no-op on the floating 3.47.x stable it resolves past the knob's removal — is removed and the lane comment corrected; the leg rides SPM enabled as it already has been (run 399572012 green). -
fix(gh-1805): modifier chords no longer type their base letter into the composer while the slash menu is open — the vendored dart_tui decoder puts the base letter into the keystroke's
textfor control bytes (Ctrl+S →ctrl+swith texts), and the slash-menu edit cluster was the one insert surface missing the_isCommandKeystrokeguard, so a chord pressed mid-menu poisoned the typed prefix (/memorylanded as/smemory). Plain letters and Shift+letters still type and filter. -
feat(1515): ONE model-limits settings surface — the settings hub's standalone "Model parameters" row is retired and bare
/model-edit(TUI) aliases into/settings→ Model capabilities, pre-focused on the active model. The caps flow gains the model-edit preset ladders + Custom… free input for context window / max output (a preset pick writesmodels.overridesAND rebuilds the active model on the spot — the old flow's live-mutation semantics, now durable), every field row shows the current EFFECTIVE value with its source layer (pinned/role override/catalog), the thinking row is an omp-style selector (only levels the model supports, per-rung budget metadata, current level preselected), and the hub row describes the effective summary (200K ctx · 16K out · thinking off) instead of a pin count. The scripted/model-edit <field> <n>form and the line-mode limits print are unchanged. -
feat(gh-1746): opt-in session disk retention —
sessions.retentionin~/.fah/config.yamlcaps the sessions root and sweeps whole session units (transcript + sidecars) oldest-last-used-first at boot, exempting live, named, young, and the current session; nothing is EVER auto-deleted without the section (byte-identical legacy boot). Addsfa session clean [--dry-run], the/sessions+fa session listusage footer under a cap, and header-cwd/path-escape guards so a planted session header can never steer a delete outside any root. -
fix(gh-1763): a
bashtool command running broad process kills can no longer signal its own shell or the harness. Scripts are delivered from a per-exec private temp file (sh -c '. "$1"' sh <script>) so the wrapper argv never carries the script body (pkill -f <pattern>cannot self-match its ownsh -c;$0/$#/exit codes/set -e/stdin stay identical), a PATH shim forpkill/killallplus akill()prelude guard exempt the harness pid chain + process group (exported asFA_PROTECTED_PIDS) and the invoking shell from the child's own kills while legitimate victims (stuck test runners, background servers) are still terminated, and headlessSIGTERMaborts now logfa: SIGTERM received …so a child-issued kill never masquerades as a user Ctrl+C (exit code contract unchanged: 130 graceful, 143 escalate). -
fix(gh-1778): the release gate no longer reds a fully-green shard when GitHub's cache service degrades. v1.0.621's
Core tests (shard 2/4)was killed by its owntimeout-minutes: 12with 2535/2761 tests green — both cache steps had stalled ~133 s on keys that existed (degraded service, not eviction), coldpub get+ native-asset hook builds delayed the first test to ~5 min, and the shard needed ~14 min against a budget sized for the warm ~8.8 min wall. The job budget is now 20 min (sibling test-leg band), and bothtest-corecache steps are best-effort (timeout-minutes: 2+continue-on-error: true) — a failed restore is slower setup, never a red shard.test/ci_core_shard_timeout_guard_test.dartpins the budget and the best-effort cache contract (RED-first on the old YAML). -
feat(#1761): the 32KB project-context budget never cuts silently again. A file truncated to its head excerpt now carries an extended
<!-- From: path — N bytes, only the first M shown -->marker plus an explicit MUST-read-the-full-file instruction (offset/limit/ranges, prompt copy inprompts/context/project_context_read_full.md); a file dropped entirely leaves a one-line tombstone naming its path instead of vanishing; and the user gets a dim boot line per truncated/dropped file (CLI line mode prints directly, TUI re-prints after the banner, the app logs through its AppLog boot-notice seam). NewprojectContext:config section:maxBytes(default 32768) —0disables the section entirely and reads no files (fast boot); unknown keys are tolerated with a note. Leaf-first allocation is unchanged. -
fix(gh-1757): the Android build no longer re-enters the sdkmanager download roulette for CMake. v1.0.619's
build-androidleg died at:jni:configureCMakeDebug[arm64-v8a]— the:jnimodule (transitivejnipackage via path_provider_android) wires externalNativeBuild.cmake with no version, so AGP auto-installed its defaultcmake;3.22.1mid-configuration and one corrupt archive ("Archive is not a ZIP archive") red'd the leg, the aggregate Quality gate, and the Advance-vpinned-marker job. The gh-1655 pre-install action now also pre-installscmake;3.22.1with bounded retry + idempotent skip (same hardening the NDK path already carries); the guard test pins the new AC6 assertions and the AGP-version coupling (AC7). -
feat(#1750): per-model image caps — the outbound request never carries more unique images than the target model accepts.
Modelgains an optionalmaxImages(catalog-seeded:gemini-4-argon: 10, measured);images.perModel.<modelId>config overrides it (strictimages:section, user truth wins); the registry resolvesperModel > catalog > images.maxPerRequest(first present wins, the issue-#1554 shape). A Google-shapedtoo many images … maximum allowed for model <id> is <n>400 is classified (image_overflow.dart, the overflow.ts twin), latches the learned cap for the (provider, model) pair for the run, and re-sends ONCE through the registry at the smaller cap — current-first-then-newest drops with the existing never-silent notices naming the learned cap; a second refusal surfaces exactly as today. JSONL is never rewritten;images.registry: falsekeeps the byte-identical legacy shape including the recovery-off behavior. -
feat(gh-1760): oversized user-message intake spills to a file instead of blowing the context window. Any incoming user message — headless
-p/positional, TUI first/mid-session, steering/follow-up drain, external inbox — whose text passes the new relative threshold (aspills.userFractionof the live window budget minus the compaction reserve, floored byspills.userThresholdbytes) is redacted and written verbatim to.fah/spills/<sessionId>/user-<n>.md(the #678 layout) from one choke point (Agent.userMessageGuard); the model receives a bounded head+tail preview plus a read-in-parts instruction riding the replacement USER message (copy inprompts/spill/user_read_instruction.md). Images stay inline, a refused spill write degrades to today's inline behavior, andspills.enabled: false/userThreshold: 0/ the newFAH_USER_SPILL_THRESHOLDenv knob (bytes) keep the legacy shapes. -
fix(gh-1743): a structured compaction that hits its total-budget watchdog (the factory's 300s
totalBudget) no longer aborts the live session.AutoCompactorFactory.run()now applies the mechanical local-trim fallback (keepRecentTokens, pairing-repaired,[context trimmed locally]marker — the same valve the classic pass ladder ends on) instead of failing fast; the honest both-roles-failed verdict is kept only when nothing is droppable. -
fix(gh-1636): auto-compaction stops dumping the internal checkpoint summary into the console — the default report is ONE marker line (
● auto-compacted · engine: N → M tokens (F freed · P%)); the records line + fenced summary moved behind the newtui.showCompactionDetailsopt-in (default false), and the manual/compactstill prints the full block. The headless log face no longer streams the summarizer deltas by default (the gh-1433 E4 live stream is part of the same opt-in; the gh-1430… reasoningliveness line still covers the window). Nothing is lost — the summary stays in the session file, reachable viacompact_expand. -
fix(test): gh-1732 — the
wrap_ansi_line_perf_testsustained-contention validation leg spikes 3 of the 5 doubled runs per attempt instead of 4 (CI run 39546301132, core shard 2/4: the old shape left exactly ONE real-wall-clock-timed doubled sample per attempt, and real jitter on that single sample — the very shape being modeled — inflated all three attempts' min ratios to a 3.30x best against the 3.2 bound while the real 500k growth legs on the same runner stayed green). 3-of-5 is the documented live-red shape ("≥3 of the 5 timed runs"): median-of-5 [c,c,s] is still a spiked value, so the leg still proves the pre-gh-1532 median harness fails, and the min harness now rides two clean doubled samples per attempt. -
fix(#1705): CLI fresh-install boarding asks the provider choice FIRST — the same list the
/add-providerpicker shows (presets,Customlast) — and onlyCustomcontinues into the api-type wizard; a preset opens its own flow with the api type prefilled. Previously boarding opened the custom wizard directly, cold-asking "api type" before any provider was chosen. -
feat(providers): gh-1704 — first-class Codex/ChatGPT credential export, CI refresh action, and Provider Queue integration (Copilot-export parity).
fa provider export <name> [--check]resolves the saved ChatGPT login's OAuth blob from its secure-store slot, refreshes it when stale, and prints the shell lines (OPENAI_API_KEY+OPENAI_BASE_URL= the Codex backend — these tokens never serve api.openai.com); the refresh token never prints and--checkreports credential health with the SSO caveat./provider chatgpt import [path]adopts an existingcodex loginsession (~/.codex/auth.json) into the same slot — no browser round-trip..github/actions/chatgpt-codex-authmints a fresh access token from aCHATGPT_REFRESH_TOKENsecret in CI (direct curl, no third-party action); invalid_grant fails fast and loudly.providersQueue:entries speakchatgpt-codex: an omittedapiKeyEnvresolves the Keychain slot automatically (in-memory refresh), a newrefreshTokenEnv:field mints the initial access token on slot activation, and a raw Bearer token inapiKeyEnvis tolerated bychatgpt_codex.dart(no more FormatException — proactive/reactive refresh degrade, a 401 surfaces as the auth death the queue fails over on). -
feat(bench): gh-1681 — leaderboard submission readiness. ATIF trajectories: new
exportAtifJsonwhole-snapshot exporter (lib/src/trajectory/atif_export.dart, ATIF-v1.7 — the schema harbor 0.23.0's flagship adapters emit) behind a headlessfa trajectory export [--format atif] [--output path]verb; the harbor adapter runs it as a bounded best-effort exec after the agent phase on every terminal path, so<trial>/agent/trajectory.jsonreaches the hub with the other agent logs (the leaderboard static analysis requires one per rewarded trial) andresult.jsonmetadata carries anatif_trajectorypresent/missing marker. The golden fixture (bench/harbor_fa/fixtures/atif_sample.json) is pinned Dart-side and cross-validated against harbor's pydanticTrajectory+validate_trajectoryintest_atif_contract.py. Workflow: asubmission: truedispatch input turns the submission rules into hard setup preflights (full task coverage, ≥5 attempts/task, no agent-timeout override, pinned dataset) and makes the new per-shard ATIF presence gate fail hard; default runs gain only a warn-only scan (artifact flow unchanged). Runbook: docs/leaderboard-submission.md (pinned dataset + @latest content-hash recording, quota-window runner policy, lb CLI steps). -
fix(headless): gh-1589 — the headless session becomes a SEALED artifact: no session-JSONL writes land after the run's agent phase ends. New
Session.seal()(state in the writer, no file-format change): raised inrunHeadless' finally and the REPL teardown as the LAST session action (close order: drain → usage fold → seal → exit, one implementation both paths — REG-2), it makes every writer (_persistMessages,shell_job_registrysnapshots, compaction, anyappendCustomEntry, leaf moves) drop late appends with exactly ONE stderr warning per writer class — never a throw into an unhandled zone; the exit code stays the turn's terminal outcome (issue #413 semantics untouched). The settle→reaction path is sealed with the file (I2): the drain wrap-up raises a fence (_reactionRunsSealed) so a background-shell settle or task completion arriving after the final answer's drain — including the registry's one-turn-deferred listener racing_finishHeadlessDrain's check-to-return window (the 65gGW7b 10:13:42–10:14:00 burst) — does board bookkeeping only: no_startRun, no model request, no record. An honest drain's records (final answer → seal) stay legal (E7); the seal is per-run state, so resume/replay/session_repairare unchanged. Adapter side (bench/harbor_fa, I3/AC4+AC7):run()/perform_taskreturns only after the fa process exited on EVERY path — the ladder kill became terminate-and-reap (SIGTERM → bounded exec await → SIGKILL escalation → pgrep confirm), and the external-cancel paths (harbor's own wait_for firing first, the no-knobs exec, external-cap-only mode) now fire the kill + bounded reap before propagating, with a loudagent-phase exit guarantee degradedstderr note when fa survives both signals (never a silent proceed, never an unbounded hang). -
fix(bench): gh-1643 — a trial killed mid-stream no longer reports 0/None usage. The fold read only FINALIZED assistant messages, so a run killed before its first assistant message (the costliest rows) folded to silent zeros. Both folds now price a dangling
model_request_summaryat its KNOWN request-side volume (system prompt + outbound message chars at the shared chars/4 rate, estimated input; output unknown) and mark the usage incomplete instead:UsageChainScan.usageIncomplete→usage.json(usageIncomplete: true, written only when set so completed folds stay byte-identical),SessionUsage.usage_incomplete→ the tb adapter'susage-guard.jsonrow and harbor'sagent_result.metadata, and the post-mortem stampsusage_incompleteon every results.json row it patches from a partial fold. Harbor also exports the run outcome class (agent_result.metadata.failure_mode: agent_timeout self-kill / external_kill / completed / crashed / never_started) so downstream classification stops relying on exception.txt archaeology; a summary superseded by another summary is flushed instead of silently dropped on both sides. Never-started trials keep the gh-1638/gh-1576 audit-only precedence (no fake usage). -
fix(stuck-calls): gh-1632 — a stuck tool call in an interactive session now escalates like everywhere else.
effectiveStuckTool()defaulted every non-headless host toStuckFollowUpMode.advisorywhen no explicitagent.stuckTool:was configured, so the fa 1.0.580 incident session (a deadgit fetchin the REPL) fired itstool_stuckflag at the 300 s threshold and then hung for 27 more minutes — advisory mode never cancels, retries, or converts; only the owner's manual steering broke the deadlock. The autonomous default (cancel → retry once → background-convert, then a session-visible escalation) now applies in EVERY mode;advisoryremains an explicit opt-out (agent.stuckTool.followUp: advisory), never an implicit default. -
fix(bindings): gh-1624 — the gh-1570 binding preflight no longer kills translating-proxy factories.
_validateModelEndpoint's vendor-prefix verdict was fatal on ANY endpoint, soFA_PROVIDER_TYPE=anthropic+ bifrost's/anthropicpath +zai/glm-5.3exit-64'd every boot on 1.0.576 (the prefix is a routing key on a translating proxy, not a dialect declaration). The vendor-prefix check now fires ONLY on the endpoints that carry a dialect verdict — the three family-exclusive canonical vendor endpoints (api.anthropic.com, api.openai.com, generativelanguage), mirroring the family verdict's scope: those keep the gh-1570 fail-fast, ROUTERS (OpenRouter/Copilot/DIAL/kimi — the prefix is a routing key there too; OpenRouter's canonical ids areanthropic/claude-*) and unknown/private endpoints carry the mismatch as aProviderModelBinding.warningsentry, never exit 64. The warning is rendered on EVERY resolve path (gh-1624 review): theFA_PROVIDER_*boot notice, the provider queue (per entry at boot, on queue reload, and in/provider queue test), and the--model/--base-urlflag revalidation — a rider never boots silently. Breaking-change note for 1.0.576 upgraders behind proxy factories: the migration is thewire:FA_PROVIDER_CONFIG key — documented now (README env-preconfig section, docs/agents/providers.md §Translating proxies,--help) with its caveat: the override engages only when the declared wire DIFFERS from the provider record's own kind (record anthropic + wire: anthropicstill runs the checks). REG matrix (AC1/AC2/AC3) pinned intest/model_roles/provider_model_binding_test.dart; AC4 IT drives a bifrost-shaped loopback proxy through the production anthropic adapter (test/model_roles/bifrost_proxy_binding_test.dart). -
gh-1596: the first-run wizard (
site/setup.sh) no longer crashes or corrupts input undercurl | shon dash (Ubuntu sh) or busybox ash (Alpine):scripts/gen_installers.dartnow renders the provider/mode/ approval menus from the live provider catalog into plain POSIX sh — the bashisms that killed dash (printf -v,read -p) and silently corrupted busybox ash are gone; the hidden API-key prompt usesstty -echo+ a by-nameread(dash has noread -s) and the key never rides printf argv; EOF/Ctrl-C mid-wizard aborts non-zero with no half-written~/.fah, and non-TTY runs print guidance and exit 1. The wizard's temp config ismktemp-created (no predictable, symlink-followable fixed path). A new path-triggeredinstaller-portabilityCI leg proves the script under dash + busybox ash (ubuntu) and bash (macOS) on everysite/**or generator change. -
fix(cli): gh-1572 —
faboot no longer rewrites~/.fah/config.yamlfrom a lossy config.persistConfig(bin/fah_runapp.dart) built a freshCliConfigcarrying only some fields andpersistConfig()ran unconditionally at boot, so every launch silently dropped the user'sspills:,subagents:,jobs:,headless:,agent:,quota:,tui:,trajectory:,waiting:,power.holdandauto_updatesettings (first reported on 1.0.547). Three cooperating fixes: the boot save is nowsaved.copyWith(<live overlays>)so every parsed section rides along by construction;CliConfig.copyWithreplaces the drifted hand-rolledwithCustomProvidersfield list (itself dropping spills/subagents/waiting/jobs/agentMode/misuseBreaker/streamThinking insidesaveCliConfig's merge step); the_diskPreservedSectionsdisk backstop covers every known top-level key.spills:renders intoYaml(newSpillsConfig.toYaml) andagent.misuseBreaker: falsepersists too; an unchanged save no longer rewrites the file at all. Rework round: the boot snapshot re-syncs from disk after every sanctioned mid-session settings write (onUserConfigFileChanged— a cleared context cap, anauto_updatekey drop or a global compaction pick is no longer resurrected/overwritten by the next save in the same session);validateAgentSection(the strictfa config check/config set/ settings-hub mirror) accepts the emitter'sagent.misuseBreakerandagent.stuckToolkeys sofa config checknever false-fails on fa's own output; clearing the context cap drops only the cap key instead of the wholeagent:block (the siblingmode:/misuseBreaker:keys survive); and theprovidersQueue:block (no typed renderer) joins the disk backstop so a save can never silently delete the user's queue. Rework round 2 (merge + guards):validateAgentSection's per-key switch became the_agentKeyValidatorstable (the two gh-1572 keys pushed the switch form to complexity 13 — over the repo's CRAP ratchet; the table keeps the mirror complete at complexity 4), and the last two direct USER-config writers —_writeTtsrSectionand_writeMcpSection— fire the re-sync hook, so a mid-session ttsr rule toggle or mcp server edit survives the next persist too (the writer roster insettings_flow_config_sync.dartis now exhaustive). -
gh-1606: the
copilotprovider accepts fine-grained PATs (github_pat_…) directly — PAT mode skips thecopilot_internal/v2/tokenexchange entirely (GitHub 404s every PAT exchange) and sends the raw PAT as the Bearer against the configured Copilot base URL with the official Copilot CLI's first-party identity headers (copilot-integration-id: copilot-developer-cli,user-agent: copilot/<fa-version> (<os>) term/unknown, installed by the host at startup). OAuth device-flow tokens keep the exchange + proactive-refresh flow unchanged; a PAT 401/403 surfaces the error instead of a doomed refresh retry. HeadlessCOPILOT_GITHUB_TOKENnow works with a PAT. Connect flow: the paste hint explains PAT mode, the dead-PAT case surfaces at the model fetch, and/provider exportcopies the saved Copilot account's full token to the clipboard (account picker on several entries; the token never prints to the transcript). -
gh-1575: macOS clipboard paste fixed for TIFF-only pasteboards + the Ctrl+V text fallback.
_readMacosprobes«class TIFF»after PNGf/JPEG miss and converts viasips -s format png(a Preview/browser copy used to dead-end onclipboard holds no image; a failed conversion keeps the unavailable fall-through and every scratch file is cleaned up); newreadPasteboardText(pbpaste/ xclip+wl-paste / PowerShell Get-Clipboard) behind the same injectableProcessRunner/platform:seam, and Ctrl+V with a TEXT clipboard now inserts the clipboard text into the composer instead of printing the image probe's dead-end reason — bracketed-paste routing, gesture pairing and silent-failure semantics unchanged. Review pass: the WindowsGet-Clipboardread pins UTF-8 console output and normalizes embedded\r\n(OEM-code-page mojibake), the Linux text backends pintext/plain;charset=utf-8(an image-only clipboard can no longer leak bytes as "text"), the library doc no longer overclaims theFA_FAKE_PASTEBOARDseam, andFaTuiCallbacksmoved to afa_tui_callbacks.dartpart file keepingfa_tui.dartunder the 2800-line gate. -
gh-1555 (W1, lazy/windowed-everywhere reads): the legacy full-open call sites migrate to windowed opens, so a session ledger past the gh-1073 2 GiB full-open backstop stays openable on every user-facing read path. The TUI session picker,
/resume, and the boot name-resolution scan open windowed and resolve the display name through paged reads; the subagent transcript preview opens the child windowed (tail only); the_loadSessionmarathon fallback no longer degenerates to a refused full open when the boundary walk exhausts its page cap (it proceeds with the tail-anchored windowed session; the boot cap owns over-window residue); and the headlessfa trajectoryresolver opens windowed, reading the whole ledger for the cost/inspect views through the newSessionTree.ensureWholeLedgerResident— a sequential forward scan in bounded strips (WindowedSessionStorage.loadAllOlder), not the boundary-walk's doubling strips (whose per-strip record cap measured ~13x read/parse amplification over the whole file). The same change block-prepends paged chunks in_indexChunk(oneinsertAllper list), removing an O(n²) the suspended-eviction walk paid per record. Trajectory export streaming (AC3a), split-and-retain rotation activation (W2), and the opt-in write-side caps (W3) remain follow-up work. -
gh-1605: the FinalizeGate gains a "grader parity" named check. A produced entry point (script/CLI the verifier will run itself) is only verified when it survives the grader's own invocation: the checklist must re-run each produced entry point from a different working directory in a fresh subprocess with a clean env, capture stdout/ stderr/exit code, and diff against the earlier in-session run — any divergence (different output, relative-path artifacts, locale/ encoding-dependent output) is a
failledger item, never a pass. Closes the modernize-scientific-stack__nwbgy7a near-miss (every in-session checklist item passed, the verifier's clean-cwd subprocess collapsed Station 102 to Station 101's mean, reward 0.0). REG coverage: the parity procedure catches cwd- and env-dependent entry points and does not false-positive cwd-independent ones (test/agent/finalize_gate_grader_parity_test.dart), and an IT replays the evidence shape end-to-end — divergence detected and persisted as afailledger item before finalize. -
gh-1603: unattended runs can no longer end as a clean success on empty model responses. Loop: from the second empty-hiccup retry on, the request carries a continuation nudge user message ("your last reply was empty/truncated — continue the task"; exact-text constant
emptyContinuationNudge, emitted with MessageStart/End so the transcript stays truthful) — a cap-truncated reasoning model re-streamed verbatim repeats the empty outcome, the nudge breaks the symmetry; the classifier treats that exact message as transparent, so the turn's partial-content window (gh-1577) survives a nudged retry. Headless: the empty-reply nudge budget rises toAgentCliConfig.headlessEmptyReplyNudges(default 2 — the session ends only after 3 consecutive unrecoverable empties; interactive keeps the #1085 M2b one-nudge semantics), and a run that still settles empty prints the explicit__FA_INCOMPLETEmarker and exits 1 — a distinguishable failure for the bench adapter, never a silent exit 0. -
gh-1577: an empty assistant completion after partial content (assistant text, tool activity, or a truncation signal earlier in the turn) is a bounded-retry provider hiccup — up to
emptyHiccupRetries(default 3) re-streams with exponential backoff (emptyHiccupBaseDelay,emptyHiccupMaxBackoff, both threaded through theAgentfacade,AgentWiringSpec, and the CLI config), and exhaustion ends the run with a loudStopReason.error(headless exit 1, interactive error + prompt) instead of the silent exit-0 settle that killed the gh-1577 trials. Clean empties keep the #1085 M2b one-nudge semantics. The abort always wins: a cancel racing the final retry settlesStopReason.abortedfor any empty shape (the exit-contract race is pinned by tests), and the backoff sleep is cancellation-aware. -
gh-1574: SQLite reads work on installed binaries — bundle libs land where the binary looks. The AOT binary's native-assets resolver reads
<exe_dir>/../lib/<name>(thedart build clibundle layout), but every POSIX installer copied the bundle libs beside the binary (<install_dir>/lib), soread path=x.dbdied with a raw FFI dump (Couldn't resolve native function 'sqlite3_initialize' … Failed to load dynamic library '~/.local/lib/libsqlite3.dylib'); it only worked on machines with a manual symlink in~/.local/lib. Fixed the layout in all three install paths —site/install.sh(incl. the quarantine-xattr pass and the source-build advice),install_local.sh, andfa update(bin/self_manage.dartcopyBundleLibs, now public and layout-pinned by tests; also aligns Windowsfa updatewithinstall.ps1, which was already correct) — plus clean degradation in the FFI engine:Sqlite3Engine.openReadOnlyclassifies the dart:ffi resolver's library-load failure (isSqliteDynamicLibraryLoadFailure) and throws a cleanSQLite is unavailable — reinstall or run fa updatenote instead of the raw resolver dump; a Dart-level system-library fallback is impossible with package:sqlite3 native assets (build-time asset mapping, no loader override). Installs already broken by the old layout self-heal: on the bundled library's first failed load the binary moves the stale<exe_dir>/libsqlite3.*into<exe_dir>/../lib/and retries the load (repairStaleSqliteBundleLayout) — so onefa updatesuffices (the successor binary repairs on its first SQLite read; a pre-fix binary cannot repair itself), and the stale<bin>/libleftovers disappear as they migrate. The POSIX installers also report a failed lib copy instead of swallowing it (site/install.shwarns naming the lib dir; same ininstall_local.sh), andsite/install.sh.templatecarries the same layout so regenerating the installers cannot resurrect the old one. -
gh-1556: bench pipeline stops bleeding score + fa deadline awareness. Bench: the harbor ladder kill uses the
[f]abracket trick and is wrapped so a kill failure can never replace theTimeoutError(the pre-fix self-matchingpkillclassified TB 2.0 ladder kills as agent crashes — a SOLVED task scored 0); progress-watch (stall-gap 360s per the gh-1430 watchdog invariant, flat abs ceiling 3600s) is the bench-harbor.yml default on every shard, with the harbor adapter picking the gap-awareProgressWatchfor parity with the terminal-bench adapter; the aggregate counts completeness byresult.jsonpresence (errored trials report as their own breakdown line; exit 1 only on genuinely lost trials) and renders the full report — table, errored breakdown, ledger row — to$GITHUB_STEP_SUMMARY(TB1 parity). Both bench adapters exportFA_DEADLINE_EPOCH_MS(effective cap − 120s wrap-up margin) into the agent session and audit the exact value. fa core: deadline awareness —FA_DEADLINE_EPOCH_MS/--timer/--deadline//timerwrite one session clock, the per-turn context carries atime-left:line while armed, and one-shot system notices steer wrap-up at ~50%, T-3min (drain background jobs), and T-30s; absent deadline = byte-for-byte today's behavior. -
gh-1522: tag-sourced versions — the git tag is the single source of truth. The release-bot file bumps are retired: cutting a release = a tag + GitHub Release (zero commits to main, zero file mutations). Both pubspecs carry the fixed
0.0.0-devplaceholder (CI guards hand-bumps), the publish job stamps the staged pubspec + generated changelog section from the tag (scripts/stamp_staged_release.sh, staged version == tag guarded pre-upload), store builds stamp--build-name/--build-numberfrom the derived tag version (pubspec.lockstops churning across releases), andinstall_local.shstampsversion.txtfromgit describe. -
feat(usage): gh-1460 — the
fa-tokens:segment-close line carries the session's model id, so every token row the factory publishes is attributable to a model and therefore priceable. The fold now captures each segment's LAST-SEEN model id (the model that served the final request, the same string settings/UI display — mid-session fallback take-overs attribute the segment to the model that actually finished it; zero-filled fallbacks never clobber a seen model) and the pinned line shape grows an OPTIONAL"model":"<id>"key after"segment"— omitted when no model was observed, so legacy lines parse unchanged and the pinned regex (usageTokensLogPattern, gh-1241 AC7) keeps matching both shapes. usage.json's schema is untouched (the model is rebuildable from the chain, I6); old consumers using tolerant JSON ignore the new key, and the repo's single strict consumer (the pinned constant) is updated in the same change. -
fix(test): gh-1460 rework — the
wrap_ansi_line_perf_testgrowth-shape legs measure the doubling ratio with the MINIMUM over 9 runs instead of the median of 5 (CI run 38112524699, core shard 0/4: a scheduling pause inflated the doubled-size median — 12.09ms against a true ~7ms — and tripped the 3.2 bound at 3.65x on a genuinely linear wrap). Runner jitter only ever inflates a wall-clock sample, so the min converges on the true compute time; genuine superlinearity still trips the ratio (the gh-1496 quadratic candidates measure ~4x by min). The absolute- budget legs keep the median — their gh-1357 headroom already prices in jitter. A synthetic regression test pins the pause-proof property.
1.0.506 #
- fix(#1044): AIIN mobile/macOS add-provider — sign-in completes but the provider is never added (#1194)
- fix(ci): pass flutter-version explicitly — awf no longer defaults a toolchain (#1205)
1.0.507 #
- gh-1208 [BENCH] fix-git task image broken on CI runners — docker compose build fails in BOTH TBench-1 runs (unknown_agent_error, trial never starts) (#1218)
- gh-1206 WIP auto-save 2026-10-04T05-52-28 (#1216)
- gh-1209 [BENCH] usage fold skips failed trials — agent_timeout rows report 0/0 tokens though the session JSONL has full usage (#1123 follow-up) (#1215)
1.0.508 #
- fix(cli): gh-1459 — headless
fa -pno longer orphans live background shell jobs._awaitHeadlessBackgroundJobsdrained only in-flight subagent jobs, so a run whose model was still waiting on abash background:truecommand (gh-1440's full test suite) printed the detach summary and exited, killing the job with the container — the result it was explicitly waiting for never reached anyone. Live shell jobs now drain exactly like subagents: the settles ride the existing_onShellJobSettledfresh-turn path (steered into reaction runs the drain awaits, loop capped at 10 rounds), suppressed jobs (suppressSettleNotification— result already landed in-turn) are not awaited, and a settle landing outside a round still gets its reaction run awaited before exit. BOTH loops share ONE wall-clock ceiling, the newheadless:config section (shellJobDrainMs, default 30 min, strict parse;0restores the detach-immediately behavior) — a never-settling watch-loop detaches with an observable⏳ … drain ceiling … — detachingline instead of hanging headless, and the detach summary stays the documented degradation, never the default path. The drain prints a⏳ waiting: …line (#1055 parity) naming what the run stays alive for. While it waits, the drain also steers interim liveness notices (gh-1459 ask #4): everyheadless.shellJobQuietMs(default 5 min;0= off) of a still-running awaited shell job, ONE compact system-notice (job <id> running · <elapsed> elapsed · tail: …plus the bash_job output/stop escape hatch) keeps the model able to wait, inspect, or kill instead of blocking blindly to the ceiling; a crossing the model probed itself (bash_job status/outputbumps the entry's probe generation) is skipped, one steer budget per threshold, never a spam loop. - feat(providers): issue #1398 — stall-recovery tuning becomes per-provider
and data-driven. Registry entries (
customProviders:,models.custom:, roles chain entries,providersQueue:entries) accept optionalconnectTimeoutMs/streamIdleTimeoutMs(strict positive-int parsing); resolution is entry > theproviderTimeouts:section > the 180 s/300 s defaults, per field, and every seeded entry prints its effective values at boot. The wire seams (sendWatchedProviderRequestconnect watchdog,createSseIteratoridle watchdog) resolve per request URL, so all adapters inherit the tuning; runs without entries are byte-identical (AC6). Also: the retry backoff contract — a parseable delta-secondsRetry-Afterwins over the ladder for that attempt, hard-capped at the 60 s ceiling (the clamp names the advertised value;0counts as absent, malformed/HTTP-date headers fall back to the ladder with a trace note) — and the dual retry budgets (connection-class cap 4, stream-class cap 3, independent counters, the terminal story carries both). Trace lines pin the formatbudget=<connection|stream> attempt=<n>/<cap> delay=<ladder|server|clamp>; the tuning report prints per-model p50/p95 inter-chunk gap + watchdog-fire counts with thestreamIdleTimeoutMs ≈ 2× p95recipe (the production feeder lands with #1392's LatencyMeter). - feat(hosts): gh-1322 — the wireAgentCore host-adoption gaps: an embed
guide (
docs/embedding.md, with the explicit "hosts ride wireAgentCore, never adk_dart" rule), the host-facing key-slot resolver (AgentCoreServices.resolveKey+HostKeyResolver— the effective slot NAME, pinned-twin drift hints identical to the CLI's migration notes, registry-legknownSlotNames, injected env/store readers only), and lifecycle telemetry for in-process hosts (AgentCoreServices.telemetry: the pure interface + in-memory ring in core, the fa.log file sink behindlib/io.dart; requestStart/firstToken/turn/tool/run records with durations and the provider HTTP status). - chore(ci): document the sm-kicker head-completeness codeless-head crash
(upstream awf#15) — the factory job's
gh apicalls put--jqbefore--arg/--argjson, so a CODELESS branch head (2 parents, 0 changed files: a routine branch-sync merge with no content diff) crashes the job withaccepts 1 arg(s), received 4— even when CI is fully green on that head, and the job's own rescue dispatch can never heal exactly those heads. Workaround until the upstream fix: keep the branch head code-bearing. Live instance: run 37193754301 on head 1fe9b1232. - fix(messaging): gh-1180 —
schedule_messageself-chains no longer die silently at the agent-chatter wake cap. The idle inbox-wake gate (InboxWakePolicy, shared by the CLI and the app hosts) now exempts a delivered scheduled self-reminder ([scheduled]prefix, from == to) from the 10-consecutive-wake streak: a deliberate agent-chosen cadence (night watch, periodic sweep) wakes forever, while foreign agent-to-agent chatter stays capped (anti-storm REG) and user-kind mail always wakes. A 30s cadence floor bounds a zero-delay re-schedule spin (E5). Refused wakes are visible ([mail] wake refused, once per episode) and every lifecycle step is receipted to<messagesRoot>/_scheduled/receipts.jsonl(ScheduledReceiptLog): scheduled / delivered / delivery_failed / scan_failed / wake_attempted / turn_started / wake_refused. A failed scheduler scan (transientlistDirerror) now re-arms atfailureBackoffwith anonErrorlog instead of silently disarming the delivery heartbeat. - fix(messaging): gh-1180 review round — refusal receipts and the
visible refusal line are gated once per refusal EPISODE (the latch
lives in
InboxWakePolicynext to the streak and re-arms on the same resets), so a held gate no longer appends per-tickwake_attemptedrows (~43k duplicate lines/day) and a repeat episode after user input is announced and receipted again. The app host receipts its wake path (wake_attempted/turn_started/wake_refused) onto the same trail — AC4 is no longer CLI-only. A self-reminder adopted across a session-id change delivers FROM the live mailbox (from re-addressed alongside to), so the resumed chain stays self-shaped and exempt instead of falling back to the capped chatter lane. Plugin-only pending batches are explicitly classified as chatter (the contract is stated, not accidental), the wake cap is single-sourced fromInboxWakePolicy.defaultMaxInboxWakeStreak, and the policy file lost a stale copy-pastedignore_for_file.
1.0.509 #
- chore(pin): awf workflows track @main — always-latest policy (owner
directive 2026-10-04). All five machine-loop stubs (teammate, SM,
merge, sm-kicker, merge-trigger) flip from immutable SHA pins to
dmtools-agentic-workflows@main, so awf fixes (kicker real ticks awf#13, per-SHA concurrency awf#14, teammate defaults awf#12) go live on merge with no re-pin ceremony. Security trade-off (owner-accepted): a mutable ref executes whatever sits at the awf main head — mitigated by awf main being review-gated, bytest/machine_kit/factory_stub_ref_test.dartnow guarding ALL FIVEuses:refs resolve to exactlymain(never a stale SHA, never a random ref) in lockstep, and by the agents ENGINE pin staying an immutable 40-hex SHA viafactory_ref. Thesecrets:policy is settled per-callee in the same guard: teammate/sm/merge mapSOURCE_GITHUB_TOKENexplicitly (their factories declare it required), while merge-trigger keeps the factory-documentedsecrets: inheritPAT passthrough (factory-merge-trigger declares no secrets) and the kicker carries no secrets block. Stale immutable-SHA pin comments in ai-teammate.yml / machine-sm.yml rewritten to state the always-mainpolicy (#1222).
1.0.510 #
- gh-1226 [BUG] 1.0.505 (with #1190 aboard): mail-wake turn after /sessions restore still loses the provider/key binding — copilot-401 error on a z.ai session + fused guidance text (#1237)
- gh-1199 [GOAL] Deterministic-only Quality gate: mock LLM everywhere, live models move to supervised benches (#1229)
- feat(1101): Agent Wire Protocol v1 — web reference client (sdk/web), conformance runner, browser example (#1228)
- gh-1224 [BUG] iOS 1.0.504: all wasm interpreters (python/qjs/lua/sqlite3) dead — 'no lazy loader' in FOREGROUND bash _forJob() clone drops moduleLoader (regression suspect #1163) (#1225)
1.0.511 #
- gh-1164 [GOAL] built-in js-apps skill (promoted from app asset, decisive apps-vs-widget routing) + JS render/runtime errors reported back to the authoring agent as failures (blocked by #1151) (#1246)
- gh-1244 [FLAKE] PTY integration: secret_sheet_test «IT-mask: masked from the first keystroke» waits for exactly 5 bullets while typing races ahead (red main, run 37232401938) (#1245)
- gh-1241 [GOAL] Session token-usage ledger: resume-aware usage.json fold over the session chain (provider-reported, estimated marked) (#1243)
- ci(quarantine): skip scheduled_indicator_test.dart in the gate (flake, https://github.com/IstiN/flutter_agent_harness/issues/1252) (#1253)
- gh-1077 [GOAL] flutter_app compaction parity with CLI — mobile sessions never compact (roles/smol absent, wrong context window, silent failure, no over-window relief) (#1239)
- ci(quarantine): skip job_board_stability_pty_test.dart in the gate (flake, https://github.com/IstiN/flutter_agent_harness/issues/1250) (#1251)
- gh-1235 Wire jsr.openUrl + webView host into the app JS engine (js_widget_runtime = 0.4.154) (#1238)
- gh-1226 [BUG] 1.0.505 (with #1190 aboard): mail-wake turn after /sessions restore still loses the provider/key binding — copilot-401 error on a z.ai session + fused guidance text (#1237)
- gh-1199 [GOAL] Deterministic-only Quality gate: mock LLM everywhere, live models move to supervised benches (#1229)
- feat(1101): Agent Wire Protocol v1 — web reference client (sdk/web), conformance runner, browser example (#1228)
- gh-1224 [BUG] iOS 1.0.504: all wasm interpreters (python/qjs/lua/sqlite3) dead — 'no lazy loader' in FOREGROUND bash _forJob() clone drops moduleLoader (regression suspect #1163) (#1225)
1.0.513 #
- fix(1096): reseed fa-extension size floor for intentional js-apps skill growth (gh-1164) (#1258)
1.0.514 #
- fix(#1197): TUI frame pipeline self-heals a throwing view/render (gh-1197 AC3) — a mid-run render exception now logs loudly, invalidates the diff state (no stranded DEC 2026 BSU), and repaints instead of dying or freezing; PTY liveness regression test proving paced thinking + answer text + a long silent tool call paint continuously (AC1/AC2/AC4), via the scripted stream's new paced
chunks/pace_ms,thinking, andsleep_mssteps
1.0.515 #
- gh-1292 fa-tokens line must reach stdout in headless/CI runs (ledger emission invisible to the GH log) (#1295)
- gh-1296 [BUG] iOS build red in CocoaPods layer: package:sqlite3 build_hook fails — Podfile.lock drift (pods cache re-rolls weekly) never-again: ALL lockfiles committed + enforced (#1298)
- feat(1096): mac size diet — wasm_run_flutter.framework + never-loaded assets, ratcheted (#1227)
- chore(merge-trigger): track awf @main + map_pr_labels: true (#1285)
- ci(quarantine): skip secret_sheet_test.dart in the gate (flake, https://github.com/IstiN/flutter_agent_harness/issues/1283) (#1284)
- fix(1280): CLI arch matrix gates the merge; release binaries boot-smoked (#1282)
- gh-1276 [BUG] iOS: memory_search returns garbage + memory_list hides user-scope notes (agent fell back to memory_delete by exact text) (#1281)
- ci(quarantine): test/integration/theme_readability_pty_test.dart (flake) (#1255)
- gh-1274 [BUG] iOS sandbox bash: relative paths resolve to a nonexistent CWD — files written in the sandbox are invisible to relative-path commands (still broken on 1.0.512 after #1225) (#1279)
- gh-1266 [BUG] nightly red: macOS flutter_app suite — 5-test cluster around apps panel / open_app launcher / dynamic_message tiles (suspects #1139, #1173) (#1278)
- gh-1275 [BUG] Built-in skills (#1151) not packaged into the apps: iOS ships EMPTY skill dirs (create-goal/fa-self-config/js-apps exist, SKILL.md missing) — verify macOS/Android too (#1277)
- gh-1272 [BUG] [URGENT] 1.0.512 TestFlight (build 205): EVERY JS widget dead — engine eval error 'Unterminated regular expression literal /[ ⇥' on all widgets (source corruption in assembly/catalog path) (#1273)
- gh-1265 [BUG] nightly red 5 nights: native desktop builds broken by a TRANSITIVE flutter_inappwebview nobody declares — linux WPE missing + windows MSVC 14.51 STL1011 (lockfile not committed) (#1268)
- gh-1261 [BUG] Play listing deploy fails: clear_images! HTTP 400 — invalid image_type "images" for en-US/phoneScreenshots (daily-publish Play leg red) (#1264)
- feat(#1079): SDK slice 2 — live agent-stack wiring (wireAgentCore); CLI converts to the shared builder (#1230)
- gh-1197 [BUG] TUI fixes (recovered dev leg) (#1263)
- ci(quarantine): skip dap_wake_hang_test.dart in the gate (flake, https://github.com/IstiN/flutter_agent_harness/issues/1248) (#1249)
- gh-1073 Session JSONL grows unboundedly (12 GiB ledger records) → resume fails with 'Failed to read session' + heap-exhaustion crash (#1247)
- fix(1096): reseed fa-extension size floor for intentional js-apps skill growth (gh-1164) (#1258)
1.0.516 #
- gh-1299 [BUG] [URGENT] main red 13 legs: release commit v1.0.515 bumps version WITHOUT regenerating pubspec.lock — new --enforce-lockfile (#1268) hard-fails every leg (#1304)
1.0.517 #
- gh-1299 [BUG] [URGENT] main red 13 legs: release commit v1.0.515 bumps version WITHOUT regenerating pubspec.lock — new --enforce-lockfile (#1268) hard-fails every leg (#1304)
1.0.518 #
- gh-1307 [BUG] nightly macOS suite red: js_app_error_capture_test — load error NOT captured (empty list) regression from #1273's engine fix, merged green through the PR exclusion-zone hole (#1309)
- fix(918): omp_ref reference fixtures captured on PTY host + nerd-glyph parity wiring (#1231)
- gh-1310 [CI] Tag CI for v1.0.513 red — 4+ jobs fail (Android APK, web debug, Hostile ambient env, PTY screenshots) → release asset-less, legs fall back to v1.0.511 (#1312)
- gh-1303 [CI] Pages 'Build landing + web demo' red on main — '41 packages have newer versions incompatible with dependency constraints' (blocks publish + merge-trigger) (#1305)
- gh-1299 [BUG] [URGENT] main red 13 legs: release commit v1.0.515 bumps version WITHOUT regenerating pubspec.lock — new --enforce-lockfile (#1268) hard-fails every leg (#1304)
1.0.520 #
- fix(1250): assert frozen-row invariant, not an unsampleable mid-drain frame (#1286)
- gh-1300 [ENH] PTY integration tests: pay toolchain+boot ONCE per shard, not per test (~30s spawn overhead × N tests) — boot-once + reset between tests (owner design), FA_BIN AOT seam as the cheap first cut (#1306)
1.0.521 #
- fix(1248): dart_tui guard misfires ghost mail-wake turns — log-and-keep-running (#1289)
- gh-1257 [FLAKE] PTY integration: convert the 5 residual exact-bullet-count anchors (secret_sheet_residual_test / password_prompt_pty_test) to the gh-1244 property anchor (#1287)
1.0.522 #
- fix(ci): play edit-commit sets changesNotSentForReview (#1367)
- fix(1339): surface recovered trials, terminal failure modes, and model ids in the bench summary (#1351)
- feat(1331): iOS size diet — IPA dSYM strip + never-loaded fixture prune + ratchet (#1333)
1.0.523 #
- gh-1341 Bump js_widget_runtime pin to 9d57570 / ^0.4.156 — flutter_js hostCall/capture channel fix (fa-craft lag, voxel-sandbox spinner) (#1366)
- fix(1349): deny bare long foreground sleeps; enrich liveness reminders with the background hint (#1355)
- fix(1293): dap start exit-0 guarantees the dial credential is durably on disk (#1354)
1.0.524 #
- ci(quarantine): skip shell_job_countdown_pty_test.dart in the gate (flake, https://github.com/IstiN/flutter_agent_harness/issues/1365) (#1347)
- fix(1368): pub.dev publish — push-tag-only OIDC path, dart-only gate, verify waits instead of false-alarming (#1370)
- fix(1339): review hardening — session-archive traversal guard on every branch (#1369)
- fix(1323): live thinking streams in the TUI — reasoning deltas commit the transient-retry attempt (#1325)
1.0.525 #
- ci(quarantine): skip subagent_integration_test.dart in the gate (flake, https://github.com/IstiN/flutter_agent_harness/issues/1372) (#1373)
- fix(1254): quarantine dracula theme-flake + wait headroom for starved shard (#1288)
- fix(1234): whole-tree CRAP ratchet 12→8, loc-gate migration, all top offenders fixed (#1291)
- fix(1252): widen scheduled-indicator reminder window past loaded-runner pre-check (#1290)
1.0.526 #
- feat(1322): wireAgentCore host-adoption gaps — embed guide, host key resolver, lifecycle telemetry (#1327)
- fix(1319): route paging history notifies through the guarded bridge (follow-up to #1320) (#1324)
1.0.527 #
- gh-1393 [GOAL] Mobile agent parity: bash-identical sandbox shell (glob/grep/cd/dev-null) + first-class jsr widget testing (jsr.test.*, check_app) (#1401)
1.0.528 #
- feat(1379): Compaction 2.0 second tier — agent-initiated hide, LRU re-hide, per-segment pins (#1383)
- fix(1402): pre-flight Play listing language gate + edit-discard on commit failure (#1405)
- feat(1380): obligations ledger substrate — verbatim entries + level-0 context block (A1 slice 1) (#1382)
1.0.529 #
- feat(1377): auto_update tri-state flag — notify banner, autonomous verified self-update, /update (#1384)
1.0.531 #
- fix(1406): bench ConnTrace dark inside tmux — launch-line env + loud-empty guard (#1416)
1.0.532 #
- ci(quarantine): skip pty_resume_equivalence_test.dart in the gate (flake, https://github.com/IstiN/flutter_agent_harness/issues/1422) (#1423)
- ci(quarantine): skip composer_echo_pty_test.dart in the gate (flake, https://github.com/IstiN/flutter_agent_harness/issues/1413) (#1414)
1.0.533 #
- gh-1412 [GOAL] Near-miss elimination: FinalizeGate contract + TaskLedger — the agent verifies produced state against task text before declaring done (#1418)
- gh-1403 [daily-publish] testflight leg failed (#1424)
- feat(bench): per-task test-budget override table + planner fairness guard (gh-1407) (#1417)
1.0.534 #
- fix(1408): harness-induced bench failures — isolated job logs, redacted at rest, shape-only bash interceptor (AC1–AC3; AC4 documented) (#1410)
- gh-1415 [GOAL] Subagent status line-language: one compact live row per subagent in the CLI TUI (omp-density, ten named deltas) (#1420)
1.0.535 #
- gh-1426 [GOAL] Model capability negotiation (rework): the resolver's loud
notes now ride the built
Model(capabilityNotes) and render on the status surfaces —/model-editprints them next to the resolved triple, and the single-model boot prints them in the boot notice — so a gated pin (E3), an override-vs-endpoint divergence (E1), and a catalog-miss override (E4) are never silent. Also:applicationNote('models')says "applies live to the next model build" (the flow live-applies; "next boot" was wrong), the duplicate_capabilitySummaryForcollapsed onto_capabilitySummary, the two capability remove paths share one_removeCapabilityYamlbody, the omit-max-output menu row names its adapter scope ("openai-completions only"), the deadresolveModelRefCapabilitiesexport is dropped, and the resolver's ceiling-table lookup and documented wire field both read the same effective api (api ?? spec?.api). - Behavior change (gh-1426, deliberate — AC6): pre-existing
thinkingLevelpins (aroles:chain entry, theFA_PROVIDER_CONFIGpreconfig, or amodels.overridespin) now reach the wire for the first time on the openai-completions family (reasoning_effort) and google (thinkingConfig); onorigin/mainthey were carried but wire-silent there. Consequences: (1) REG-1's "no overrides → byte-identical payload" corpus holds only for sessions with NO thinking pin at all — a session with a bare roles pin changes payloads by design; (2) an endpoint that rejectsreasoning_effort(strict gateways, o-series rung spelling) can now 400 where it previously worked — unpin the level (/settings → Model capabilities → thinking level → off) or pinomitMaxOutputTokenswhere the max-output field is the problem. The boot note that claimed the openai-completions adapter "is not wired" to the config-carried level is corrected and now fires only for the genuinely unwired adapters (dial, copilot, chatgpt-codex).
1.0.537 #
- feat(1374): animated two-tone kaomoji thinking indicator — app + web TUI (#1419)
1.0.538 #
- gh-1433 [GOAL] Workflow log fidelity: non-interactive headless renders EVERYTHING the model says — thinking deltas AND assistant text, default-on (the post-hoc log IS the UI) (#1437)
- gh-1425 [GOAL] Resume loses structured-compaction folds — marathon session reopens at 143% of window make fold projection resume-equivalent and cap every detonation path (#1427)
- gh-1430 [GOAL] Headless stream-liveness: fa must heartbeat provably-alive reasoning streams, and the bench stall-gap must defer to fa's own watchdog (round-4 RCA: 13 tasks ≈ 16% killed mid-thinking) (#1436)
- chore(1431): reseed fa-extension size baseline for the 3.47.7 engine rev (#1432)
- gh-1409 [GOAL] Compaction-pinned skill operative lines — instructions must survive folding (image-carrier precedent) (#1428)
- feat(1374): animated two-tone kaomoji thinking indicator — app + web TUI (#1419)
1.0.539 #
- gh-1438 bash_job: resolve near-miss/stale job ids instead of 'unknown background job' dead-ends bound status output GC exited jobs (#1447)
1.0.540 #
- gh-1441 Voxel nodes render as the “Voxel world” placeholder — Fa app builds JsonWidgetRenderer without voxelWorld (fa-craft 0.2.18, voxel-sandbox 1.0.0) (#1445)
1.0.541 #
- feat(1079): SDK slice 6 — IT-5 record-level runtime parity for extension hosts (YoClip scenario) (#1456)
- gh-1449 [GOAL] Orphan-result notices: reported once, never a user turn, always identifies the call (#1451)
- gh-1439 [GOAL] Live-follow etiquette: scrolling up while the agent works never yanks the user back down (TUI + app + web: follow-mode contract + «jump to live» affordance) (#1443)
1.0.542 #
- gh-1450 [GOAL] SSO/OAuth login must always show the full authorization URL and allow opting out of the default browser (CodeMie/OpenRouter/ChatGPT family) (#1464)
1.0.543 #
- gh-1450 [GOAL] SSO/OAuth login must always show the full authorization URL and allow opting out of the default browser (CodeMie/OpenRouter/ChatGPT family) (#1464)
1.0.545 #
- ci(quarantine): skip header_badge_pty_test.dart in the gate (flake, https://github.com/IstiN/flutter_agent_harness/issues/1469) (#1470)
1.0.546 #
- chore(factory): flip engine pin to agents-rel-20261009-181034 (206a8c62) (#1474)
- gh-1477 [BUG] build-mobile Derive version: fetch-depth:0 checkout outgrew its own 10-min timeout — daily leg cancelled mid-fetch (time bomb, grows with every tag) (#1482)
- gh-1444 [GOAL] iOS sandbox ergonomics: skills resolve, networks fail loudly, secrets prove presence, timeouts tell the truth (#1453)
1.0.547 #
- gh-1446 [GOAL] TUI chrome diet: textless fold rule, running/lost-only jobs line, live activity animation in the reserved _ Fa brand slot (#1454)
- fix(1431): size gate survives Flutter rev-hash churn — normalize 20+hex rev dirs, vendored carve-out, exact-patch SDK pin (#1486)
- gh-1471 [GOAL] bench.yml: provider selection for tbench runs (zai-glm default, kimi-for-coding) with a dedicated bench key (#1475)
- gh-1452 Release blocked: CHANGELOG.md exceeds pub.dev 256 KiB cap (262 672 B on main) — v1.0.538 not on pub.dev trim + pre-flight guard needed (#1462)
1.0.548 #
- gh-1478 [ENH] daily-publish auto-filer: signal-first failure excerpts + cancelled-run digests + root-cause dedup (never-again for noise filings) (#1480)
1.0.549 #
- chore: pin factory_ref to agents-rel-20261010-170624 (fb32c3c8) — brings gh-843 ghost fix + gh-840 sweep to the fa tick; live: #1457 ghost #2 BLOCKED with green-on-head (previously cost ~2h) (#1513)
1.0.550 #
- chore: pin factory_ref to agents-rel-20261011-002034 (aa5ddd8bd78e64c9ce77a43b31bc63b40b0f8d7a) — minter fix (gh-848/#849): gh-748 never cancels pre-materialization; unblocks fa #1457/#1520 (ghost-seized) (#1527)
1.0.551 #
- gh-1459 [BUG] Headless exits with live background shell jobs (detached, results lost) — must drain+steer like subagents (gh-1440 run orphaned its full-suite job) (#1463)