Commit 36eafa4
feat(core,server): truth-kernel hardening Waves 0-4 -- live verification, evidence semantics, assistant retrieval, coverage/noise honesty
Full delivery of docs/plans/2026-08-20-truth-kernel-hardening-execution-plan.md,
a verification + execution plan against a large incoming audit claiming CALM's
read/edit path could silently act on stale index coordinates. All 12 audit
findings were independently confirmed against live code (one via direct SQLite
query, five via live tool-call reproduction) before any fix landed.
Wave 0 (stop the cheap, high-confidence leaks): path containment for
source_range (reuses resolve_repo_path's PATH_ESCAPES_PROJECT_ROOT guard);
fixed suggested_next args that don't validate against their own target tool's
schema, plus a new invariant test that would have caught both; corrected the
kind="text" tool description to stop claiming body coverage it didn't have
yet; fixed edit_context's read_only_hint/idempotent_hint annotations (it mints
a new ReviewAuthority/ChangeIntent on every call -- a real write, not a
cacheable read); defensive clamps in source()/understand()/symbols_batch()
against a stale line_start past current EOF panicking.
Wave 1 (Live Truth Kernel, the core architectural fix): live-verification
folded directly into resolve_symbol itself rather than a separate opt-in
function agents could forget to call. New SymbolResolution::ReadFailed
variant; hash-compares the live file against the indexed hash on every
resolution, falling back to a fresh reparse matched by (name, kind,
class_context) -- not bare name alone -- only on a mismatch. Threaded through
all 9 existing call sites plus understand()/symbols_batch() (previously
bypassed resolve_symbol_candidates entirely via independently-duplicated
stale-slice logic). 5 new adversarial tests: stale/moved/duplicate-class/
genuinely-ambiguous/deleted-since-indexed.
Wave 2 (Evidence/confidence semantics): EvidenceSnapshot::compute gained a
mtime-only live-disk spot-check that downgrades Current to Degraded on any
drift (fail-closed on a missing file or NULL mtime); the reconciliation fence
in watch_supervisor now persists plain Current + a Current->Reconciled
promotion instead of unconditional compute_after_reconciliation, so drift
caught during the reconciliation's own reindex window blocks the Reconciled
claim; canonical EdgeConfidence::is_verified/is_probable/is_lexical_lead
predicates replace ad-hoc rank() comparisons at the two call sites judged
correctness fixes (path()'s certain flag, the bridge-gate), with the coreness/
hub-detection bucket question deliberately deferred pending a false-hub-rate
measurement pass (tightening it would loosen the edit gate).
Wave 3 (Assistant-grade retrieval): search's default kind flipped
symbol->hybrid (confirmed zero-regression via search_hybrid's existing
graceful degrade to today's symbol-search output when no embedder is
configured); a new fts_chunks FTS5 table gives kind="text" real function-body
coverage, merged with the existing fts_exact hits via rrf_merge_n;
understand() gained a top-1/top-2 margin check surfacing resolution_
confidence + alternatives instead of silently committing to a near-tied top
hit; qualified_name threaded through resolve_symbol as an additional
narrowing filter that still flows through the same live-verification step
(the corrected design -- short-circuiting straight to a DB row by
qualified_name would have reintroduced the exact staleness risk Wave 1
closed), restoring SearchResultItem.qualified_name (gated on kind.is_some()
so synthetic file/gap-chunk identities are never surfaced as resolvable).
Wave 4 (Coverage/noise honesty): fixed a genuine correctness bug found during
this wave's own research, not in the original audit -- reindex_changed_
cancellable (the everyday incremental-reindex path) was deleting a file's
indexed symbols/call_sites whenever it transiently failed to read (permission
hiccup, briefly oversized, non-UTF-8 mid-write), indistinguishable from a
genuinely deleted file even though the file still existed and would read fine
next pass; landed first as its own isolated step. read_source_capped's return
type changed Option<String> -> Result<String, String> so its 3 callers can
record *why* a file was skipped via a new file_index.skip_reason column,
surfaced through a new indexing_status.skipped_files field (capped list +
true count) rather than leaving it write-only in the DB. search(kind="grep",
include_tests=false) was a complete silent no-op (is_test hardcoded false for
every grep result) -- enclosing_symbol now selects the real, already-computed
symbols.is_test column instead.
Verified: cargo test --workspace green across every wave's own closing pass
(final state: calm-server 421/421, calm-core 1266/1266, plus schema-migration/
watcher-integration/doctest suites, 0 failures workspace-wide). cargo fmt
--check clean throughout (via format_files, never raw rustfmt). cargo clippy
--workspace --all-targets -- -D warnings clean. 12 toolsnaps regenerated
across the session for every tool whose output schema changed. diff_impact
confirms the full Wave 0-4 change surface matches expectations at each stage.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>1 parent 0d8d1f2 commit 36eafa4
31 files changed
Lines changed: 3243 additions & 198 deletions
File tree
- crates
- calm-core/src
- authority
- db
- indexer
- pipeline
- calm-server/src
- __toolsnaps__
- tools
- docs/plans
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
146 | 146 | | |
147 | 147 | | |
148 | 148 | | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
149 | 161 | | |
150 | 162 | | |
151 | 163 | | |
152 | | - | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
153 | 169 | | |
154 | 170 | | |
155 | 171 | | |
| |||
169 | 185 | | |
170 | 186 | | |
171 | 187 | | |
172 | | - | |
173 | | - | |
174 | | - | |
175 | | - | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
176 | 197 | | |
177 | 198 | | |
178 | 199 | | |
| |||
326 | 347 | | |
327 | 348 | | |
328 | 349 | | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
329 | 398 | | |
330 | 399 | | |
331 | 400 | | |
| |||
823 | 892 | | |
824 | 893 | | |
825 | 894 | | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
| 911 | + | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
| 922 | + | |
| 923 | + | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
| 930 | + | |
| 931 | + | |
| 932 | + | |
| 933 | + | |
| 934 | + | |
| 935 | + | |
| 936 | + | |
| 937 | + | |
| 938 | + | |
| 939 | + | |
| 940 | + | |
| 941 | + | |
| 942 | + | |
| 943 | + | |
| 944 | + | |
| 945 | + | |
| 946 | + | |
| 947 | + | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
| 953 | + | |
| 954 | + | |
| 955 | + | |
| 956 | + | |
| 957 | + | |
| 958 | + | |
| 959 | + | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
826 | 981 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
170 | 170 | | |
171 | 171 | | |
172 | 172 | | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
173 | 180 | | |
174 | 181 | | |
175 | 182 | | |
| |||
221 | 228 | | |
222 | 229 | | |
223 | 230 | | |
224 | | - | |
| 231 | + | |
| 232 | + | |
225 | 233 | | |
226 | 234 | | |
227 | 235 | | |
| |||
966 | 974 | | |
967 | 975 | | |
968 | 976 | | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
969 | 1007 | | |
970 | 1008 | | |
971 | 1009 | | |
| |||
1111 | 1149 | | |
1112 | 1150 | | |
1113 | 1151 | | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
| 1155 | + | |
| 1156 | + | |
| 1157 | + | |
1114 | 1158 | | |
1115 | 1159 | | |
1116 | 1160 | | |
| |||
1121 | 1165 | | |
1122 | 1166 | | |
1123 | 1167 | | |
| 1168 | + | |
1124 | 1169 | | |
1125 | 1170 | | |
1126 | 1171 | | |
| |||
1296 | 1341 | | |
1297 | 1342 | | |
1298 | 1343 | | |
| 1344 | + | |
1299 | 1345 | | |
1300 | 1346 | | |
1301 | 1347 | | |
| |||
1569 | 1615 | | |
1570 | 1616 | | |
1571 | 1617 | | |
| 1618 | + | |
| 1619 | + | |
| 1620 | + | |
| 1621 | + | |
| 1622 | + | |
| 1623 | + | |
| 1624 | + | |
| 1625 | + | |
| 1626 | + | |
| 1627 | + | |
| 1628 | + | |
| 1629 | + | |
| 1630 | + | |
| 1631 | + | |
| 1632 | + | |
| 1633 | + | |
| 1634 | + | |
| 1635 | + | |
| 1636 | + | |
| 1637 | + | |
| 1638 | + | |
| 1639 | + | |
| 1640 | + | |
| 1641 | + | |
| 1642 | + | |
| 1643 | + | |
| 1644 | + | |
1572 | 1645 | | |
1573 | 1646 | | |
1574 | 1647 | | |
| |||
0 commit comments