|
| 1 | +--- |
| 2 | +'@objectstack/objectql': minor |
| 3 | +--- |
| 4 | + |
| 5 | +fix(objectql)!: a read with no projection serves the object's declared fields and the platform's system columns, never a column no metadata declares (#21571) |
| 6 | + |
| 7 | +**BREAKING (narrowing)** — what a released read door serves shrinks. A column that |
| 8 | +no metadata declares, typically a field retired in an upgrade whose column additive |
| 9 | +schema sync leaves in the table until `os migrate apply --allow-destructive`, is no |
| 10 | +longer returned by any read through the engine. |
| 11 | + |
| 12 | +| read | before | now | |
| 13 | +| --- | --- | --- | |
| 14 | +| `POST /api/v1/data/:object/query` or `GET /api/v1/data/:object` with no `fields` | every column of the table, retired ones and their values included | the declared fields, the registry's system columns, `id`, `created_at`, `updated_at` | |
| 15 | +| `GET /api/v1/data/:object/:id`, export, search hits, the RPC dispatcher, `expand`ed records | the same whole row | the same declared set | |
| 16 | +| `engine.find` / `engine.findOne` in process (hooks, flows, plugins), no `fields` | the whole row | the declared set | |
| 17 | +| an explicit `fields` naming a declared field whose column does not exist yet (driver-sql retries `select('*')`) | the whole row, retired columns included | the declared set | |
| 18 | +| `POST /api/v1/data/:object/:id/clone` of a record whose table carries a retired column | refused `INVALID_FIELD` (the copy carried the retired column into the insert) | cloned | |
| 19 | + |
| 20 | +**Unchanged:** naming a retired column in `fields` still answers `400 INVALID_FIELD` |
| 21 | +on the data door. Declared fields keep their treatment: `internal: true` omission, |
| 22 | +credential masking, formula evaluation and the hidden `__search` strip run as |
| 23 | +before, and the registry-injected tenant, owner and audit columns are still served. |
| 24 | +No driver changed: the engine shapes the rows any driver returns, so the answer is |
| 25 | +the same on every driver and every door. Writes, and the rows a write returns, are |
| 26 | +not changed by this release. |
| 27 | + |
| 28 | +**If you still read a retired column's values** (for example a one-time conversion |
| 29 | +that copies the old columns into their replacement field): run that conversion |
| 30 | +BEFORE upgrading to this release, while the old field is still declared, or, once |
| 31 | +it lands, read the unmapped columns through the operator-only `os migrate` read |
| 32 | +(objectstack#21573). There is no flag that re-opens undeclared columns on a runtime |
| 33 | +door. An in-process reader that needs a column must declare it as a field. |
| 34 | + |
| 35 | +Clause-②: no (narrowing) |
| 36 | + |
| 37 | +<!-- 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: the change narrows which physical columns the engine's read verbs return, to the field map the metadata already declares. A retired column's values stay in the table; what an app does with them is an operator action stated above (convert before upgrading, or the operator-only os migrate read), 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 a read projection (not registered / already-registered); and the change is runtime behaviour, not a declaration (not runtime-interface-only / type-surface-only). --> |
0 commit comments