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
{{ message }}
Repository navigation
Commit 06f0798
Browse filesBrowse the repository at this point in the historyBrowse files
Refusals, log lines and field help in core, the in-memory and MongoDB drivers, formula, metadata, metadata-core, objectql and platform-objects no longer cite tracker numbers; each states the reason in words
13
+
14
+
Clause-②: no
15
+
16
+
Many messages these packages show to authors, administrators and operators ended with an issue-tracker
17
+
number where the reason belonged. The number goes, and where the sentence did not already say what was
18
+
decided, it now does. Where an ADR stood beside the number, the ADR stays.
19
+
20
+
- Refusals and prescriptions: the retired health-check keys, the `IMetadataService.register` refusals
21
+
(the contract refuses loudly and names the mismatch, never coerces a value into storability), the
22
+
kernel's plugin-ordering errors (registration order is not a contract), the in-memory and MongoDB
23
+
filter and aggregation refusals, formula's empty field constraint, the retired `artifact-api`
24
+
source, and the by-id update and delete refusals. The MongoDB retired-aggregate refusal now says the
25
+
function left `AggregationFunction` because no SQL backend compiled it; its undeclared-aggregate
26
+
refusal says the builder used to sum an unrecognised name before this refusal existed.
27
+
- The `findOne` no-predicate refusal loses its citation in `objectql` and in `metadata-core`'s
28
+
`engineFindOnePredicateRefusalMessage` together, so the two still read byte for byte the same.
29
+
- The in-memory and MongoDB drivers' multi-tenancy refusals (`MEMORY_MULTI_TENANT_UNSUPPORTED`,
30
+
`MONGODB_MULTI_TENANT_UNSUPPORTED`) no longer end with a `Tracking:` line linking a tracker card;
31
+
the sentence above it already says the driver refuses rather than run or answer unisolated.
32
+
- Field help and protection text: the `sys_account` token help (and its es-ES, ja-JP and zh-CN
33
+
translations), the `sys_email` headers help and the SCIM credential store's protection reason.
34
+
- Log lines: the superseded-registration warning, the authz cache posture line, the endpoint matcher's
35
+
excluded-item error, the metadata history and loader-read failure errors, and the fresh-datastore
36
+
attestation info lines.
37
+
38
+
Text only: no error code, field name, status or behaviour changes.
fix(service-analytics)!: every analytics face answers the engine's field-level read refusal, whichever strategy serves the cube: a field the caller may not read is judged before either strategy runs (#20917)
6
+
7
+
Clause-②: yes (narrowing)
8
+
9
+
<!-- adr-0087: not-required (no-migration-prescription) No authorable key, export or stored shape is removed or renamed. The change refuses analytics queries that read a field the caller's field-level permissions hide, which the engine already refuses on the data API and on the ObjectQL strategy, so there is nothing for `objectstack migrate meta` to rewrite. The one public-surface addition is a new optional service hook. -->
10
+
11
+
**BREAKING for analytics queries on a SQL deployment that read a field the caller may not read.**
The field form offers `useGrouping` on `number` fields: one plain boolean row beside `scale`, gated to `number` as `scale` is, whose control copies the field form's `allowCreate` row (the same `z.boolean().optional()` node, no default). The key was declared by `FieldSchema` and graded `live` by the liveness ledger once the console's number display began to answer an authored value first, but no form offered it, so an author's only door was the Source tab. The help text follows the key's own description: unset lets the renderer decide, off never groups (a year or an ID), on always groups. It also says that an untouched switch writes nothing, so it reads off even where the renderer groups.
9
+
10
+
⛔ **No schema accept set moves and no export changes.** What changes is the **form payload**`getMetaTypes()` serves and the translation keys `os i18n extract` walks, hence the regenerated `platform-objects` metadata-form bundles, whose two new leaves are authored in `zh-CN`, `ja-JP` and `es-ES` rather than left as extractor fills.
The import row report and the validate-only answer can now say which fields a write drops. `ImportRowResultSchema` and each `ValidateDataResponseSchema.results[]` row gain an optional `droppedFields`: an array of `DroppedFieldsEventSchema`, the engine's own strip event. So the reason vocabulary is the engine's (`readonly`, `readonly_when`, `primary_key`, `computed`), and there is no second enum. The row still succeeds: `ok`, `action` and `valid` are unchanged. The key is declared ahead of its producer. A server that does not produce the report omits the key, so an absent key alone does not prove nothing was dropped.
6
+
7
+
`ImportRowResultSchema` also declares `warnings`, which the REST import dry run already serves: the findings the validate verdict admits, in the `ValidateDataIssue` shape, on an ok dry-run row. Until now `ImportRowResultSchema.parse` stripped the key, and readers typed by the spec could not see it.
8
+
9
+
`ImportJobResultsSchema.results` now says what an async reader gets: a capped sample, failures first. An ok row's `droppedFields` or `warnings` reaches that reader only if the row falls inside the sample. The cap is unchanged.
10
+
11
+
A consumer that branches on `reason` must stay exhaustive over `DroppedFieldsEvent['reason']`. The known exhaustive consumer is objectui's write-warning toast table, `STRIPPED_LINE` in `packages/app-shell/src/providers/writeWarningToast.ts`, which covers all four reasons today. A reader that renders the import or preview report should word `reason` through that table rather than a second one. When the union widens again, the table keyed by it fails type-check on the missing reason, while a second table would fall behind without a sound.
|**results**|`{ row: integer; ok: boolean; action: Enum<'created' \| 'updated' \| 'skipped' \| 'failed'>; id?: string; … }[]`| ✅ | Capped sample of per-row outcomes, failures first. An ok row, and any `droppedFields` or `warnings` it carries, reaches this reader only if it falls inside the sample; `resultsTruncated` says whether the sample is partial, and the job counters count every row.|
219
219
|**resultsTruncated**|`boolean`| ✅ | Whether `results` is a capped sample of a larger set |
|**warnings**|`{ field: string; code: string; message: string }[]`| optional | Findings this deployment ADMITS rather than rejects (ADR-0104 value shapes under a warn-first posture), in the same `{ field, code, message }` shape the validate verdict carries. Set only on a dry-run row the verdict accepted: the row is `ok` because the write would store it and log the same complaint. A committed row never carries it, since the write path has no channel to report admitted findings on. |
233
+
|**droppedFields**|`{ object: string; fields: string[]; reason: Enum<'readonly' \| 'readonly_when' \| 'primary_key' \| 'computed'> }[]`| optional | Write-observability: caller-supplied fields the engine LEGALLY strips from THIS row, one event per reason, in the engine's own `droppedFields` shape and reason vocabulary. A dry-run row reports the strips the write would make; a committed row reports the strips it made. The row still succeeds: `ok` and `action` are unchanged. Present only when at least one field was dropped. A server that does not produce this report omits the key too, so an absent key alone does not prove nothing was dropped. In an async job's `results`, an ok row's drops reach the reader only if the row falls inside that capped, failures-first sample. |
|**warnings**|`{ field: string; code: string; message: string }[]`| optional | Findings this deployment ADMITS rather than rejects (ADR-0104 value shapes under a warn-first posture), in the same `{ field, code, message }` shape the validate verdict carries. Set only on a dry-run row the verdict accepted: the row is `ok` because the write would store it and log the same complaint. A committed row never carries it, since the write path has no channel to report admitted findings on. |
361
+
|**droppedFields**|`{ object: string; fields: string[]; reason: Enum<'readonly' \| 'readonly_when' \| 'primary_key' \| 'computed'> }[]`| optional | Write-observability: caller-supplied fields the engine LEGALLY strips from THIS row, one event per reason, in the engine's own `droppedFields` shape and reason vocabulary. A dry-run row reports the strips the write would make; a committed row reports the strips it made. The row still succeeds: `ok` and `action` are unchanged. Present only when at least one field was dropped. A server that does not produce this report omits the key too, so an absent key alone does not prove nothing was dropped. In an async job's `results`, an ok row's drops reach the reader only if the row falls inside that capped, failures-first sample. |
|**warnings**|`{ field: string; code: string; message: string }[]`| optional | Findings this deployment ADMITS rather than rejects (ADR-0104 value shapes under a warn-first posture), in the same `{ field, code, message }` shape the validate verdict carries. Set only on a dry-run row the verdict accepted: the row is `ok` because the write would store it and log the same complaint. A committed row never carries it, since the write path has no channel to report admitted findings on. |
380
+
|**droppedFields**|`{ object: string; fields: string[]; reason: Enum<'readonly' \| 'readonly_when' \| 'primary_key' \| 'computed'> }[]`| optional | Write-observability: caller-supplied fields the engine LEGALLY strips from THIS row, one event per reason, in the engine's own `droppedFields` shape and reason vocabulary. A dry-run row reports the strips the write would make; a committed row reports the strips it made. The row still succeeds: `ok` and `action` are unchanged. Present only when at least one field was dropped. A server that does not produce this report omits the key too, so an absent key alone does not prove nothing was dropped. In an async job's `results`, an ok row's drops reach the reader only if the row falls inside that capped, failures-first sample. |
|**fields**|`string[]`| ✅ | Caller-supplied field names the engine removed from the write payload |
398
+
|**reason**|`Enum<'readonly' \| 'readonly_when' \| 'primary_key' \| 'computed'>`| ✅ | Why the fields were dropped: static readonly, a TRUE readonlyWhen predicate, the primary-key strip of a payload id the engine ruled is not an identifier, or a computed (formula) field no driver has a column for |
|**posture**|`{ valueShapeStrict: boolean; mediaValueShapeStrict: boolean }`| ✅ | The ADR-0104 posture the verdict was reached under — reported because it is the difference between "this row is fine" and "this row is fine HERE". The same row can be an error on a self-certified deployment and an admitted warning on an un-migrated one, and a caller explaining a verdict needs to know which it got. An unconditionally-strict preview was considered and rejected (option B): it would fail rows on every un-migrated deployment that the write would have accepted. |
@@ -2987,6 +2987,7 @@ A write-path strip event: caller-supplied fields legally dropped from the payloa
2987
2987
|**valid**|`boolean`| ✅ | True when this row would be accepted by the write path. |
2988
2988
|**errors**|`{ field: string; code: string; message: string }[]`| ✅ | Findings that would REJECT this row. Empty when valid. |
2989
2989
|**warnings**|`{ field: string; code: string; message: string }[]`| ✅ | Findings the target deployment ADMITS rather than rejects — today, ADR-0104 value shapes under a warn-first posture. The row is valid; the write would store it and log the same complaint. |
2990
+
|**droppedFields**|`{ object: string; fields: string[]; reason: Enum<'readonly' \| 'readonly_when' \| 'primary_key' \| 'computed'> }[]`| optional | Write-observability for the preview: caller-supplied fields the write would LEGALLY strip from THIS row, one event per reason, in the shape and reason vocabulary the write itself reports. A strip is not a finding: `valid` is unaffected, and the fields appear in neither `errors` nor `warnings`. Present only when at least one field would be dropped. A server that does not produce this report omits the key too, so an absent key alone does not prove nothing would be dropped. |
0 commit comments