fix(knowledge): matched was an opinion, and eleven tables that do not exist got it - #236
Merged
Conversation
…ot exist got it
`sync_status` is the word a customer reads on the code↔DB screen. `matched` says "your
code and your database agree about this table". Measured in production 2026-08-27:
db_index rows for bs ls os zes active unlimit esim clones
interfaces price contract → 0
code_db_sync status for those same eleven → matched, all of them
Eleven tables that are not in the database were reported as agreeing with it.
The mechanism, not a guess. `_match_tables` builds the code-only tail with
`_make_matched(nm, "", …)` — db_context empty, because there is no DB side. That struct
goes to the LLM, which returns a sync_status. The deterministic SYNC-L5 override fires
only when BOTH column sets are non-empty, which a table with no DB side can never satisfy,
so `effective_status = analysis.sync_status` stood and the model's answer became the
customer's fact.
`resolve_sync_status()` decides in order:
1. structure — no DB side → code_only, no code side → db_only. A missing side is a fact;
no model can overturn it and none should be asked to
2. SYNC-L5 — the column sets settle matched vs mismatch
3. the model — only where both sides exist with columns unknown on one of them, which is
where its reading is the only reading available
Judgement is removed from where it does not belong and kept where it does: a genuine pair
with a code-only column still resolves to mismatch, a clean pair still to matched, both
without asking.
23 tests, the eleven names among them verbatim. It never raises — it runs inside the sync
pipeline, and losing a table's row to an exception is worse than an uncertain status.
Suite: 6945 passed, 4 skipped, 1 xfailed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtEZboEDbEXLYrLf1owRXB
CI's Format check is a separate step from `ruff check`, and I ran only the latter before pushing. The gate caught it in 54 seconds, which is the gate working. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XtEZboEDbEXLYrLf1owRXB
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
sync_statusis the word a customer reads on the code↔DB screen.matchedsays your code and your database agree about this table.Measured in production, 2026-08-27:
Eleven tables that are not in the database were reported as agreeing with it.
The mechanism, not a guess
_match_tablesbuilds the code-only tail with_make_matched(nm, "", …)—db_contextempty, because there is no DB side. That struct goes to the LLM, which returns async_status.The deterministic SYNC-L5 override fires only when both column sets are non-empty — which a table with no DB side can never satisfy. So
effective_status = analysis.sync_statusstood, and the model's answer became the customer's fact.The order that replaces it
resolve_sync_status():code_only. No code side →db_only. A missing side is a fact; no model can overturn it and none should be asked to.matchedversusmismatch.The fix takes judgement away from where it does not belong and leaves it where it does. Verified on the real names:
Tests
23, with the eleven production names verbatim. It never raises:
resolve_sync_statusruns inside the sync pipeline, and losing a table's row to an exception is worse than keeping a status that is merely uncertain.Suite:
6945 passed, 4 skipped, 1 xfailed.This is the third defect in this feature found in one sitting — the other two being invented table names (#234) and a guard that did not apply on load (#235). All three were found by measuring production rather than reading the code.
🤖 Generated with Claude Code
https://claude.ai/code/session_01XtEZboEDbEXLYrLf1owRXB