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
* docs(agents): claim the issue before writing any code
Several agents work this repo at once and an unassigned issue reads as an
open invitation. Two agents starting the same issue burn the same hours
twice and then race to land conflicting shapes for one problem.
Makes assignment the first action of a task — before the worktree, before
the first read — and states the corollary for Prime Directive #10: file a
finding unassigned, assign it at the moment you actually start, so the
issue list works as a queue other agents can trust.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WsgTqRF58HsQYKLsrZ5pQY
* feat(spec)!: retire datasource.readReplicas (#4468)
BREAKING CHANGE: `datasource.readReplicas` is removed.
It described replica connections nothing ever opened. `ConnectableDatasource`
and `DatasourceConnectionSpec` carry no replicas field, the driver factory
never reads the key, and no query path distinguishes a read from a write —
the platform has no read/write splitting at all, so every statement always
went to the primary regardless of what was declared.
There is no target to move to, because there is no read-replica routing to
move to. Front replicas behind one endpoint (pgpool, ProxySQL, an RDS reader
endpoint) and point `config` there; `os migrate meta --from 16` strips the key.
Worth recording why this one survived so long: #4410 closed the
`datasource.config` gap and, reasonably, extended the new per-driver
validation over each `readReplicas` entry. The result was a slot with every
marker of a working feature — declared, `.strict()`-guarded, and validated
field-by-field against the driver's contract, rejecting a misspelt replica
host by index. None of that is evidence of a consumer and all of it reads
like one. Rigor is cheap to add to a dead slot and expensive to tell apart
from life, which is why ADR-0049 asks for a consumer rather than for rigor.
The retirement kit:
- DatasourceSchema: key deleted (strict route), `readReplicas`/`replicas`
added to the guidance map so the rejection carries the prescription; the
#4410 validation loop removed with it
- `datasource-read-replicas-removed` D2 conversion + step-17 chain wiring,
retired from the load path like the other keys retired for misdescribing
themselves
- authorable-surface baseline line deleted deliberately (gate (a)'s strict-
removal trip wire); spec-changes, upgrade guide, reference docs regenerated
- pin test flipped from "validates each entry" to "rejects the slot"
- release notes, strictness ledger, and the two pending changesets that still
described the key corrected
Follow-ups filed: #4479 (read-replica routing as a real feature request,
starting from the read/write decision point) and #4480 (the same feature
declared a second time as `DatabaseConnector.readReplicaConfig`, also unread).
Closes#4468
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WsgTqRF58HsQYKLsrZ5pQY
---------
Co-authored-by: Claude <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: content/docs/releases/v17.mdx
+15-7Lines changed: 15 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -412,12 +412,13 @@ schema to the two highest-risk authorable surfaces, per the triage in
412
412
-**Datasources** — `DatasourceSchema` with its `pool` / `healthCheck` / `ssl` /
413
413
`retryPolicy` blocks, the ADR-0015 `external` federation settings and their
414
414
`validation` policy, `DatasourceCapabilities`, and `DriverDefinitionSchema`.
415
-
`config` and `readReplicas` stay **open** records: their shape is per-driver.
416
-
Nothing validates *inside* them — an earlier version of this note said the
417
-
driver's own `configSchema` did, which was wrong; the per-driver schemas exist
418
-
(`PostgresConfigSchema` and siblings) but nothing parses `config` against
419
-
them, tracked as #4410. So a misspelling one level *down* is still silent
420
-
today. That openness is why the
415
+
`config` stays an **open** record: its shape is per-driver. What it no longer
416
+
is, is unvalidated — #4410 wired the per-driver schemas
417
+
(`PostgresConfigSchema` and siblings) into `DatasourceSchema`'s refinement, so
418
+
a misspelling one level *down* is now rejected with the canonical key named.
419
+
An earlier version of this note said the driver's own `configSchema` did that,
420
+
which was wrong for two releases: the field existed, nothing read it. That
421
+
openness is why the
421
422
top level had to close — a connection key written one level too high (`host`
422
423
next to `driver` instead of inside `config`) was stripped, and the datasource
423
424
then connected on driver defaults rather than failing. Those keys now
@@ -1014,6 +1015,7 @@ import or the authored key.
1014
1015
|`DEFAULT_DISPATCHER_ROUTES`| dead route table |
1015
1016
| Aspirational config on Theme / Translation / Webhook | still-dead after #3494|
1016
1017
|`ChartInteraction.zoom` / `.clickAction`| never implemented (#3752) |
1018
+
|`datasource.readReplicas`| replica connections nothing ever opened — no driver reads the key and no query path splits reads from writes, so every statement went to the primary. #4410 had just taught the schema to validate each entry against the declared driver's contract, which made a dead slot look rigorously alive (#4468) |
1017
1019
1018
1020
The Console side follows: `@object-ui/types` drops its
1019
1021
`ObjectStack`/`ObjectOS`/`ObjectQL`/`ObjectUI` Capabilities re-exports, which
@@ -2034,7 +2036,13 @@ covers are folded into the list below rather than left to the changelog.)
2034
2036
exit code to assert on: nothing left to do exits `0`.
2035
2037
- **Datasources:** verify every declared datasource connects in every
2036
2038
environment — a bound datasource that cannot connect now fails the boot
2037
-
instead of failing every later query.
2039
+
instead of failing every later query. Delete `readReplicas` (`os migrate meta`
2040
+
does it). Nothing ever opened those connections, so read throughput is
2041
+
unchanged by removing them; if you need replica reads, front them behind one
2042
+
endpoint (pgpool, ProxySQL, an RDS reader endpoint) and point `config` there.
2043
+
Also re-check what you wrote under `config`: it is parsed against the driver's
2044
+
contract now, so a key that used to be ignored — and left the datasource on
2045
+
driver defaults — is rejected by name.
2038
2046
- **Sharing rules:** rewrite `sharedWith.type: 'group'` → `'team'`; drop `guest`
2039
2047
and owner-type rules; expect `accessLevel: 'full'` to convert to `'edit'`.
2040
2048
**A rule must state its criteria** — authoring one without is rejected, and a
|`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`**at this level** by construction (per-driver shapes), but are no longer unchecked: **#4410** made `DatasourceSchema`'s refinement parse both 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 |
188
-
| `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` (and each `readReplicas` entry) against them, and the same schemas project onto `configSchema` and onto the Studio connection form. `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 |
187
+
| `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 |
188
+
| `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 |
189
189
|`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) |
0 commit comments