Found while writing the Data Modeling import-mappings page (epic #10206, card #10213). Filed unassigned for domain:spec triage; not fixed there, per that card's non-goals.
The shape
ImportFieldMappingSchema.params in packages/spec/src/data/mapping.zod.ts declares four keys whose only stated purpose is to steer the lookup transform:
object — "Lookup Object"fromField — "Match on (e.g. name)"toField — "Value to take (e.g. id)"autoCreate — "Create if missing"
They also carry a full alias set (lookupObject/targetObject, match/matchOn/matchField/keyField, returnField/valueField, create/createIfMissing/upsert), so an author who reaches for any of eight other spellings is actively routed onto them.
Nothing reads them
The only consumer of a mapping artifact is the import path. In packages/rest/src/import-mapping.ts, applyMappingToRows handles lookup in the same branch as none:
case'none':
case'lookup': {// lookup values resolve downstream via metaMapmapped[first(entry.target)]=row[first(entry.source)];break;}Reference resolution happens afterwards in import-coerce.ts, driven by the target object's own field metadata (buildFieldMetaMap), never by these keys. Grepping the repo for fromField and autoCreate outside mapping.zod.ts and its own tests returns only unrelated identifiers (sql-driver.tsuniqueIndexesFromFields, tenant.zod.tsautoCreateSchema/autoCreateDatabase).
The liveness ledger already records this, as a sub-walk boundary under fieldMapping rather than as a verdict of its own — packages/spec/liveness/mapping.json:
SUB-WALK BOUNDARY, recorded not hidden: params' lookup-specific keys (object/fromField/toField/autoCreate) are read by nothing — reference resolution comes from the target object's own field definitions, not from these — and they sit one level below the drill, so only this note governs them.
So the state is known and deliberately parked, not undiscovered. What it does not have is an ADR-0049 enforce-or-remove disposition.
Why it is worth a decision rather than a note
params is a strictObject, so it rejects a misspelling loudly — which makes these four the opposite case: they are accepted loudly. An author writing params: { object: 'account', fromField: 'name', autoCreate: true } gets a clean parse, a clean defineStack() build, and an import that silently ignores every one of them. autoCreate is the one with teeth: it reads as "create the referenced record when the name does not match", and what actually happens is that the row fails with an unresolved-reference error.
Options
- Remove the four keys under ADR-0049 (with the alias entries converted to
guidance so the eight spellings land on a prescription rather than a "did you mean"). Matches how extractQuery / errorPolicy / batchSize left the same schema in 17.0.0. - Implement them in
applyMappingToRows — a per-entry lookup resolution that overrides the object-metadata default. This is a second reference-resolution dialect on the import path, which is what the existing comment declines to build.
Option 1 looks right from here, but it is domain:spec's call.
Impact on docs
content/docs/data-modeling/import-mappings.mdx (card #10213) documents the lookup transform as a pass-through and carries an explicit warning that these four params are not read, pointing at this issue. That warning should be deleted along with the keys if option 1 lands.
Generated by Claude Code
Found while writing the Data Modeling import-mappings page (epic #10206, card #10213). Filed unassigned for
domain:spectriage; not fixed there, per that card's non-goals.The shape
ImportFieldMappingSchema.paramsinpackages/spec/src/data/mapping.zod.tsdeclares four keys whose only stated purpose is to steer thelookuptransform:object— "Lookup Object"fromField— "Match on (e.g. name)"toField— "Value to take (e.g. id)"autoCreate— "Create if missing"They also carry a full alias set (
lookupObject/targetObject,match/matchOn/matchField/keyField,returnField/valueField,create/createIfMissing/upsert), so an author who reaches for any of eight other spellings is actively routed onto them.Nothing reads them
The only consumer of a mapping artifact is the import path. In
packages/rest/src/import-mapping.ts,applyMappingToRowshandleslookupin the same branch asnone:Reference resolution happens afterwards in
import-coerce.ts, driven by the target object's own field metadata (buildFieldMetaMap), never by these keys. Grepping the repo forfromFieldandautoCreateoutsidemapping.zod.tsand its own tests returns only unrelated identifiers (sql-driver.tsuniqueIndexesFromFields,tenant.zod.tsautoCreateSchema/autoCreateDatabase).The liveness ledger already records this, as a sub-walk boundary under
fieldMappingrather than as a verdict of its own —packages/spec/liveness/mapping.json:So the state is known and deliberately parked, not undiscovered. What it does not have is an ADR-0049 enforce-or-remove disposition.
Why it is worth a decision rather than a note
paramsis astrictObject, so it rejects a misspelling loudly — which makes these four the opposite case: they are accepted loudly. An author writingparams: { object: 'account', fromField: 'name', autoCreate: true }gets a clean parse, a cleandefineStack()build, and an import that silently ignores every one of them.autoCreateis the one with teeth: it reads as "create the referenced record when the name does not match", and what actually happens is that the row fails with an unresolved-reference error.Options
guidanceso the eight spellings land on a prescription rather than a "did you mean"). Matches howextractQuery/errorPolicy/batchSizeleft the same schema in 17.0.0.applyMappingToRows— a per-entry lookup resolution that overrides the object-metadata default. This is a second reference-resolution dialect on the import path, which is what the existing comment declines to build.Option 1 looks right from here, but it is
domain:spec's call.Impact on docs
content/docs/data-modeling/import-mappings.mdx(card #10213) documents thelookuptransform as a pass-through and carries an explicit warning that these four params are not read, pointing at this issue. That warning should be deleted along with the keys if option 1 lands.Generated by Claude Code