v4.0.0_sync
DonSeTch v4.0.0_sync
The agent web stack, rebuilt end to end. Same four tools, same
zero-config donsetch mcp default. Faster, stealthier, more
reliable, and honest about what it knows.
Removed
web_answer(the evidence pack) andweb_memory(the local vector
store), by my call. A fixed search-then-read pipeline and a
memory-of-everything store strip the agent's control over the loop
(which link, which budget) and spend tokens on pages the agent
would not have picked. The agent owns search + fetch; DonSeTch just
makes each of those calls god-tier. The search prefetch that the
pack spawned is kept (web_fetch consumes it: a speed win with zero
new surface).
Fixed
- Persona locale is fail-closed sanitized before it can reach Chrome
--lang, CDPnavigator.languagesinjection, or an
Accept-Language header. A corrupt on-disk persona or hostile
persona.locale/ LANG value can no longer break out of the JS
array or inject header bytes; invalid values becomeen-US. - A warm ghost whose viewport/locale no longer matches the incoming
persona (quarantine re-mint) now relaunches instead of silently
claiming the old identity.web_screenshotuses the same persona
wire as tier-1. - Cross-process host-pace rows are compared by host on read (FNV
collision no longer shares a floor) and stale.tmpfiles from
failed atomic writes are pruned. - PDF glyph walk no longer panics when the first glyph's font has no
PDFium-reportable name (Type3, missing BaseFont, over-long name).
The mono-font check now bounds-checks the family index like the
sibling dingbat flag; a crafted PDF can no longer abort the process
(releasepanic = "abort") on fetch. (dondai44423#221) - Search syndication dedup keeps punctuation in the title key, so
C++ TutorialandC# Tutorial(and dotted versions like
Rust 1.75) no longer collapse into one result and silently drop
the other. Only titles that are identical after case/whitespace
normalization still dedup. (dondai44423#222) web_screenshotomittedfull_pagenow defaults to viewport on
both CLI and MCP (MCP used to silently mean full-page).- Fetch CLI long-help cites
--actions, not the dead
--browser-actions.
Changed
donsetch config showredacts bearer tokens and credential-bearing proxy
values, including proxy pools, while still showing whether each field is
configured and where its value came from.- Browser version probes now apply one deadline to process exit and bounded
stdout capture, terminate inherited-pipe descendants on Unix and Windows,
and cap captured output at 64 KiB. - Every runtime env read now flows through the typed config. The old
env names keep their exact historical trigger semantics and still
work in 4.0, but they are deprecated;donsetch doctorlists the
ones your shell still sets and maps each to its config key. The
hard cut lands in a later minor once the migration is done.
Added
-
Egress fabric (v4 A): search, crawl, fetch, and ghost share one
process-wide proxy pool with durable lane health. Burned and dead
lines survive restarts inegress-health.json(kill:
DONSETCH_NO_EGRESS_PERSIST). When a pool is configured,web_fetch
sticks to one exit per host and rotates on 429 / 407 / connect-dead /
timeout; the lane stays pinned for the whole redirect chain (never
mid-200-session). Kill:DONSETCH_NO_FETCH_ROTATE. Personas get an
exclusive lane bind: a burned or foreign-persona exit is never
reused for a new mint, and quarantine frees the lane. Per-lane RTT
EWMA feeds search pacing and surfaces indonsetch doctor --deep
as one line per lane (ok / slow / burned / dead / auth) with a named
fix. Daemon preflight still benches dead proxies before the first
query; crawl skips benched lanes and reports outcomes into the same
health world. -
Learning engine v2 (v4 B, local only): per-(engine, intent)
search trust EWMAs drive roster order (search-trust.jsonv2; empty
intent maps seed every intent from engine-global history so a
restart never re-learns a walled engine from zero). Domain profiles
stamp which egress class their cookies were learned on; a Warm
clearance vault is refused when the live lane is the other class
(home-IP cookies never ride a proxy exit). Crawl host ladders
(429 storms, robots delays) persist tocrawl-governor.json
(cap ~2k hosts, 7d TTL). Enrich/prefetch success density feeds a
capped domain quality prior (search-quality.json, ±0.08 after
≥3 samples; killDONSETCH_NO_QUALITY_PRIOR; walls and timeouts
never count). Agent-outcome feedback (must_contain miss / thin /
SoftNotFound) soft-demotesclass|hostinoutcome-feedback.json
(±0.05 after ≥2 misses; default off until the 24h soak proves
it; enable withDONSETCH_OUTCOME_FEEDBACK=1; never extra fetches).
donsetch statushas an improve line
(warm-hits, walled, cooldowns, flaky, low-trust/quarantined,
quality hosts, outcome demotes) anddonsetch doctor --improve
explains the loop in ~10 lines with live local receipts and kill
switches. No MCP tool, no telemetry, no cross-machine sharing.
A 24h soak battery still gates any public improve claim. -
Search v3: adaptive early-return cancels stragglers once ≥3
independent index families already agree on a top-3 URL (kill
DONSETCH_NO_SEARCH_EARLY). Mojeekempty-parse(blocked as HTTP
200) burns engine trust harder so it leaves the default width
instead of occupying a slot every query. Compact snippets trim to
180 chars. Query compiler splitssite:/filetype:/intitle:
out of the free text and only sends each operator to engines that
honor it (DDG lite strips them so BM25 never ranks the literal
token); post-merge filters enforcesite:andintitle:, and
filetype:keeps matching URLs plus extensionless download
handlers (killDONSETCH_NO_QUERY_COMPILE).site:github.com,
site:stackoverflow.com, and friends also join the fan-out as
that site's own API. A byte-derived SERP instant layer lifts
featured snippets / instant answers / knowledge panels out of the
organic list into their own slot with the source URL always
present (never invents text; not cached; kill
DONSETCH_NO_SERP_INSTANT). Code verticals are query-gated and
stress-aware: StackExchange only on Q&A/error language, MDN only
on web-platform tokens, HN only on release/announce; under pool
stress HN drops first. -
Doctor ultra (v4 D): broader local coverage, same fast default.
New checks: config posture (NO_CONFIG_FILE+DONSETCH_CONFIG
conflict, missing explicit file, layer report), search health
(engine trust, quarantine, quality/outcome receipts, BYOK key
state counts, C kill-switch flags), clearance stores (routes.json
counts, handles, cookie vault), crawl stores (governor host
ladders, page-history size warning past 5MB), DNS resolution
(independent of HTTP, names AAAA presence), and a captive-portal
probe under--deep(generate_204must stay 204). State
permissions now cover every secret-bearing store
(ghost-state.json,routes.json,byok-keys.json) and
auto-tighten to 0600. All new checks carry unit tests; live
doctoron a real box is green with honest warnings. -
ML-DSA ClientHello parity (v4 E1): Chrome 151 pads
signature_algorithmswith ML-DSA 44/65/87 (IANA 0x0904/05/06).
boring 5.2.0 finally names and verifies those codes, so the
ChromeTrue wire advertises them (mldsa44:mldsa65:mldsa87:at
the front). InterceptionSafe never sends them (a corporate MITM
re-terminates without ML-DSA certs). Kill:
tls.mldsa_sigalgs=false/DONSETCH_NO_MLDSA_SIGALGS. -
Persona wire divergence (v4 E2): per-domain personas now
actually drive the wire. Tier-1 Accept-Language is persona-locale
first (TLD/script kept as a lower-q preference so localized
content still lands, without the classic en-US browser speaking
perfect ru-RU JA4H tell). The ghost browser launches with the
persona's viewport and--lang, and CDPnavigator.languages
matches. Quarantined personas fall back to the default wire. -
Crawl polish (v4 F): dataset JSONL rows carry
dataset_version: 1in structuredContent; resume-token TTL is
fetch.resume_ttl_secs(default 7200, clamped 300..86400) instead
of a hardcoded 2h. Cross-process host politeness: crawls share a
per-host last-stamp file under<cache>/host-pace/so a daemon and
a CLI crawl of the same host respect one floor gap (kill:
DONSETCH_NO_HOST_PACE_FILE; corrupt file = ignore). Canonical/
binary skip and transient-vs-permanent retry were already on
master; reconfirmed with tests. -
just win-check: type-checks the crate forx86_64-pc-windows-gnu
from Linux (clippy, no linkage), both--no-default-featuresand
the full feature set, so#[cfg(windows)]breakage from a
Linux-only change surfaces before the push instead of in Windows
CI. Needs mingw-w64; see CONTRIBUTING.md. -
One typed runtime config (
src/config.rs, issue dondai44423#193): every knob
lives in a layered struct, defaults <donsetch.toml
(DONSETCH_CONFIGor<config-dir>/donsetch/donsetch.toml,
skippable viaDONSETCH_NO_CONFIG_FILE=1) <DONSETCH_<SECTION>__<KEY>
env names. Values validate loudly at load; unknown TOML keys name
the offending file.donsetch config showprints each knob with
its value and origin (--markdownfor the reference table,
--legacyfor the old-name map);donsetch doctorwarns about
deprecated env names active in the shell. -
Resurrection reaches transport-dead URLs: a TLS handshake against
a parked domain, a dead DNS name and a refused port now gate
archive=autoresurrection the same way 404/410 do, while
timeouts, resets and protocol errors stay excluded (a snapshot
must never launder an unknown, and a reset can be an IP-level
block that an archived copy would paper over). The gate reads a
newstructuredContent.fetch_errortransport class recorded on
every status-0 fetch error. -
Wayback snapshot serving survives wayback's own redirect
interstitials: a thin capture is re-checked against wayback stub
markers, and a stub chain-hops through up to 4<meta http-equiv="refresh">targets when (and only when) wayback
rewrote the target (web.archive.org/web/<14-digit-ts>/...); a
live-web refresh target is never followed, because the URL we
are resurrecting may still be dead, moved, or hostile. -
web_screenshotMCP tool: a rendered PNG of a page through the
existing tier-2 browser (url, full_page, wait_ms). The capture is
in-process only; the MCP result carries an image content block and
a text note. Verified live against a real render (PNG header,
image/png). The CLI ships the same render now that it was wired up:
donsetch screenshot URL [--full-page|--wait-ms N]prints the
receipt and, with the CLI-only--out PATH, writes the PNG with
honest failure paths (bad path or missing path = stderr + exit 1). -
h3 lane hardening (mnaza, PR dondai44423#169): every transport now exits
through one point, so decompression and wall detection also apply
to HTTP/3 responses (a challenge served over h3 no longer reports
as clean content); alt-svc routes honor the server's ownma=
lifetime instead of a constant; the HTTP/3 body reader stops at
the shared 64 MiB cap before allocating;routes.jsoncarries
serialized TLS session material and lands owner-only (0600). -
Experimental HTTP/3 lane (opt-in via
DONSETCH_H3=1) on a quiche
0.29.3 fork that shares one BoringSSL build with tier-1. An h3
route is learned fromalt-svcresponse headers (same-origin
only, proxies exempt) and persisted in the cache dir under
routes.jsontogether with the serialized QUIC TLS session. The
lane stays off by default: on repeat visits the v1 one-shot
connection shape measures slower than our reused h2 pool, and
DONSETCH_NO_H3kills the whole path regardless. The h3 Client
Hello reuses the same Chrome-true TLS builder as h1/h2.
Transport parity verified live against curl --http3 on a
1.4 MB page (852 ms vs 825 ms) and 0-RTT resumption arms and
is accepted on repeat visits; the default stays on our reused
h2 pool, which still measurably wins the same-or-faster gate. -
Local web memory for agents (
web_memorytool +donsetch memory
query): a bounded on-device index of pages this machine fetched.
all-MiniLM-L6-v2 quantized runs locally on the same onnxruntime
the search reranker uses; the model + tokenizer download once,
sha256-pinned, into the cache dir and nothing ever leaves the box
after that. Fetches, crawl pages and search snippets ingest
automatically;DONSETCH_NO_WEB_MEMORYdisables ingest and search;
DONSETCH_WEB_MEMORY_CAPbounds the index (default 4000 rows,
oldest-first eviction). Unavailable on builds without the rerank
feature: the release builds all carry it. -
Adapter registry v1 (
donsetch adapters): the named rewrite and
extract adapters are now a registry, and operators can add more
fetch-level rewrites as pure-data JSON plugins in
cache_dir()/adapters/(one file per rule: hosts, optional path
prefix, an https target template with one{path}placeholder;
no executables or scripts, the fetcher's egress guards still
apply). Bad files are skipped with a receipt and never break
fetching;DONSETCH_NO_ADAPTERS=1stays the master kill switch. -
Native keyless Google search via the legacy mobile endpoint, using
DonShadow without a browser or paid API. Seven selectable Nokia
profiles (DONSETCH_GOOGLE_PROFILE, default6230-03.15), observed
working in local tests; availability is not guaranteed. An explicit
CAPTCHA permits one next-profile attempt in the existing thin-merge
retry wave; successful profiles remain preferred per egress in
memory, with circular advancement on CAPTCHA and no profile cooldowns.
Profile selection resets on restart. HTTP 429 and other walls do
not rotate. Native and
browser Google share one ranking family but keep separate health. -
Route memory: fetches learn route health per tier (EWMA latency by
route, failure classes, LRU-bounded store). Tier 1 rides healthy
routes only; persistent failures quarantine and a background probe
re-heals them when the block lifts; a replaced route never re-enters
while still marked failed. Kill switches +donsetch statusline. -
Persona store: long-lived per-domain identity records (fingerprint
class, headers, session state) ride inside ghost pages across runs,
with a coherence checker and adonsetch statusline. -
Stealth scorecard:
doctor --stealthgrades the tier-1 battery
(TLS/H2/header classes) with conflict codes;--paritydiffs the
live fingerprint against real local Chromium (JA4/JA3/H2/vector
agreement). Weeklystealth.ymlCI alarm on profile drift. -
Tier-1 request realism: navigation-class header sets per request
class (document/rpc/embed), subresource shadow-fetching that
reproduces real page-load traffic (assets behind the primary fetch),
and tier-1 cookie persistence replaying returning-device sessions
across runs. Each subsystem carries a kill switch. -
Prewarm: search hands a warm tier-1 pipe to the first-result fetch
that follows it (hot-path time drops from roughly 550 ms wire
build-up to about 25 ms served from RAM). Served/wire split is
visible indonsetch status. -
web_answer: evidence-pack answer tool for chat-first MCP clients
(query + token budget, up to a handful of pages, ranked citation
graph, one-line answer). Kill switchDONSETCH_NO_ANSWER_TOOL. -
Crawl dataset mode:
--jsonrenders one JSON object per page
(url/title/kind/markdown/chars/fetched_at/lastmod/parent), sorted by
URL, deduped; skipped pages carry reasons. Best for machine-ready
exports; plain text stays the default. -
Crawl delta recrawl:
--since-lastre-fetches pages and compares
content fingerprints against crawl history; unchanged pages refresh
history but drop out of results and budgets with skip reason
"unchanged since last crawl". Replaces the old fixed 24 h window
that silently missed quiet mutations. -
Crawl-shape: seeded reader-like frontier ordering (head-window
jitter over the top ranks, topology preserved), so repeated crawls
of one site stop replaying an identical mechanical order to access
logs. Kill switchDONSETCH_NO_CRAWL_SHAPE. -
Adapters reach the crawl fetch path: the same rewrite pass
web_fetchuses rides inside crawl fetches; the canonical URL stays
the dedup/history key. -
Ghost browser pool: up to 16 warm browser slots keyed by persona
identity and host affinity; a repeat hit on the same host lands on
the browser that already carries that site's session state, and a
persona switch inside a slot relaunches instead of inheriting
another identity's fingerprint state.donsetch statusshows the
warm-serve receipt;DONSETCH_GHOST_POOL_SLOTSsizes the pool
(default 3),DONSETCH_NO_GHOST_POOLreverts to the old
single-slot path. -
MCP compat folding applies to
web_searchtoo: structured-content-
only clients receive raw result URLs through the folded metadata
block instead of losing them; the model-facing contract text now
states it. (dondai44423#165) -
Clarify compact search labels: counts describe search-index families
that returned a URL, not independent sources corroborating its
claims. The weak results message now refers to cross-index
agreement. Ranking is unchanged. (dondai44423#166)
Changed
- Crawl pacing cleanup: the vestigial 0-100 ms skim dwell is deleted;
self-inferred waits cap at 7 s while host-declared waits (Retry-
After) stay uncapped and honored. All pacing lives in the crawl
governor, pressure-adaptive. - Dependencies: tokenizers 0.23.2, encoding_rs 0.8.40, brotli 9.0.0,
zstd 0.14.0, psl 2.1.231, actions/checkout 4 -> 7.
Fixed
-
Security review batch (dondai44423#216-dondai44423#219):
donsetch doctorBright Data zone probe hit/zone/route_ipstwice
(a doubled path that 404'd every configured zone). The ship path now
passes the API root and builds the URL through one shared helper.- h3/QUIC dial now applies the same connect-time SSRF filter as h1/h2:
a DNS rebind to a private/loopback address between the request-time
check and the dial is refused.DONSETCH_ALLOW_PRIVATE_EGRESSstill
works as the explicit escape hatch. - BYOK provider error bodies are capped at 600 chars before they reach
the agent, stderr, or the debug log (context DoS). serpapi additionally
scrubs the URL-borneapi_keyfrom a reflected error body (key leak). - Crawl resume tokens that are not plain ASCII alphanumeric are refused
before they index the filesystem, closing a path-traversal read-then-
delete on agent-suppliedresume.
-
Browser backend aliases now share the typed enum as their single registry
and normalize casing and surrounding whitespace across config sources.
Unknown effective legacy values fail closed instead of silently becoming
auto; a valid higher-precedence modern setting still overrides them. -
The ONNX reranker now consumes the validated
search.rerank_threadsvalue
directly instead of leaking and reparsing a string, and reports configured
values as coming from the layered config.0 = autobehavior is unchanged. -
Master hardening wave (overnight full-tree audit, every finding
reproduced before fixing): -
h1: a connection that closes before Content-Length is satisfied now
fails the transport instead of returning the partial body as
success. The old reader scored truncated pages clean and stored
them in the revalidation cache as Fresh, so every later fetch of
that URL served the truncated page forever. The fix caught a lying
Content-Length in my own egress-proxy test rig live (it claimed 12
bytes and sent 10). -
h3: a QUIC connection that closes or drains mid-body is an error,
same truncated-success class. The route drops and h1/h2 answer. -
Cookies: a hostile
Set-Cookiewith a multibyte month token in
Expires=panicked the date parser, and with panic=abort in
release that is a one-request remote kill of the daemon. Date
tokens now parse by bytes. Cookie path matching uses the URI path
only (a path-scoped cookie used to stop attaching on query URLs,
against RFC 6265 and every browser). The jar enforces the RFC 6265
section 6.1 bounds (4096-byte cookies, 100 per domain, 3000 total,
4 KiB / 50-pair Cookie header), so a Set-Cookie flood can neither
grow the jar for process lifetime nor emit megabyte headers. -
Ghost session vault: a live daemon's state save no longer erases
fresh harvests or resurrects logged-out sessions. Vault writers
(the logout clear, the session store, the tier-1 sync) stamp a
vault epoch, and every save adopts whichever side wrote last. -
Crawl resume-only (empty url + resume token) consumed the token
twice, always failed with "resume token expired or unknown", and
destroyed the saved state in the process. One take, and the
resume-only flow works. -
Search hot paths no longer initialize the reranker: the first
rerank::active()on the search path blocked a tokio worker on
the whole init chain, up to a 120-second model download. Report
stamps now read a non-initializing check; ranking still
initializes inside its own spawn_blocking. -
h2: a bodyless response whose header block arrives fragmented
(END_STREAM on HEADERS, END_HEADERS on CONTINUATION) no longer
hangs to the 30s timeout; a missing or unparseable:statusis a
transport error instead of a success with status 0; an
unfragmented header frame honors the same 256 KiB block cap as
continuations; response header names are lowercased like h1 so a
nonconforming peer's mixed-casecontent-encodingcannot skip
decompression and itsalt-svccannot skip h3 discovery. -
TLS: brotli certificate decompression is bounded by a take() cap;
a hostile compress_certificate stream used to decompress to its
full (potentially gigabyte) end before the declared-length check
fired. -
Wall detection: bare prose mentions of PerimeterX, Imperva,
Incapsula, Sucuri and Wordfence on healthy 200 pages no longer
score Challenge (each false positive burned a warm retry, route
memory and a paid bypass call). The challenge-specific markers and
error-status co-signals still fire, pinned by tests. -
Revalidation cache:
Cache-Control: no-cacheis honored (stored,
never served fresh); entries are keyed by cookie lane, so a
jar-less search lane can never be served a logged-in fetch's body
or the reverse; a 304 whose entry was evicted mid-flight fails
honestly instead of scoring an empty body as Blocked. -
Crawl: a redirect out of the seed's host, scope, or robots rules
is skipped instead of landing in results, dataset and history
under its final URL. Frontier normalization re-encodes query
strings (distinct URLs with encoded&/=collided in the
seen-set and one of them silently never fetched). A hostile
<priority>NaN</priority>can no longer poison a resume token.
Too-deep items are skipped with a reason instead of aborting the
whole crawl and discarding the frontier. A host's declared
Crawl-delay is honored in full above the 7s self-inferred cap (a
host declaring Crawl-delay: 30 actually sees 30s pacing), stored
per host so concurrent crawls stop cross-polluting each other's
pacing. The governor prunes idle per-(host, lane) clocks instead
of growing them forever. -
MCP supervisor: a failed replay write followed by new client data
no longer drops the held bytes; the held request folds into the
new replay window. -
MCP tools: the fetch batch honors cancellation (a cancelled
12-URL batch no longer runs every escalation to completion);
web_screenshot honors deadline and cancellation with a 60s
ceiling; an all-failed fetch batch classifies permanent vs
transient like the search batch instead of always claiming
"safe to retry"; a hostile multibyte wayback timestamp no longer
panics a byte slice; oversized stdin request lines are bounded
and answered with a parse error instead of growing the reader
without bound. -
Search: SERP bodies cap at 3 MiB before the DOM parse (one broken
proxy answering 200 with tens of MB stalled the whole fan-out
past its deadline). BYOK results carry single-flight, so two
concurrent identical queries bill the metered provider once, and
the byok cache stores the provider's full top-12 (a first search
at max=2 no longer serves later max=10 calls a 2-row slice as
cached). Provider error bodies cap at 600 chars.+survives
cache-key normalization, so "rust vs c++ performance" and "rust
vs c performance" stop sharing one cache entry. The search cache
serializes to disk outside its lock. The ddg_html retry lane
reads its learned trust. Short API keys are never printed whole
bykeys list. -
Adapters: the JSON fast path honors focus/toc/must_contain/section
(must_contain on an adapter-shaped URL used to hand the agent the
full document against its own contract). PyPI normalization
follows PEP 503 separator runs. The plugin loader opens the file,
stats the handle and bounds the read: a swapped FIFO could hang
the first rewrite and a swapped file bypass the size cap. -
h3 lane: DNS resolution runs off the reactor with the same 10s
bound as the h1/h2 path; the platform trust store parses once per
process instead of per request; the profile's accept-encoding
rides the h3 request (bodies arrive compressed and the wire
matches Chrome); a server-declared alt-svc ma= is capped at 30
days; TLS session warm detection uses the same key the session
store writes, so TFO actually arms on non-default ports and
proxied lanes. -
Hygiene: handles.json is written owner-only (interned link URLs
can carry query-string credentials); finished shadow-burst
handles are reaped in daemons; timed-out CDP calls release their
pending slot (a wedged tab used to leak one sender per call); a
Page.navigate failure surfaces its real cause instead of a
generic 20s timeout; egress dead-proxy and auth-fail reports use
poison-recovery locks; config file-layer errors stop labeling
themselves "invalid env value"; a non-UTF-8 modern env value
warns instead of vanishing;DONSETCH_CONFIG=""is treated as
unset;donsetch helpno longer routes the removed answer/memory
commands; the search help lists the real intent verticals. -
HTTP bearer configuration now fails closed: modern TOML/env tokens reject
whitespace and non-visible bytes without echoing the secret, while legacy
text tokens retain their exact historical value instead of being trimmed
into disabled authentication. CORS/auth validation also runs before daemon
work. -
donsetch config show --markdownnow emits one complete Markdown table per
config section, so section labels no longer turn the following knob rows
into plain paragraphs. -
Modern
DONSETCH_<SECTION>__<KEY>variables now fail loudly when a
recognized value is not UTF-8 or when distinct names normalize to the same
config key. Diagnostics identify the variable names without exposing their
values, and collision handling no longer depends on environment iteration
order. -
Typed config validation now rejects an out-of-policy TOML value with
file attribution even when a valid higher-precedence env value would
otherwise hide it; legacy out-of-range values remain warning-only. -
Browser path overrides now preserve source presence across the typed config:
legacy empty values keep their historical override semantics, while modern
empty values reset to discovery or ambient defaults. Explicit Chromium,
CloakBrowser and Playwright paths remain literal. -
Legacy route-memory and bypass-cache controls compose in their original
order under the typed config: the route-memory kill switch beats read-only,
while a valid legacy bypass TTL applied afterDONSETCH_BYPASS_CACHE=0
re-enables the cache (and TTL zero disables it). TOML and modern env
overrides retain their higher precedence. -
The supervisor's replay now survives a crash loop: the bytes
replayed into a replacement were cleared from the unacked
history, so a second silent death dropped them (reported by
mnaza in dondai44423#202, discriminating two-death test included). The
live unacked history is also bounded to the same 1 MiB replay
window on every append (keep the tail), not only at death time. -
The browser probe timeout now kills the whole process group, not
just the parent: a wedged browser whose descendant held the stdout
pipe used to hangdonsetch doctorforever. The probe now fails
at the timeout, bounded, on every platform. -
The MCP supervisor no longer loses a request buffered into a
child that dies before consuming it. The write succeeds while
the child is alive, so no EPIPE ever fires, and the death only
surfaces on the next idle poll: the supervisor now replays the
child's whole unacked history (bounded to 1 MiB, duplicated
delivery preferred over a lost request). Caught by the macOS CI
run timing the crash between a successful write and the idle
poll. -
Crawl resume tokens survive concurrent crawlers. The store was
one shared JSON map saved with load-modify-save, so two
processes issuing tokens at the same time (the daemon plus a
CLI run, parallel test processes) wrote stale copies over each
other and fresh tokens read back as expired or unknown. Tokens
are now one immutable file each under the cache dir; the legacy
single-file store migrates on first touch, retires only after
every entry lands, and the consume-on-resume semantics are
unchanged. Caught by the Windows CI run while it beat on the
shared store in parallel. -
donsetch doctor --deepno longer reports a valid Bright Data
dynamic-IP unlocker (Web Access API zones and friends) as broken:
the free zone probe costs nothing, and where the zone has no
static route pool Bright Data answers 403 "Static routes not
found". That answer no longer reads as a failed check: the
probe skips with an honest, zero-credit note instead (reported
by tripflex on dondai44423#200). A 401 always stays a failure. -
Resurrection no longer claims "never archived" on shaky ground:
the availability API is lossy and scheme-strict (a capture
recorded underhttp://is invisible to anhttps://query), so
an empty answer now falls through to the complete CDX index
(scheme-canonical,filter=statuscode:200, last 5 captures)
beforearchive=onlyreports anything, an unreachable archive
answerstransientwith its own message instead of a false
permanent, and a found-but-unusable snapshot names itself and
its stage (structuredContent.archive_stage) instead of
collapsing into the live error. -
site:queries no longer leak off-domain results through BYOK
providers (issue dondai44423#190): both BYOK exits (provider-first and the
local-first fallback) sweep results through the same post-merge
domain filter the local engine uses; goto/redirect proxies drop
(fail closed), and the warm body prewarm runs on the rows that
survive the filter. -
donsetch login --logout DOMAINnow also wipes the rendered-DOM
cache of the logged-out domain (Mart-Bogdan, PR dondai44423#188): a page
fetched behind the session was a fourth persisted copy of the
session, served back with no network hop for up to five minutes
after logout. Unrelated domains' renders stay. -
Repeat BYOK searches now ride the same TTL'd disk cache as keyless
results instead of re-billing the provider (issue dondai44423#195): same query- intent replays from cache under a separate byok namespace, capped
at 500 entries like the local path (mnaza, dondai44423#197).
- intent replays from cache under a separate byok namespace, capped
-
The web-memory index persist stages to a PID+sequence-unique
file per write (PR dondai44423#191): overlapping persists (a crawl fires
one per 256-row chunk and one on completion) can no longer tear
index.jsonthrough a shared tmp inode and parse-fail the next
recall to an empty index. -
Subresource shadow-fetching no longer aborts the daemon on a page
containingİ,KorΩ. The scanner searched ato_lowercase()
copy of the document for tag offsets and then sliced the original
string at them, butto_lowercaseis not byte-length preserving, so
one such character shifted every later offset: assets silently
dropped where the shift landed on ASCII, a mid-codepoint slice panic
where it did not : and the release profile'spanic = "abort"turns
that into a daemon kill. Folding isto_ascii_lowercasenow, which
is byte-length and char-boundary preserving, and is also what the
HTML standard specifies for tag and attribute names.attr()had
the same latent pattern and is fixed with it. -
MCP text-only fold now covers OpenCode v1 (tested on 1.18.3):
unlike Claude Code / VS Code, OpenCode renders thecontentarray
and dropsstructuredContententirely, so agents previously lost
every compact state field (URL handles,next_offset, verdicts,
error codes). Handshake detection now matchesopencodeand folds
the state into the leading[meta]text block, same as the other
text-only clients. -
A corrupt local embedding model no longer wedges every subsequent
fetch.ensure_filerecursed into itself with identical arguments
when the file on disk failed its SHA/size pin, never removing it, so
the same bad bytes were read forever : a stack overflow, or an
infinite loop if the recursion was optimized into a tail call. The
bad file is removed and the existing atomic download path takes
over; a concurrent remover is tolerated with a receipt, any other
removal failure is honest and immediate. -
Default-feature builds compile again (Mart-Bogdan, PR dondai44423#174): the
web-memory status receipt tested the rerank feature with a runtime
cfg!so no-rerank builds failed the compile on three symbols
behind the feature gate. -
donsetch login --logoutnow wipes the tier-1 echo of the vault
from ghost-state.json, not only the registries the sessions
replays through on the next start (issue dondai44423#173). -
routes.jsonwas rewritten on every alt-svc sighting, could grow
without bound, and had no switch: re-vouches with nothing
materially new (under a 60 s grace) are skipped before the disk
write, expired rows never survive a persist, the row count caps at
512, andDONSETCH_NO_ALT_SVCshuts the bookkeeping off (issue
dondai44423#175). -
Web memory re-embedded and rewrote its whole index once per row,
putting up to one 20MB+ write on the answer path per hit: batch
ingest embeds in one pass and persists once, the crawl path chunks
at 256 rows, and ingestion runs on the blocking pool so a recall
never holds a response past its deadline (issue dondai44423#178). -
CI runs now concurrency-cancel per pull request only, never on
master (Mart-Bogdan, PR dondai44423#181). -
The alt-svc kill-switch test no longer excludes Windows
(Mart-Bogdan, PR dondai44423#189): the env-var mutations in it are not
Windows-specific, so the guard was dead weight. -
Xvfb reuse gate now demands a bounded real-protocol answer
(xdpyinfo within 2s) before handing a display to the pool, so a
SIGKILLed Xvfb's tombstone socket can no longer wedge every
tier-2 escalation behind an honest "devtools ws timeout". -
Ghost pool spill fix (mnaza): a same-persona pool previously
funneled every distinct host into slot 0, since "any warm
same-persona slot" outranked free slots and the daemon always runs
one persona. Slot claims (persona key + host) are now stamped and
visible to concurrent selectors at pick time under the meta lock,
before the seconds-long browser launch, so a second in-flight host
claims a free slot and a same-host job joins the in-flight claim
and warm-serves it. An exhausted pool reuses our coldest own
browser before evicting a stranger's. Their contribution lives as
its own rebased commit on master (af13034). -
Search pacing uses cancellation-safe per-engine/egress admission;
waiting is included in attempt deadlines and cancelled waiters
leave no future-slot debt. Google HTTP health is isolated from
legacy browser health; Google follows common failure and quarantine rules. -
Search retries retain completed peers when another retry times out
and report retry timeouts explicitly, with the attempted Google
profile when available. At most one retry per engine per search. Ordinary
retries, including Google, keep a three-second budget including pacing. -
dondai44423#164 audit wave (S1-S6 in the search/fetch stack):
S1: version matching is boundary-aware; "5.2" no longer matches
"15.2" or "5.20" but still matches "5.2.1" and "v5.2".
S2: empty vertical results report no-results instead of success;
engine OK counts and retry/cache gates were inflated.
S3: plugin-hit truncation before URL dedup dropped, so oversize
plugin output can no longer shrink the final unique count.
S4: cache entries keep engine reports; cache hits return real
engine evidence (old 4-tuple caches still load).
S5: single-URL fetch withbudget_tokensruns under
run_with_budget:deadline_msand MCP cancellation apply, and
the budget bounds the page like batch mode.
S6: BYOK plugin error envelopes cap at 600 chars, matching the
stderr trim. -
Storage guard: bounded target-dir growth and pinned the cargo
profile on every nextest run. -
Ghost-state counters now merge against the state on disk at every
save, so a late save with a stale in-memory snapshot can no longer
rewind lifetime counters (caught live: the pool warm-serve receipt).
Full Changelog: https://github.com/axwfae/donsetch_noavx/commits/v4.0.0_sync