Commit eb93349
docs(drivers): measure the ContainsAny phantom-leg sweep across eight door pins (#17967)
Fixes #17879
Clause-②: no
A **measurement** card, not a defect sweep. Every reading below was
taken on disk against
`origin/main@bdb247d`, control first, with each leg's direction
predicted before it was run.
## Headline
**No detector was swapped, anywhere — and that is the measured result,
not a gap.**
The phantom half is real on all eight doors. The `ContainsAny` template
landed by #17876 closes
**none** of them: seven are defeated by one mechanism, and the eighth is
already masked today.
## The mechanism, measured
`ContainsAny` distributes over a union, because `T` is naked in its
array/record arms. So a
door that is a union answers `boolean`, and **both** of the family's
assertion forms accept
`boolean`:
```text
const leg: boolean = false compiles -> the `= false` half stays GREEN
boolean extends true ? never : X picks X -> the conditional half stays GREEN
```
Calibration, measured twice in independent runs (a line that errors =
that leg reddens):
```text
shape IsAny leg ContainsAny leg
any (bare) RED RED <- control fires
any[] green RED <- template works
Record[string, any] green RED <- template works
Record[string, any] | null green GREEN <- template INERT
Record[string, any] | undefined green GREEN <- template INERT
any[] | undefined green GREEN <- template INERT
```
Seven of my eight doors are unions — either a not-found arm (`| null`)
or an optional
parameter (`| undefined`). That is why the swap buys nothing on them.
## Per-file measurement
`resolves to` is read off the door itself; `CONTROL` puts that door back
to a **bare** `any`;
`NESTED` puts it back to a nested one. Counts are errors **in that
file**.
| # | file | door resolves to | CONTROL (bare any) | NESTED | swap? |
|---|---|---|---|---|---|
| 1 | `sql-driver-distinct-filter-narrowing` | `FilterCondition \|
undefined` | **3 errors** — fires | **0** | no — union **and** saturated
|
| 2 | `sql-driver-update-declared-null` | `Record[string, unknown] \|
null` | **2 errors** — fires | **1** (`Equals` only) | no — union |
| 3 | `sqlite-wasm-16711-inherited-object-def-keys` | nested `any`
**today** (see below) | **7 errors** — fires | n/a | no — RED on `main`
|
| 4 | `sqlite-wasm-distinct-filter-narrowing` | `FilterCondition \|
undefined` | **2 errors** — fires | **0** | no — union **and** saturated
|
| 5 | `sqlite-wasm-update-declared-null` | `Record[string, unknown] \|
null` | **2 errors** — fires | **1** (`Equals` only) | no — union |
| 6 | `turso-driver-options-door` (17 doors) | `DriverOptions \|
undefined` | row reds (TS1360) — fires | **0** | no — union |
| 7 | `turso-driver-update-declared-null` | `Record[string, unknown] \|
null` | **2 errors** — fires | **1** (`Equals` only) | no — union |
| 8 | `turso-update-missing-id` | `Record[string, unknown] \| null` |
**2 errors** — fires | **1** (`Equals` only) | no — union |
**The control fired on all eight**, so no reading here is void. In every
NESTED run a shadow
`ContainsAny` leg was compiled alongside the real one: it stayed green
in all seven applicable
cases, which is the direct measurement that the swap would have bought
nothing.
Files 1 and 4 carry a second, independent reason:
`ContainsAny[FilterCondition]` is already
`true`, because `FilterCondition` is an open map with `any` values by
contract. The detector is
**saturated** on the correct door and cannot separate it from a
regression at all.
## File 3 — the strongest reading in the sweep
`SqliteWasmDriver.initObjects`'s parameter does not merely *regress* to
a nested `any`. It
**is** one, on `main`, today:
```text
objects: Array[{ name: string; fields?: Record[string, any]; tenancy?: any;
indexes?: any[]; lifecycle?: any }]
```
Four sub-doors are masked (`fields`, `tenancy`, `indexes`, `lifecycle`),
and the file's two
`IsAny` legs are green about all four. `ContainsAny` there is **RED at
baseline** — it would go
red on `main`, not on a regression — so the swap is not available.
Un-masking the door is a
change to `SqlDriver.initObjects` in `@objectstack/driver-sql`, a
**non-test file**, which is
outside this card (stop condition: *the fix would require touching a
non-test file*).
Worth recording: the existing pair already covers the `objects: any[]`
shape — the **element**
leg catches it, since the element of `any[]` is `any`.
## The two excluded files — read-only, nothing touched
`driver-memory` is under the #5499 investment freeze, so this is a
source read plus the
calibration table above — no probe, no run, no file touched in that
package. It is a
**derived** reading, flagged as such:
| door | resolves to | would the template work? |
|---|---|---|
| `InMemoryDriver.update` | `Record[string, unknown] \| null` | no —
union |
| `InMemoryDriver.upsert` | `Record[string, unknown]` | **yes** |
| `InMemoryDriver.find` | `Record[string, unknown][]` | **yes** |
| `InMemoryDriver.findOne` | `Record[string, unknown] \| null` | no —
union |
| `InMemoryDriver.create` | `Record[string, unknown]` | **yes** |
So the frozen pair holds **the only three doors in the whole population
where #17876's template
is effective exactly as written**. That is a question for triage, not
for this PR.
## What this PR changes
Eight comment blocks, one per file, recording that file's measured
reading where the next
author will look. **No detector, no assertion and no type was changed**
— so this diff cannot
move any verdict, and it does not preempt the repair decision.
## Verification
```text
pnpm --filter @objectstack/driver-sql typecheck exit 0 (tsc --noEmit)
pnpm --filter @objectstack/driver-sqlite-wasm typecheck exit 0 (tsc --noEmit)
pnpm --filter @objectstack/driver-turso typecheck exit 0 (tsc --noEmit)
driver-sql test 176 files / 2602 passed, 11 + 164 skipped
driver-sqlite-wasm test 29 files / 518 passed
driver-turso test 52 files / 1248 passed
VERDICT command-exit 0 (shared verify lock)
pnpm lint (repo-wide, `eslint . --no-inline-config`) exit 0 in 2m0s
dispatch-gates derived families 49 of 52 PASS
```
The three not in that 49 exited **3 = PREREQUISITE NOT MET**, which is
neither a pass nor a
failure: `check:dual-build-cjs-loads`, `check:lean-entry-closure` and
`check:type-check-debt`
each need a full-monorepo `pnpm build` this worktree never did. **NOT
MEASURED**, declared to
CI, which builds fresh. None can be reached by a comment-only diff.
Ablation hygiene: every mutation leg proved its edit on disk before the
run and proved the
artifact carried it (`scripts/ablation-dist-preflight.mjs`, driver-sql
rebuilt per wasm leg);
every restore leg was proved by blob hash against `HEAD` and a
whole-tree `git status`.
## Changeset — measured, not assumed
`skip-changeset`. `npm pack --dry-run --json` in all three packages: the
intersection of
(changed paths) and (shipped paths) is **empty**, with a positive
control present in every
listing. `files[]` is `["dist","README.md","CHANGELOG.md"]` in all three
— `src/**` never
ships, and no `.test.` file appears in any tarball. Zero published bytes
move.
## Acceptance notes
- **Not filed, recommended for the seat:** `SqlDriver.initObjects`'s
parameter masks four
sub-doors (`fields`, `tenancy`, `indexes`, `lifecycle`). Measured, live
on `main`, with a
pin that is green about it. The fix is a non-test narrowing in
`@objectstack/driver-sql`.
- **Not filed, observation:** #17876's own `findOne` leg
(`ContainsAny[SqlFindOne] = false`, door `Record[string, unknown] |
null`) has the same
union blind spot measured here. Its array and bare-record legs are
unaffected and sound.
- The repair itself is **not** proposed here: both candidates were
measured, and either also
changes the two files #17876 already landed, which is outside this
card's eight.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01RuoNSXUbBoWHkNS4AknTrM
---
_Generated by [Claude
Code](https://claude.ai/code/session_01RuoNSXUbBoWHkNS4AknTrM)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 00c332b commit eb93349
8 files changed
Lines changed: 139 additions & 0 deletions
File tree
- packages/drivers
- driver-sqlite-wasm/src
- driver-sql/src
- driver-turso/src
Lines changed: 19 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
51 | 51 | | |
52 | 52 | | |
53 | 53 | | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
54 | 73 | | |
55 | 74 | | |
56 | 75 | | |
| |||
Lines changed: 19 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
49 | 49 | | |
50 | 50 | | |
51 | 51 | | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
52 | 71 | | |
53 | 72 | | |
54 | 73 | | |
| |||
Lines changed: 19 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
39 | 58 | | |
40 | 59 | | |
41 | 60 | | |
| |||
Lines changed: 17 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
37 | 54 | | |
38 | 55 | | |
39 | 56 | | |
| |||
Lines changed: 16 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
37 | 37 | | |
38 | 38 | | |
39 | 39 | | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
40 | 56 | | |
41 | 57 | | |
42 | 58 | | |
| |||
Lines changed: 17 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
65 | 82 | | |
66 | 83 | | |
67 | 84 | | |
| |||
Lines changed: 16 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
42 | 42 | | |
43 | 43 | | |
44 | 44 | | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
45 | 61 | | |
46 | 62 | | |
47 | 63 | | |
| |||
Lines changed: 16 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
107 | 123 | | |
108 | 124 | | |
109 | 125 | | |
| |||
0 commit comments