|
| 1 | +--- |
| 2 | +"@objectstack/spec": minor |
| 3 | +"@objectstack/rest": minor |
| 4 | +"@objectstack/lint": minor |
| 5 | +--- |
| 6 | + |
| 7 | +fix(rest,lint): an import mapping target that names no field is refused on the dry run, on the commit and at `objectstack validate` alike (#20150) |
| 8 | + |
| 9 | +Clause-②: yes |
| 10 | + |
| 11 | +<!-- adr-0087: not-required (no-migration-prescription) Nothing authorable is renamed, retired or re-typed: `ImportFieldMappingSchema.target` keeps its declared shape and meaning ("Target object field(s)"), no stored mapping or record moves, and every mapping parses byte-identically to before. What narrows is the ACCEPT SET of the import door and of the published author-time checker, and only for mappings whose target already names no field of the object: those failed every row on the commit before this change, so no import that wrote anything is refused now. The remedy is per mapping and the refusal names it in full (the mapping, the target, its position and the object); there is no stored representation for `objectstack migrate meta` to rewrite. --> |
| 12 | + |
| 13 | +**BREAKING** in the accept-set sense only, landing in the launch window as |
| 14 | +`minor`: the import route and `objectstack validate` now refuse a mapping they |
| 15 | +used to pass, and every such mapping already failed on the commit. |
| 16 | + |
| 17 | +**What was wrong.** `ImportFieldMappingSchema.target` is declared as "Target |
| 18 | +object field(s)", and nothing held a mapping to it. A mapping whose target named |
| 19 | +no field of its `targetObject` (measured with `mailing_address.street` on an |
| 20 | +object whose address field is `mailing_address`): |
| 21 | + |
| 22 | +- passed `objectstack validate`, `os lint` and `os build` with no diagnostic; |
| 23 | +- answered `ok` for every row on `POST /api/v1/data/:object/import` with |
| 24 | + `dryRun: true`; |
| 25 | +- then failed every row on the commit with `INVALID_FIELD` ("Unknown field |
| 26 | + 'mailing_address.street' on object '…'"). |
| 27 | + |
| 28 | +The dry run promised what the commit refused. |
| 29 | + |
| 30 | +**What changes.** |
| 31 | + |
| 32 | +- `@objectstack/spec` exports ONE verdict on what a target may name, beside the |
| 33 | + schema it judges: `unknownImportMappingTargets(fieldMapping, objectDef)`, with |
| 34 | + `indexImportMappingTargets`, `judgeImportMappingTarget`, |
| 35 | + `importMappingEntryTargets` and `IMPORT_TARGET_ALWAYS_ADDRESSABLE_COLUMNS` |
| 36 | + (from `@objectstack/spec/data`). A target may name a declared field, a column |
| 37 | + the platform provisions on that object (`resolveInjectedSystemColumns`), or one |
| 38 | + of `id` / `created_at` / `updated_at`, which the engine's write door admits on |
| 39 | + every object. An object with no readable, non-empty field map is not judged. |
| 40 | +- `@objectstack/rest`: `prepareImportRequest` refuses a named mapping (`mappingName`) |
| 41 | + with a target that names no field, before any row, with `400 INVALID_FIELD` — |
| 42 | + the code the commit's per-row refusal already carried. The dry run and the |
| 43 | + commit give the same answer, and so does the async import-job route. |
| 44 | +- `@objectstack/lint`: the reference-integrity suite (`os validate`, `os lint`, |
| 45 | + `os build`) gains `validateMappingTargetFields`, rule id |
| 46 | + `mapping-target-field-unknown` (`MAPPING_TARGET_FIELD_UNKNOWN`), severity |
| 47 | + `error`, located at `mappings[i].fieldMapping[j].target`. It asks the same |
| 48 | + spec verdict, so it never refuses a target the import door accepts. |
| 49 | + |
| 50 | +**What to do.** Point each reported target at a field the object declares. An |
| 51 | +array target (`split`) is judged element by element. |
0 commit comments