Rust rewrite comparison plan

August 18, 2026 ยท View on GitHub

The Go executable is the behavioral oracle until the Rust implementation passes every required parity gate. Performance wins do not waive correctness, integrity, or security requirements.

Required gates

AreaTest levelAcceptance criterionCurrent automation
Trace/frontmatter and IDsUnit + propertyGo-compatible parse/write, validation, hashing, and collision behaviorRust unit tests; expand with proptest corpus
Database and migrationsUnit + integrationExact Go migration chain through schema 19; SQLite integrity remains okRust migration test and differential suite
Backup and restoreDifferential + negative integrationGo and Rust archives restore across runtimes without identity duplication, destination loss, metadata leakage, or archive traversalrestore_parity.py covers both archive directions, trace preservation, duplicate-ID refusal, forced replacement, transaction cleanup, traversal, and links; Rust unit tests also cover names, paths, roots, duplicates, rollback, metadata, long paths, self-inclusion, the exact legacy Obsidian-facing .trash -> trash/traces/ alias emitted by Go backup, and rejection of every other link; eight subprocess scenarios cover journaled resume/rollback, tamper refusal, redaction, permissions, contention, and killed-owner lock release
CRUD lifecycleDifferentialEither build can create, read, search, append, archive, trash, recover, sync, and verify the same cortexcompare.sh
Events and signingUnit + differentialCanonical signatures verify across languages; mutation clocks remain monotonicRust signing tests, Go Rust-wire fixture, mixed signed federation
MCP stdioContractExact tool-name set, compatible input schemas, result semantics, and errorsmcp_contract.py covers names, schemas, structured results, lifecycle, observability, candidates/distillation/lineage, identity/status/sync, non-mutating announcements, and invalid/missing-resource behavior
MCP HTTPIntegrationBoth transports initialize and serve calls; auth, TLS, host validation, shutdown, and federation-mode restrictions matchhttp_smoke.sh covers both builds plus Rust repeated dual-stack static listeners and dynamic local-address reconciliation; unit and deployment-canary checks cover a DNS Host-header allowlist distinct from listener binding while retaining rejection of unknown names; federation_tls.py covers authenticated HTTPS, custom CA, and plaintext refusal; tls_certificate_lifecycle.py covers validity gates, CLI precedence, monitor bands, and redaction; mcp_contract.py covers every publish-mode mutation guard, local stdio exemption, and subscribe-mode publication guards
WatcherIntegrationExternal create/edit/rename is debounced, onboarded, indexed once, and healed after atomic savewatcher_parity.py covers edit bytes, metadata reindex, burst debounce, create, archive/unarchive, atomic save, heal, onboarding, delete/purge, and source locks
FederationMulti-processMultiple nodes converge under normal, duplicate, reordered, concurrent, signed, paused, and unavailable-peer casesfederation_network.py covers signed bidirectional batching/lifecycle; federation_ring.py covers three nodes, background sync, pause/recovery, concurrency, shutdown, and key-rotation recovery; federation_dynamic.py covers live worker add/remove/re-add and cursor preservation; federation_tls.py covers authenticated mixed-runtime TLS
Memory tiersUnit + differentialUsage counters, scoring, promotion, graduation, votes, purge, and health output matchPer-peer usage publication/merge, short-to-mid scoring/promotion, strict mid-to-long graduation, search activity, promotion latency, election/failure totals, and one-source leak reporting automated
Semantic searchContract + integrationMock embedding endpoint, codec, stale detection, backfill, cosine ranking, and hybrid RRF matchsemantic_search.py covers request/auth/order/text limits, exact BLOBs, freshness, bounded/idempotent backfill, ranking, archive/source rules, corrupt vectors, MCP degradation, and automatic maintenance
ConsolidationDeterministic + bounded real-model integrationFake LLM covers election, gating, clustering, success/failure events, and idempotency; real model preserves planted synthetic facts and rejects unrelated bucketsRank/election/watchdog/cadence, heuristic promotion, graduation, all three model profiles, exact cross-runtime prompt/request contracts, ID-free model input, strict output shape, CLI overrides/dry-run/JSON, malformed/offline fallback, restart idempotency, signed bidirectional replay, seven-run baseline comparison, four-run diagnostic comparison, two independent six-run untagged small-profile comparisons, and three-run large/frontier real-model qualification automated
PluginsFile integrationEmbedded payload hashes, install/check/force rules, target resolution, and drift reporting matchplugin_lifecycle.py covers all six payloads, independent CLI dispatch, target guards, dry-run non-mutation, idempotency, drift hashes/refusal, forced atomic file/symlink replacement, unmanaged files, and temp cleanup
TUIState-machine + styled-buffer + live PTYNavigation, filters, tier actions, themes, resize, editor handoff, exit, terminal recovery, and Go visual hierarchy matchEight Rust TUI tests cover navigation/focus/scroll, search/tier/help transitions, lifecycle and vote mutations, sticky live refresh/highlights, right-aligned header state, Go-matched divider/title columns, explicit title ellipsis, dark/light tier and chip cell colors, wrapped tags, full-width scroll indicators, and pinned metadata; tui_pty.py covers the real backend's editor leave/show/re-enter sequence, 24-to-32-row redraw, keyboard exit, canonical/echo mode, alternate screen, and cursor restoration. The resize/quit sequence passed 30 consecutive runs with Crossterm's Unix polling backend; an identical-size capture exposed and drove a one-cell pane correction, and the final release-binary recapture visually matches Go in the original terminal. Multi-emulator human review remains
Fault toleranceFault injectionInterrupted writes, malformed Markdown, corrupt DB, unavailable endpoints, and lock contention fail safelybackground_lock_contention.py covers MCP-only losers, killed-owner release, and replacement acquisition; io_failure_safety.py covers pre-mutation trace, lifecycle, and manifest I/O refusal with unchanged bytes/DB/events; Rust unit tests inject returned SQLite aborts after local, replay, destructive, watcher reconstruction, and restore mutations; five subprocess scenarios SIGKILL create/replace/move/delete/reconstruction after the filesystem mutation; nine restore subprocess scenarios exercise hash-bound resume/rollback, config-replace death, malformed/tampered journals, contention, and killed-owner lock release; an independent config subprocess proves byte-identical old YAML and clean retry after a killed writer; storage_fault_macos.py forcibly detaches disposable APFS images and verifies restore rollback/resume, config rename, strong journal cleanup, SQLite integrity, and acknowledged standard state across remount; the differential fixture proves Go refuses pending Rust recovery until Rust repairs it; five safety tests cover corrupt DB bytes, malformed records, path traversal, non-mutating status, and CLI redaction; corrupt-DB salvage, older-Go takeover, automatic startup restore reconciliation, and device-cache-loss qualification remain pending
SecurityNegative integrationPath traversal, source-lock bypass, forged signatures, bearer auth, TLS expiry, and secret redaction matchSigning/source-lock, archive path/link/multi-root/duplicate rejection, bearer rejection, private-CA rejection, plaintext-auth refusal, expired/future validity refusal, explicit bypass, monitor transitions, and secret/certificate-content redaction automated

