Skip to content

Commit b6b5e91

Browse files
committed
chore(changeset): service-datasource reads the metadata service when used (narrowing on start)
Claude-Session: https://claude.ai/code/session_011K3zqE8Pv1Evw5hc8tZCnN Co-authored-by: Claude <noreply@anthropic.com>
1 parent 10dd861 commit b6b5e91

1 file changed

Lines changed: 45 additions & 0 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
---
2+
'@objectstack/service-datasource': minor
3+
---
4+
5+
fix(service-datasource)!: on `objectstack start`, external validation and the boot gate compare every federated object
6+
7+
**BREAKING (narrowing)** — on `objectstack start` a deployment with real schema drift on a
8+
federated object can now refuse to boot, as its `external.validation.onMismatch` setting
9+
declares.
10+
11+
The federation service (`ExternalDatasourceServicePlugin`) read the `metadata` service once,
12+
in its `init()`, and kept the answer. `objectstack start` composes no metadata plugin: its
13+
`metadata` service is the kernel's in-memory fallback, which the kernel registers after every
14+
plugin's `init()`, just before the start phase. So on `start` the federation service kept "no
15+
metadata service" for the life of the process, and every read behind it answered as if the
16+
deployment declared nothing. It now asks for the `metadata` service each time it reads it, so
17+
`start` sees what `objectstack dev` always saw.
18+
19+
| on `objectstack start` | before | now |
20+
| --- | --- | --- |
21+
| the boot gate (ADR-0015 §5.2) | logged "all federated objects match their remote schema" with `objects: 0`, having compared nothing, so no `onMismatch` policy ever applied | compares every federated object and applies each datasource's `onMismatch` to every measured mismatch |
22+
| `POST /api/v1/datasources/:name/external/validate` | `ok: true` with no rows | one row per federated object bound to the datasource, with its diffs |
23+
| `POST /api/v1/datasources/:name/external/refresh-catalog` | answered the snapshot, never stored it | also stores it as the datasource's `external_catalog` record |
24+
| `GET /api/v1/datasources/:name/external/tables` | ignored the datasource's `external.allowedSchemas` | leaves out a table whose schema is outside them |
25+
| draft and import names | never resolved a package namespace: drafts were unprefixed, and an import's explicit `name` was never held to the ADR-0028 prefix rule | resolve the namespace of the datasource's package when the datasource carries package provenance; an import whose explicit `name` lacks that prefix is refused `400 EXTERNAL_IMPORT_ERROR` |
26+
27+
**What to do if a `start` deployment now refuses to boot.** Under `onMismatch: 'fail'` (the
28+
default) the boot stops with `ExternalSchemaMismatchError`, naming the object, the datasource
29+
and each drifted column. Either fix the drift (align the object's fields, its
30+
`external.columnMap` or `external.ignoreColumns`, or the remote table) or set
31+
`external.validation.onMismatch: 'warn'` on that datasource, which boots and logs the drift
32+
instead. To see the drift before deploying, call
33+
`POST /api/v1/datasources/:name/external/validate` on `objectstack dev`, which already
34+
compared. A remote that cannot be reached still never stops the boot. An import refused for
35+
its name takes a `name` carrying the datasource package's namespace prefix.
36+
37+
**Unchanged.** `objectstack dev`, and every composition that registers a metadata plugin before
38+
the federation service, answers exactly as before: measured on the showcase, every federation
39+
door and the boot gate gave the same answers before and after. What validation judges, what
40+
each `onMismatch` value does, and the boot gate's skip for a datasource that sets
41+
`external.validation.checkOnBoot: false` are unchanged.
42+
43+
Clause-②: no (narrowing)
44+
45+
<!-- adr-0087: not-required (no-migration-prescription) No authorable key, spelling, export, config field or stored shape is removed or renamed, and no stored row is read or rewritten: on a composition with no metadata plugin the federation service now reads the metadata service it always declared it reads, so the boot gate and the federation doors judge the objects and datasources the deployment already declares. The handling above is an operator choice between two settings that already exist, not a FROM to TO mapping that objectstack migrate meta could apply. The other categories are closed on facts: the package publishes (not unpublished); no ADR-0087 id covers when a plugin resolves a service (not registered / already-registered); and the change is runtime behaviour, not a declaration (not runtime-interface-only / type-surface-only). -->

0 commit comments

Comments
 (0)