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
feat(spec)!: retire datasource.capabilities — eleven flags nothing read, one a safety claim (#4583)
DatasourceCapabilities declared eleven booleans — transactions, seven query*
flags, joins, fullTextSearch, readOnly, dynamicSchema — all strict-guarded, all
read by nothing. Pushdown is decided by the runtime driver's own `supports.*`, a
different mechanism, so declaring `queryAggregations: false` never once changed
which engine path ran. Removed rather than bridged: there was nothing on the
other side to connect it to.
readOnly is why this is not tidy-up. It reads as a safety property and was
authored as one — the shipped CRM example labelled a datasource "CRM Analytics
Read Replica" on its strength while the datasource took writes like the primary.
The key had already been MOVED twice toward somewhere it might be enforced (out
of `config` in #4410, into `capabilities` in #4465) and was inert at every
address. This removes it instead of moving it a third time.
Removing it does NOT hand the author a replacement, and the rejection says so.
`external.allowWrites: false` is the one enforced write gate and applies only to
FEDERATED datasources — assertWriteAllowed returns early for a managed (or
unset-schemaMode) one, so that key would be equally inert for a local database. A
managed datasource has no read-only gate at all; that gap is #4584, deliberately
not invented here.
Also fixed: READ_ONLY_BELONGS_ON_DATASOURCE — the prescription every SQL driver
shares for a `readOnly` written inside `config` — was still sending authors TO
the removed key. A prescription that lands on an inert key manufactures exactly
the belief it was meant to correct.
DriverDefinition.capabilities goes with it: its call graph is closed too —
MemoryDriverSpec / MongoDriverSpec are referenced only by their own tests, so the
whole schema object is inert, not just the datasource-side use.
Route is strict-removal (both shapes are .strict()): keys leave the walked shape,
so the 11 ledger rows are DELETED rather than flipped, and the 13 baseline lines
in authorable-surface.json are removed deliberately in this PR — the readReplicas
(#4468) precedent. ADR-0087 conversion `datasource-capabilities-removed` is
registered in step 17, so `os migrate meta --from 16` really does rewrite author
sources rather than the tombstone merely claiming it.
datasource ledger: 20 dead -> 9 (healthCheck x3, retryPolicy x4, external x2 —
batches B/C/D of #4583). Strictness-ledger site count 9 -> 8.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E5CYr5SDwe85gH2Jr5KSgu
|`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` stays `z.record` **at this level** by construction (per-driver shapes), but is no longer unchecked: **#4410** made `DatasourceSchema`'s refinement parse it against the contract for the declared driver (`driver/config-registry.zod.ts`), so the openness here is a shape this level cannot express rather than the absence of one. This row used to add "the driver's own `configSchema` validates them", which was false until #4410 landed the parse site it names. #4410 extended the same parse to each `readReplicas` entry; **#4468 retired that key** — no driver ever opened a replica connection and no query path splits reads from writes, so the entries were being checked against a contract nothing would apply. Strictness makes a dropped key loud; it cannot make a slot live, and a *precisely validated* dead slot is the more convincing lie |
468
+
| `datasource.zod.ts` | 8 | authorable | **strict as of #4001 data step** — all 8: `DatasourceSchema` (+ `pool` / `healthCheck` / `ssl` / `retryPolicy`), `ExternalDatasourceSettingsSchema` (+ `validation`), `DriverDefinitionSchema`. `config` stays `z.record` **at this level** by construction (per-driver shapes), but is no longer unchecked: **#4410** made `DatasourceSchema`'s refinement parse it against the contract for the declared driver (`driver/config-registry.zod.ts`), so the openness here is a shape this level cannot express rather than the absence of one. This row used to add "the driver's own `configSchema` validates them", which was false until #4410 landed the parse site it names. #4410 extended the same parse to each `readReplicas` entry; **#4468 retired that key** — no driver ever opened a replica connection and no query path splits reads from writes, so the entries were being checked against a contract nothing would apply. Strictness makes a dropped key loud; it cannot make a slot live, and a *precisely validated* dead slot is the more convincing lie | **#4583 dropped the ninth site**: `DatasourceCapabilities` is gone — eleven flags no code read, on a block whose strictness was the clearest case of this row's own closing sentence. `readOnly` in particular was *precisely validated* and completely inert, and had been relocated twice (#4410, #4465) toward somewhere it might be enforced; the shipped CRM example called a datasource a read replica on the strength of it while writes went through. Class unchanged
469
469
| `driver/memory.zod.ts` / `driver/mongo.zod.ts` / `driver/postgres.zod.ts` | 6+1+1 | authorable | The per-driver shapes for the `config` slot — what an author actually writes under `datasource.config` (`host`, `port`, `filename`). **Undeclared here until the coverage walk went recursive** (see below): a subdirectory was invisible to the gate, so these sites sat outside the map while the map reported full coverage. **Strict as of #4410**, which is also what unblocked them: this row previously read "strictness here would enforce nothing" because nothing parsed `datasource.config` against these schemas and both `*DriverSpec.configSchema` literals were `{}`. Now `DatasourceSchema` parses `config` against them, and the same schemas project onto `configSchema` and onto the Studio connection form. (#4410 also ran the parse over each `readReplicas` entry; #4468 retired that key outright — see the row above.) `postgres.zod.ts` drops a site: its `ssl` was a `boolean | {ca, cert, key, …}` union, and the object arm is gone — certificates now live in the datasource-level `ssl` block (declared, strict, and until #4410 read by nobody), leaving `config.ssl` as the on/off shorthand. That narrowing is forced by the same projection: the Studio form renders anything that is not boolean/enum/number as a TEXT INPUT, so a union here would have produced a wizard whose every `ssl` value the new gate rejects. `memory.zod.ts` keeps 6 but loses two KEYS — `indexes` / `maxRecordsPerObject`, which `InMemoryDriverConfig` has no field for, removed under ADR-0049 rather than blessed by the new gate |
470
470
|`driver/mysql.zod.ts` / `driver/sqlite.zod.ts`| 1+2 | authorable | The rest of the `config` contract, added by #4410. `mysql.zod.ts` and `sqlite.zod.ts` (sqlite + sqlite-wasm) are shapes that **never existed** — both driver ids were offered by the connection form and buildable by the shared factory, with no config contract anywhere, so `driver: 'sqlite'` + a misspelled `filename` was an ephemeral `:memory:` database reported as configured. All three sites strict, same error factory as the rest of the campaign. (Their sibling `driver/common.zod.ts` holds shared enums and prescription strings and has no `z.object(` site, so the coverage gate skips it) |
Copy file name to clipboardExpand all lines: docs/protocol-upgrade-guide.md
+1Lines changed: 1 addition & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -188,6 +188,7 @@ The `script` flow node converges on its one real path (#4343). It had four ways
188
188
|`stack-api-require-auth-removed`|`stack.api.requireAuth`| stack key 'api.requireAuth' removed — anonymous access is always denied; publish public surfaces by declaration (#3963) | retired — `migrate meta` only |
189
189
|`flow-node-wait-timeout-keys-removed`|`flow.node.waitEventConfig`| waitEventConfig keys 'timeoutMs' (→ 'timerDuration', stringified — its only reader used it as the duration) and 'onTimeout' (removed — zero readers, so no timeout ever fired) (#4158) | retired — `migrate meta` only |
190
190
|`datasource-read-replicas-removed`|`datasource.readReplicas`| datasource key 'readReplicas' removed (#4468 — no driver opened a replica connection and no query path splits reads from writes; front replicas behind one endpoint and point `config` at it) | retired — `migrate meta` only |
191
+
|`datasource-capabilities-removed`|`datasource.capabilities`| datasource key 'capabilities' removed (#4583 — eleven flags no code read; pushdown comes from the driver's own supports.*, and `readOnly` never made anything read-only) | retired — `migrate meta` only |
191
192
|`flow-node-script-branch-keys-removed`|`flow.node.script.config.actionType / flow.node.script.config.template / flow.node.script.config.recipients / flow.node.script.config.variables / flow.node.script.config.script`| script flow-node config keys 'actionType' (→ 'function' when it was shorthand for one; otherwise removed — 'email'/'slack' were logger-backed stubs that delivered nothing), plus 'template' / 'recipients' / 'variables' (fed those stubs) and 'script' (inline JS the runtime never executed) (#4343) | retired — `migrate meta` only |
192
193
193
194
### Semantic (delegated to you, with acceptance criteria)
0 commit comments