Changed
- CLI arms that open the Tantivy index no longer hoist a
stdout/stderrlock. A hoistedStdoutLock/StderrLockis process-wide, so a command holding one across an index open could deadlock against Tantivy's own logging threads — the root cause behind thedoctor --repairhang (AILAB-575).recall,score, andsetupnow write through unlockedstd::io::stdout()/stderr()handles, which lock and release perwriteln!. The eight arms that still hoist —archive,init,migrate,reset workspace,status,uninstall,update,version— each carry an inline// lock-ok (AILAB-583):rationale naming why they never open an index, andAGENTS.mdnow requires that rationale so a new or changed arm cannot silently reintroduce the hang. No user-visible output change. (AILAB-583 —crates/dreamd-cli/src/cli.rs,AGENTS.md) - The State-Drift benchmark is now the WasTrue benchmark. The Oct-2026 third-party eval scaffold was renamed throughout:
scripts/benchmark/state_drift_bench.py→wastrue_bench.py, along with its--demo/--verify-determinism/--bakeoffcommand references, the benchmark README, and the root README's roadmap row and methodology section. Repository tooling and documentation only — nothing in the shippeddreamdbinary or thedreamd-mcppackage changes. (AILAB-593 —scripts/benchmark/,README.md)
Fixed
uninstall/updateno longer stop other homes' (or other users') dreamd servers. Both commands stopped local servers by shelling out to the manual README recipe's barepkill -f 'dreamd mcp'/pkill -f 'dreamd watch', which is machine-global by construction: it SIGTERMs every process on the box whose command line matches, whatever$HOMEit serves. The 2026-08-03 clean-box audit caught it (AILAB-554 F1) — a sandboxedHOME=/tmp/… dreamd updatekilled the developer's real Cursordreamd mcp. The stop pass now enumerates the process table itself, keeps only entries that are thedreamdbinary with a matching command line, and attributes each one to this invocation's scope before signalling: its executable must live under this$HOME's~/.cache/dreamd-mcp, or its ownHOME=must resolve to this$HOME. Everything else is left running, named on stderr, and reported to the caller so the restart contract cannot claim "no processes were running" about a daemon that is still up. Attribution data that cannot be read (another user's/proc/<pid>/environis EACCES) fails closed — failing to stop a daemon costs one command, killing someone else's does not. An emptyHOMEis now treated as no home at all, since$HOME/.cache/dreamd-mcpwould otherwise collapse to a cwd-relative path that attributes foreign processes (and, inuninstall, a cwd-relative./.npm/_npxthe scoped cache clear would delete). Covered by unit tests over a synthetic/proctree, a cross-$HOMEintegration suite that spares and then stops a really-runningdreamd watch, and a live step in the install-funnel suite. Thepackages/dreamd-mcpmanual recipe no longer teaches the unscoped kill. (AILAB-584 —crates/dreamd-cli/src/commands/lifecycle_cleanup.rs,cli.rs,uninstall.rs,update.rs,packages/dreamd-mcp/README.md,scripts/alpha/install-funnel-suite.sh)uninstall/updateno longer unlink a live daemon's socket. Both commands run a best-effortpkillstop pass whose failure is only a stderr warning, so on a box withoutpkill— or where the signal is denied — the daemon was still serving when its socket file was removed. That orphaned it: the daemon kept working while every client resolved a path that no longer existed, so MCP silently fell back to the in-process Phase 1 backend and cross-harness recall stopped with no error.remove_socketnow connect-probes first and leaves a live socket in place with an actionable warning, matching the ruledreamd archiveanddreamd doctor --repairalready apply. Becausepkillreturns when the signal is delivered rather than when the target exits — anddreamd watchdrains its coordinator and Tantivy indexer before unlinking its own socket — the probe waits out a 5s grace window first, so a daemon that is merely mid-shutdown is not mistaken for one that refused to stop. (crates/dreamd-cli/src/commands/lifecycle_cleanup.rs,uninstall.rs,update.rs)- A healthy index is no longer wiped by a false schema-mismatch match.
is_schema_incompatiblegates aremove_dir_allof the index cache but matched a bare"schema"substring anywhere in the error text.tantivy_io_to_indexembeds the directory path in its message, so any store living under a path containing "schema" (e.g.~/dev/schema-tools/) tripped the branch and silently rebuilt a healthy index. It now matches tantivy's exactSchemaErrorrendering ("Schema error: '…'"). The companion|| msg.contains("incompatible")alternative was removed:TantivyError::IncompatibleIndexrenders throughIncompatibility's hand-writtenDebugas"Library version: N, index version: M. …", so it never matched that variant and only widened the false-positive surface — an index-format mismatch stays a loud startup error rather than a silent wipe. (crates/dreamd-core/src/server/tantivy_handle.rs)
SHA-256 checksums
7ed46898b762a1c660b56dd64d54252d7daac5307404ef6750bf7a91d6d618e3 dist/darwin-aarch64.tar.gz/darwin-aarch64.tar.gz
8aed3bc579d36632d2fcc27dfe18bcfe0bf3f871ccf9e600032b8d72a9827826 dist/darwin-x86_64.tar.gz/darwin-x86_64.tar.gz
ce0b4a5992fac5569cdb220cf0b11c3740cc4af48606b00fa726ace747941ec0 dist/linux-x86_64-musl.tar.gz/linux-x86_64-musl.tar.gz
7ebf5a8cf752fcf96dd6e88c4db31069d9a7f2176b0e56240b16dc3c42b46566 dist/linux-x86_64.tar.gz/linux-x86_64.tar.gz