fix(sql): attribute a duplicated key to its own tags; key-value cap gets 2x headroom (R06:S-1 review I-1, m-3)
One stray duplicate row used to fail every tag in a key-value group or none of them, depending on whether an unrelated key was absent. Duplicated keys are now refused per key: only that key's tags publish BadConfigurationError and the rest of the group reads normally. The key-value cap reads up to 2x the distinct keys (+1 to detect excess), so a few stray duplicates are attributed per key and only a gross excess (history/events table) fails the whole group. Duplicated-key refusals count as answered refusals for health. The row-cap, duplicate-key and multi-row warnings now use the per-plan limiter (m-3); the reader-wide limiter is removed. Unit tests pin both the all-keys-present and absent-key cases with Good controls; live SQL Server gate added (23/23). Refs #744 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
+17
-10
@@ -166,16 +166,23 @@ emits a `SqlQueryPlan` per distinct group key. Grouping is deterministic (groups
|
||||
order of their first member, members keep their input order, parameters keep first-appearance order),
|
||||
so an unchanged configuration produces byte-identical SQL.
|
||||
|
||||
**Every key-value and where-pair query is row-capped (R06:S-1).** A key-value plan asks for one row more
|
||||
than it has distinct keys (`TOP (n+1)` / `LIMIT n+1` / `FETCH FIRST n+1 ROWS ONLY`), a where-pair wide-row plan
|
||||
for two, and the reader stops reading there even if a provider ignores the limit. Receiving the extra row
|
||||
proves the selector is ambiguous — a history/events table, or a where column that is not unique — so every
|
||||
member of that group publishes `BadConfigurationError` with a rate-limited warning naming the table and
|
||||
selector, instead of the old behaviour of materialising every matching row on every poll and publishing an
|
||||
arbitrary "last row" at Good. A duplicate that fits inside the cap (a duplicated key alongside an absent one)
|
||||
still resolves last-row-wins. `topByTimestamp` keeps its single-row limit. An over-cap answer, like every
|
||||
other refusal (absent row, NULL cell, uncoercible cell), is the database answering: it advances
|
||||
`LastSuccessfulRead` and restores `Healthy` after a comms fault.
|
||||
**Every key-value and where-pair query is row-capped (R06:S-1).** A key-value plan reads at most twice as
|
||||
many rows as it has distinct keys and asks for one more (`TOP (2n+1)` / `LIMIT 2n+1` / `FETCH FIRST 2n+1 ROWS
|
||||
ONLY`); a where-pair wide-row plan asks for two. The reader stops there even if a provider ignores the limit.
|
||||
|
||||
- **A duplicated key is refused per key.** When a key comes back more than once, only the tags on THAT key
|
||||
publish `BadConfigurationError`; every other key in the group reads normally, whatever else is present or
|
||||
absent. (Before this, a duplicate was last-row-wins Good.)
|
||||
- **A gross excess fails the group.** Receiving the extra row past the cap means a history/events table or a
|
||||
non-unique where column, which cannot be attributed because the rest is unread, so every member of the group
|
||||
publishes `BadConfigurationError`. For a where-pair any second row is this case.
|
||||
- Each case logs a per-plan rate-limited warning naming the table and the selector (or an example key).
|
||||
`topByTimestamp` keeps its single-row limit.
|
||||
- **Upgrade note:** a deployment whose key-value source carries stray duplicate rows, or whose where column is
|
||||
not unique, will see those tags go Bad where they used to read an arbitrary row at Good.
|
||||
|
||||
Every such refusal, like the other refusals (absent row, NULL cell, uncoercible cell), is the database
|
||||
answering: it advances `LastSuccessfulRead` and restores `Healthy` after a comms fault.
|
||||
|
||||
⚠️ **Group keys are case-sensitive on identifiers.** Two tags authored `dbo.T` and `DBO.T` plan as
|
||||
**two** groups — one extra round-trip, not a correctness problem, but worth knowing if a group count
|
||||
|
||||
Reference in New Issue
Block a user