You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* fix(spec): stop promising validation that never runs, and let the strictness ledger see nested dirs (#4001)
Two corrections to the #4001 unknown-key campaign. Both are the same defect the
campaign exists to remove — a success signal covering an omission — found in the
campaign's own output.
1. The `config` prescription was false.
`DatasourceSchema` went strict in #4207 with `config` left open, and the
rejection for a misplaced connection key prescribed: "Move it to
`config: { host: … }`; the driver's own configSchema validates it there."
Nothing validates it there. `DriverDefinitionSchema.configSchema` is a
`z.record`; both bundled driver specs set it to `{}` (mongo's with a comment
promising runtime population that no code performs); and no consumer in this
repo reads it. So the message took an author who had made a recoverable mistake
at a place that now catches it and directed them, with the platform's authority,
at a slot where the same mistake is silent again — `config: { hostname: … }` is
stripped and the datasource connects on localhost, which is #4001's original bug
one level down.
The guidance now names the per-driver shape to write against
(`PostgresConfigSchema` / `MongoConfigSchema` / `MemoryConfigSchema`) and claims
nothing about enforcement. Same false claim removed from `driver/mongo.zod.ts`,
whose header advertised that the Platform validates `datasource.config` with it.
Enforcement — enforce-or-remove on an inert `configSchema` — is filed as #4410.
Error-message and documentation text only; no authorable key changed.
2. The ledger gate's coverage walk was one level deep.
`check:strictness-ledger` promises every sited `*.zod.ts` in a triaged directory
carries a classification row. It listed directories non-recursively, so
`data/driver/` — three per-driver config files, nine authorable sites — was
invisible to the check whose entire promise is "no undeclared surface", which
printed "no undeclared schema files" and was believed.
A gate that under-reports is worse than no gate: it converts "I should classify
this" into "it is already classified". The walk is now recursive, the three
files are classified, and the ledger records both findings.
`scripts/strictness-ledger.test.ts` pins the recursion, and is not redundant with
the gate: measured, with the rows now present, reverting to a non-recursive walk
leaves the gate GREEN — it cannot catch its own regression. The test can, and
was verified to go red before it went green.
Verified: spec 283 files / 7205 tests, `tsc --noEmit` clean, all 8 generated
artifacts current, and all 10 `check:*` gates green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY
* fix(docs): v17 release notes repeated the false driver-configSchema claim (#4001)
Fourth and last copy, and the only user-facing one. The v17 notes told readers
that `config` and `readReplicas` stay open records because "the driver's own
`configSchema` validates them" — the same sentence corrected in
`datasource.zod.ts` (module comment + the `belongsInConfig` rejection) and
`driver/mongo.zod.ts`.
Found by this PR's own docs-drift advisory, which is worth recording: the bot
listed 107 docs on a package-level heuristic and the correction was real in
exactly one of them. Cheap to check, and it was the copy readers actually see.
Now states that nothing validates inside `config`, that the per-driver schemas
exist but parse nothing, and that a misspelling one level down is still silent —
with the pointer to #4410.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WnqGjQFQMqd5k81LYV8SCY
---------
Co-authored-by: Claude <noreply@anthropic.com>
Datasource unknown-key guidance no longer promises validation that does not happen, and the #4001 strictness ledger sees nested schema directories.
6
+
7
+
Two related corrections to the #4001 unknown-key campaign, both about a check reporting more coverage than it had.
8
+
9
+
**The `config` prescription was false.** When `DatasourceSchema` rejects a connection detail written at the top level, it prescribed: "Move it to `config: { host: … }`; the driver's own configSchema validates it there." Nothing validates it there — `DriverDefinitionSchema.configSchema` is a `z.record` that both bundled driver specs set to `{}`, and no consumer reads it. The message therefore took an author who had made a recoverable mistake at a place that now catches it and pointed them at a slot where the same mistake is silent again: `config: { hostname: … }` is dropped and the datasource connects on localhost. The guidance now names the per-driver shape to write against (`PostgresConfigSchema` / `MongoConfigSchema` / `MemoryConfigSchema`) instead of promising a gate. Enforcement is tracked in #4410. The same false claim is removed from `data/driver/mongo.zod.ts`, whose header advertised that the Platform validates `datasource.config` with it.
10
+
11
+
No authorable key changed — this is error-message and documentation text only.
12
+
13
+
**The ledger gate's coverage walk was one level deep.**`check:strictness-ledger` promises that every `*.zod.ts` with sites in a triaged directory carries a classification row. It listed each directory non-recursively, so `data/driver/` — three per-driver config files, nine authorable sites — was invisible to it while it printed "no undeclared schema files". The walk is now recursive (nested files declare as `driver/postgres.zod.ts`), those three files are classified in the ledger, and `scripts/strictness-ledger.test.ts` pins the recursion — necessary because with the rows in place the gate itself passes either way and cannot catch its own regression.
|`filter.zod.ts` / `query.zod.ts`| 11+5 | open | query dialect — user data flows through; validated semantically elsewhere. `query.zod.ts` dropped one site in #4196: `FieldNodeSchema`'s nested-select object form was declared-but-inert and narrowed to `z.string()`, so the union's second member is gone. Four more left in #4286 with the `joins`/`windowFunctions` removals: `JoinNodeBaseSchema`, `WindowFunctionNodeSchema`, and `WindowSpecSchema`'s two blocks (outer + `frame`) were deleted with their clusters. Class unchanged |
|`datasource.zod.ts`| 9 | authorable |**strict as of #4001 data step** — all 9: `DatasourceSchema` (+ `pool` / `healthCheck` / `ssl` / `retryPolicy`), `ExternalDatasourceSettingsSchema` (+ `validation`), `DatasourceCapabilities`, `DriverDefinitionSchema`. `config` + `readReplicas` stay `z.record` by construction (per-driver shapes; the driver's own `configSchema` validates them) — which is precisely why the top level had to close: a connection key written one level too high was stripped, and the datasource then connected on driver defaults instead of failing |
172
+
|`datasource.zod.ts`| 9 | authorable |**strict as of #4001 data step** — all 9: `DatasourceSchema` (+ `pool` / `healthCheck` / `ssl` / `retryPolicy`), `ExternalDatasourceSettingsSchema` (+ `validation`), `DatasourceCapabilities`, `DriverDefinitionSchema`. `config` + `readReplicas` stay `z.record` by construction (per-driver shapes — see the `driver/` row below). This row used to add "the driver's own `configSchema` validates them"; **it does not, and never did** — corrected, and the gap is #4410. Which is precisely why the top level had to close: a connection key written one level too high was stripped, and the datasource then connected on driver defaults instead of failing |
173
+
|`driver/memory.zod.ts` / `driver/mongo.zod.ts` / `driver/postgres.zod.ts`| 6+1+2 | authorable | The per-driver shapes for the `config` slot — what an author actually writes under `datasource.config` (`host`, `port`, `filename`, pool sizes). **Undeclared here until the coverage walk went recursive** (see below): a subdirectory was invisible to the gate, so these nine sites sat outside the map while the map reported full coverage. Authorable by the rule, but they are **contract-only exports today** — nothing parses `datasource.config` against them and both `*DriverSpec.configSchema` literals are `{}` (#4410). Strictness here would therefore enforce nothing; this row is blocked on #4410 giving it a parse site, not on a verification pass |
161
174
|`analytics.zod.ts`| 8 | mixed (p) ||
162
175
|`document.zod.ts`| 8 | wire (p) ||
163
176
|`hook.zod.ts` / `hook-body.zod.ts`| 6+2 | mixed |**strict as of #4001 data step** for the AUTHORING shapes: `HookSchema` (+ `retryPolicy`) and both body branches (`ExpressionBodySchema` / `ScriptBodySchema`). `HookContextSchema` and its `session` / `provenance` / `user` blocks are the RUNTIME shape the engine hands a handler — they stay tolerant, and must: strictness there would make an engine-internal enrichment (as `provenance` was in #3712) a breaking change for anyone parsing a context they were given. The file's old blanket `authorable (p)` was too wide — verification split it |
@@ -220,6 +233,32 @@ tightening (the #4001 "sharing-rule lesson": candidates, not verdicts).
220
233
strict close-out on what it actually reports — which is the whole point of
221
234
having built it. Nothing more to do here until there is field data.
222
235
236
+
**This wait has a decision point, deliberately.** "Wait for field data" with
237
+
no way to tell when it has arrived is how a ratchet stops without anyone
238
+
choosing to stop it — and this file would go on describing an in-flight
239
+
campaign either way. So the wait is discharged by an answerable question, not
240
+
by a date: *has `lintUnknownAuthoringKeys` reported an unknown key on any
241
+
surface outside this repo yet?* Three outcomes, each with a next action:
242
+
-**Findings exist** → they are the close-out worklist. Tighten the shapes
243
+
they name first; that is the evidence the whole layer was built to produce.
244
+
-**Zero findings, and the layer is reaching real authors** → the tail is
245
+
cheaper than feared and the remaining directories can be batched by class
246
+
rather than one shape at a time.
247
+
-**Zero findings because nothing is reporting back** → then the layer is not
248
+
instrumented, and *that* is the next task, not more strictness. This is the
249
+
outcome to actually check for: it is indistinguishable from success at a
250
+
glance, which is this campaign's own subject matter.
251
+
252
+
Whoever reads this next: answer the question and record the answer here, even
253
+
if the answer is "still nothing". A wait that is never re-examined is
254
+
indistinguishable from an abandoned one.
255
+
256
+
2.`studio/` is the largest untouched authorable block — 27 sites, **0 strict**,
257
+
and all three files still carry a provisional `(p)` from the original triage.
258
+
Not blocked on field data (Studio-written JSON is our own producer, so the
259
+
downstream risk is the lowest on the board); it is simply unstarted. If the
260
+
step-1 question comes back "nothing is reporting", start here instead.
261
+
223
262
Done in step 2: `security/rls.zod.ts` + `security/sharing.zod.ts` strict;
224
263
`PositionSchema` strict with the protection envelope declared (closing the
225
264
known sibling gap below).
@@ -303,9 +342,11 @@ checkable, so this map cannot go stale in silence again:
303
342
matches means schemas were added or removed under a `Class` verdict nobody
304
343
re-examined. Touching a file forces you back through this ledger.
305
344
-**Coverage.** Every `*.zod.ts` in a triaged directory that HAS sites must have
306
-
a row. A new one is undeclared surface. Zero-site files (pure enum/token
307
-
modules like `data/date-macros.zod.ts`) are skipped — there is nothing to
308
-
classify — and become reportable the day they grow their first `z.object(`.
345
+
a row. A new one is undeclared surface. The walk is **recursive**; nested files
346
+
are declared by their path relative to the section directory
347
+
(`driver/postgres.zod.ts`). Zero-site files (pure enum/token modules like
348
+
`data/date-macros.zod.ts`) are skipped — there is nothing to classify — and
349
+
become reportable the day they grow their first `z.object(`.
309
350
-**Section totals**, and that any row claiming "strict as of" names a file that
310
351
really contains `.strict()`.
311
352
@@ -336,5 +377,23 @@ precisely the intended behaviour: the file arrived, so someone had to classify
336
377
it. It is now a row. Every existing count survived that merge unchanged, so the
337
378
failure was exactly as narrow as it should have been.
338
379
380
+
**And then the gate turned out to have the ledger's own disease.** Its coverage
381
+
walk listed each triaged directory exactly one level deep, so `data/driver/` —
382
+
three per-driver connection-config files, nine sites — was invisible to the check
383
+
whose entire promise is "no undeclared surface". The gate printed *"no undeclared
384
+
schema files"* while nine authorable sites sat outside the map. Fixed by making
385
+
the walk recursive; the three files are now a row.
386
+
387
+
Read that next to this file's own opening argument — *a map that drifts is worse
388
+
than no map, because it is followed*. The same asymmetry applies one level up,
389
+
and harder: **a gate that under-reports is worse than no gate, because it
390
+
converts "I should classify this" into "it is already classified."** No gate
391
+
leaves a reader suspicious; a green gate retires their suspicion. That is the
392
+
identical shape to the silent strip this whole campaign is about — a success
393
+
signal covering an omission — reproduced in the instrument built to detect it.
394
+
So when a check claims coverage, prove it sees something it is supposed to see
395
+
before trusting the green: this one was verified by watching it go red on
396
+
`data/driver/` and green again only once the rows existed.
397
+
339
398
Long tail stays gated on a verification pass per shape — never a one-shot
340
-
"make all ~453 sites strict" (ADR-0054 ratchet; #4001's own recommendation).
399
+
"make all ~500 sites strict" (ADR-0054 ratchet; #4001's own recommendation).
0 commit comments