Performance protocol

Use stripped release binaries on the same host, with equivalent fresh cortexes. Record at least five runs and report median plus spread rather than selecting the fastest run.

  • Process-level CLI: ingest, lexical search, filtered list, sync, verify.
  • Long-lived MCP: warm-up, requests/second, median, p95, and maximum latency.
  • Resource use: binary size, idle RSS, peak RSS during ingest/search, and CPU.
  • Bounded federation soak: equal three-node mutation schedules, restart recovery, exact event counts, graceful shutdown, and sampled aggregate RSS/CPU.
  • Scale: 100, 1,000, 10,000, and 100,000 traces where practical.
  • Concurrency: parallel readers, reader/writer mix, watcher activity, and federation replay under the race detector or equivalent stress tooling.

Any benchmark run is invalid if its corresponding correctness gate fails.

The final scale gate has five alternating runs at 10,000 traces and five runs on a nominal 100,000-trace, independently cloned, byte-identical verified corpus, all with four MCP clients. Each scenario used fresh server processes, both builds passed verify, and mixed writes matched exact expected SQLite counts. With NOEMA_DURABILITY=standard, Rust leads every measured 10,000- and 100,000-scale throughput median, including mixed writes. The default strong profile remains about 13x behind Go on the 10,000-scale mixed workload because it provides a stronger recovery protocol. Standard is therefore the selected default, while NOEMA_DURABILITY=strong is the explicit opt-in. The performance gate is closed; the remaining profile work is power-loss qualification rather than an unexplained implementation gap.

Current decision gaps

The Rust implementation is feature-complete against the public Go surface covered by this repository and is now a replacement candidate. It is not yet a release replacement: device-cache-loss durability, corrupt-database salvage policy, takeover by older Go binaries, multi-emulator human TUI validation, representative multi-model/multi-reviewer quality evaluation, and staged packaging / rollback policy remain. Standard is the selected release default to preserve Go's performance and crash posture; strong remains available for users who explicitly value the pending-mutation/fsync recovery protocol. Standard mode still needs an explicit physical-power-loss promise because it intentionally omits the pending-mutation journal and per-file fsyncs. Automatic restore reconciliation is deliberately not a goal because ambiguous or tampered state requires an explicit operator choice.