Commit e00d503
committed
fix(repair): anchor the FTS5 classifier, attribute integrity verdicts (#2240)
maybe_autoheal_fts5_index rebuilds a corrupt FTS5 index in place when
PRAGMA quick_check's errors look like they came from that index alone. On
develop it has six exits, two of them take that decision silently, and no
verdict anywhere says which SQLite produced it -- or whether one was
produced at all.
Anchor both known phrasings to the start of the quick_check row.
sqlite_integrity_errors reports a failed probe as `PRAGMA quick_check
failed: <error>`, and an unanchored match reads such a row as an isolated
FTS5 fault whenever the wrapped text carries one of the phrasings,
authorizing a write on a database whose state was never established. That
is not a cosmetic misread: on develop, handing such a row to
maybe_autoheal_fts5_index takes the mine lock and changes chroma.sqlite3
on disk. Producing a matching wrapped row needs a table named after a
phrasing, which a chroma palace never has, so this is hardening rather
than a reachable fix. Across 3,200 deliberately damaged databases per
build on 3.45.1, 3.47.1 and 3.51.2, 2,975 dirty on each, the anchored
pattern refused no row the old one accepted and accepted none it refused;
FTS5 faults arrived as whole rows, and the `*** in database <db> ***`
header appeared on b-tree rows only.
Explain a declined heal instead of returning silently, on both quiet
exits and in --dry-run, and name the SQLite that decided. The message
reports what the classifier concluded rather than guessing a cause, since
quick_check may have failed to run at all, reported damage outside the
index, or reported an FTS5 fault in an unrecognized wording. The
--dry-run copy is marked as a preview: without the marker it was
byte-for-byte the run it was predicting, which is the one thing a preview
must not be. The shared text no longer opens with a blank line either,
because the post-mine path passes logger.warning as progress, where a
leading newline renders as a bare WARNING header above an empty line.
Carry sqlite3.sqlite_version wherever a quick_check result is stated: the
abort banner, both --dry-run branches, the heal's outcome line, the
post-recovery check, all three shapes of the MCP integrity payload, the
tool-refusal payload, the integrity log line and MineValidationError's
message. A clean result from a build that cannot detect a given FTS5
fault reads exactly like one from a build that can. The exception message
matters because two callers render it rather than the banner: the MCP
mine tool and the daemon's job runner.
Stop the MCP integrity payload reporting a verdict nobody produced. Above
MEMPALACE_STARTUP_INTEGRITY_MAX_MB, 512 MB by default, the startup probe
does not run, yet the payload answered checked: true, ok: true. It now
returns the not-applicable shape #1931 introduced for the same reason,
carrying the skip as its reason. This matters here specifically: the
palace in #2240 is about four times that limit, so on that install no
quick_check runs at all. The reason is recorded before the rest of the
state, so a reader taking the payload without the refresh lock cannot
catch a half-updated skip and read it as clean. That reason also states
sizes precisely enough to show the comparison it reports: rounded to whole
megabytes, a 1.4 MB database against a 1 MB limit read as "is 1 MB, over
the 1 MB limit". /statusz no longer collapses a missing verdict into a
failure either: false there now means a check came back dirty, which also
stops a non-chroma backend from reporting itself unhealthy.
Report the post-mine validator at warning rather than info. Nothing
configures logging on the mempalace mine path, so its info records were
dropped before reaching a handler there; the MCP server, which configures
logging at info on import, was already showing them.
`fts5: checksum mismatch`, which SQLite 3.51.2 emits, stays unmatched on
purpose. It says the index and the content table disagree without naming
the damaged side, and a rebuild reads from content: edited bytes inside
%_content produce it while the index still holds the original token, and
single-byte damage to an index leaf produces it too, in 75 of the 115
flips that registered at all in a 120-trial run. A rebuild then leaves
quick_check clean whichever side was damaged, on all three builds. A
comment and a test record the counterexample so the pattern is not
widened again.
The subject of #2240 -- one SQLite calling a file clean while another
calls it malformed -- is not addressed here, and the issue stays open.
That asymmetry did not reproduce: 3.45.1, 3.47.1 and 3.51.2 all called the
same 2,975 shapes dirty, differing only in wording, and quick_check agreed
with FTS5's own integrity-check 24 times out of 24 on each build.
Reported by @darkrhodes7, whose suggestion to log the SQLite version
alongside integrity verdicts is implemented here.1 parent 3e56979 commit e00d503
8 files changed
Lines changed: 1017 additions & 36 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
8 | 8 | | |
9 | 9 | | |
10 | 10 | | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
11 | 17 | | |
12 | 18 | | |
13 | 19 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
352 | 352 | | |
353 | 353 | | |
354 | 354 | | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
355 | 358 | | |
356 | 359 | | |
357 | 360 | | |
| |||
834 | 837 | | |
835 | 838 | | |
836 | 839 | | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
| 845 | + | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
837 | 865 | | |
838 | 866 | | |
839 | 867 | | |
| |||
852 | 880 | | |
853 | 881 | | |
854 | 882 | | |
855 | | - | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
856 | 897 | | |
857 | 898 | | |
858 | 899 | | |
859 | 900 | | |
| 901 | + | |
860 | 902 | | |
861 | 903 | | |
862 | 904 | | |
| |||
867 | 909 | | |
868 | 910 | | |
869 | 911 | | |
870 | | - | |
871 | | - | |
872 | | - | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
873 | 922 | | |
874 | | - | |
875 | | - | |
| 923 | + | |
| 924 | + | |
876 | 925 | | |
877 | 926 | | |
878 | 927 | | |
879 | | - | |
880 | | - | |
| 928 | + | |
| 929 | + | |
881 | 930 | | |
882 | 931 | | |
| 932 | + | |
| 933 | + | |
| 934 | + | |
883 | 935 | | |
884 | 936 | | |
885 | 937 | | |
| |||
895 | 947 | | |
896 | 948 | | |
897 | 949 | | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
898 | 953 | | |
899 | 954 | | |
900 | 955 | | |
901 | 956 | | |
902 | | - | |
| 957 | + | |
903 | 958 | | |
| 959 | + | |
904 | 960 | | |
905 | 961 | | |
906 | 962 | | |
| |||
928 | 984 | | |
929 | 985 | | |
930 | 986 | | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
931 | 1005 | | |
932 | 1006 | | |
933 | 1007 | | |
| |||
937 | 1011 | | |
938 | 1012 | | |
939 | 1013 | | |
| 1014 | + | |
| 1015 | + | |
| 1016 | + | |
940 | 1017 | | |
941 | 1018 | | |
942 | 1019 | | |
| |||
950 | 1027 | | |
951 | 1028 | | |
952 | 1029 | | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
953 | 1034 | | |
954 | 1035 | | |
955 | 1036 | | |
| |||
995 | 1076 | | |
996 | 1077 | | |
997 | 1078 | | |
| 1079 | + | |
| 1080 | + | |
| 1081 | + | |
998 | 1082 | | |
999 | 1083 | | |
1000 | 1084 | | |
| |||
7089 | 7173 | | |
7090 | 7174 | | |
7091 | 7175 | | |
7092 | | - | |
| 7176 | + | |
| 7177 | + | |
| 7178 | + | |
| 7179 | + | |
| 7180 | + | |
| 7181 | + | |
7093 | 7182 | | |
7094 | 7183 | | |
7095 | 7184 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
9 | 9 | | |
10 | 10 | | |
11 | 11 | | |
| 12 | + | |
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
| |||
1107 | 1108 | | |
1108 | 1109 | | |
1109 | 1110 | | |
1110 | | - | |
| 1111 | + | |
| 1112 | + | |
| 1113 | + | |
| 1114 | + | |
| 1115 | + | |
| 1116 | + | |
| 1117 | + | |
| 1118 | + | |
| 1119 | + | |
| 1120 | + | |
1111 | 1121 | | |
1112 | 1122 | | |
1113 | 1123 | | |
| |||
1144 | 1154 | | |
1145 | 1155 | | |
1146 | 1156 | | |
1147 | | - | |
1148 | | - | |
1149 | | - | |
1150 | | - | |
1151 | | - | |
| 1157 | + | |
| 1158 | + | |
| 1159 | + | |
| 1160 | + | |
| 1161 | + | |
| 1162 | + | |
| 1163 | + | |
| 1164 | + | |
| 1165 | + | |
| 1166 | + | |
| 1167 | + | |
| 1168 | + | |
| 1169 | + | |
1152 | 1170 | | |
1153 | 1171 | | |
1154 | 1172 | | |
| |||
0 commit comments