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
External object-draft renders a field key that is not authorable: fields.<f>.primaryKey fails tsc against ServiceObject and ObjectSchema.safeParse #11000
Found while working #10676. This is the reason that card could not be discharged as written, so it is filed as its own defect — it exists today, independently of #10676, and is reachable without any change to the tree.
What
ExternalDatasourceService.generateObjectDraft emits, and renderObjectSource renders, a field-level primaryKey: true:
primaryKey is not a key of the spec field schema. The rendered *.object.ts is annotated ServiceObject, so the generated source does not compile, and the definition does not parse.
Measured at 368e7a06f
tsc --noEmit over the rendered draft, with a no-primaryKey copy of the same file in the same program as a positive control:
with-pk.ts(8,25): error TS2353: Object literal may only specify known properties,
and 'primaryKey' does not exist in type '{ type: "number" | ... ; externalId?: boolean | undefined; }'.
without-pk.ts produced no diagnostic — so the program is live and the clean result is meaningful.
ObjectSchema.safeParse on the same two definitions:
This is not hypothetical and does not depend on #10676. generateObjectDraft already emits the key whenever the caller passes the primaryKey option — the path POST /object-draft { "primaryKey": [...] } and os datasource introspect --primary-key take — and the existing suite pins that output (external-datasource-service.test.ts asserts both { type: 'text', primaryKey: true } in definition.fields and "order_id: { type: 'text', primaryKey: true }" in source). So the generator has a pinned path that produces a draft the platform's own validator and compiler both refuse.
It is usually invisible only because the introspected default never fires — which is precisely the bug #10676 reports.
The open question
There is currently no authorable place for a federated object's remote primary key:
not on the field — primaryKey is unrecognized, as measured above;
not on the binding — ObjectExternalBindingSchema is a strictObject whose keys are remoteName, remoteSchema, writable, columnMap, introspectedAt, ignoreColumns. No key holds a primary key.
FieldSchema does declare externalId: z.boolean().default(false) — "Is external ID for upsert operations" — which is semantically adjacent (the card #10676 describes the lost value as "the addressing/upsert key"). Routing the introspected primary key there would need no spec change. But it is a different concept, it maps badly onto a composite key, and a scan of non-test, non-dist TypeScript under packages/ turned up no site that reads a field'sexternalId property at all — the externalId hits are SCIM, the batch API, and the seed/mapping upsertKey aliases, which take a field name at the dataset level, not this boolean. So it may itself be declared-but-unenforced (ADR-0049 territory) and is not obviously a safe destination.
Three candidate repairs, none of which a dev should pick unilaterally:
B. Emit fields.<f>.externalId — no spec change, draft stays compilable, but overloads a key with different stated semantics that may itself have no enforcing consumer.
C. Add an authorable spelling for a remote key (e.g. external.primaryKey: string[] on ObjectExternalBindingSchema) — contract-first, handles composite keys naturally, declared = enforced; but it is a packages/spec change and adds surface, which wants a maintainer ruling on whether anything consumes a federated primary key at runtime today.
Related: #10712 (the same generated draft also fails os build on the missing ${namespace}_ prefix and absent sharingModel), #10676 (the seam that keeps the key from ever reaching the draft).
Filed unassigned as a finding awaiting first-touch grading. Discovered from #10676.
Found while working #10676. This is the reason that card could not be discharged as written, so it is filed as its own defect — it exists today, independently of #10676, and is reachable without any change to the tree.
What
ExternalDatasourceService.generateObjectDraftemits, andrenderObjectSourcerenders, a field-levelprimaryKey: true:primaryKeyis not a key of the spec field schema. The rendered*.object.tsis annotatedServiceObject, so the generated source does not compile, and the definition does not parse.Measured at
368e7a06ftsc --noEmitover the rendered draft, with a no-primaryKeycopy of the same file in the same program as a positive control:without-pk.tsproduced no diagnostic — so the program is live and the clean result is meaningful.ObjectSchema.safeParseon the same two definitions:successfields.id.primaryKey: truefalseunrecognized_keys,path: ["fields","id"], keys["primaryKey"]trueReachable today
This is not hypothetical and does not depend on #10676.
generateObjectDraftalready emits the key whenever the caller passes theprimaryKeyoption — the pathPOST /object-draft { "primaryKey": [...] }andos datasource introspect --primary-keytake — and the existing suite pins that output (external-datasource-service.test.tsasserts both{ type: 'text', primaryKey: true }indefinition.fieldsand"order_id: { type: 'text', primaryKey: true }"insource). So the generator has a pinned path that produces a draft the platform's own validator and compiler both refuse.It is usually invisible only because the introspected default never fires — which is precisely the bug #10676 reports.
The open question
There is currently no authorable place for a federated object's remote primary key:
primaryKeyis unrecognized, as measured above;ObjectExternalBindingSchemais astrictObjectwhose keys areremoteName,remoteSchema,writable,columnMap,introspectedAt,ignoreColumns. No key holds a primary key.FieldSchemadoes declareexternalId: z.boolean().default(false)— "Is external ID for upsert operations" — which is semantically adjacent (the card #10676 describes the lost value as "the addressing/upsert key"). Routing the introspected primary key there would need no spec change. But it is a different concept, it maps badly onto a composite key, and a scan of non-test, non-distTypeScript underpackages/turned up no site that reads a field'sexternalIdproperty at all — theexternalIdhits are SCIM, the batch API, and the seed/mappingupsertKeyaliases, which take a field name at the dataset level, not this boolean. So it may itself be declared-but-unenforced (ADR-0049 territory) and is not obviously a safe destination.Three candidate repairs, none of which a dev should pick unilaterally:
fields.<f>.primaryKeyanyway — no spec change, but ships codegen output that failstscandObjectSchemaby default. Adds a third reason on top of [finding] External object-draft output failsos buildas generated — object name lacks the${namespace}_prefix and nosharingModelis emitted #10712's two for why the draft does not build.fields.<f>.externalId— no spec change, draft stays compilable, but overloads a key with different stated semantics that may itself have no enforcing consumer.external.primaryKey: string[]onObjectExternalBindingSchema) — contract-first, handles composite keys naturally,declared = enforced; but it is apackages/specchange and adds surface, which wants a maintainer ruling on whether anything consumes a federated primary key at runtime today.Related: #10712 (the same generated draft also fails
os buildon the missing${namespace}_prefix and absentsharingModel), #10676 (the seam that keeps the key from ever reaching the draft).Filed unassigned as a finding awaiting first-touch grading. Discovered from #10676.