Skip to content

IDataEngine.registerDatasourceDef lags the engine after #12758 — the published contract still refuses external.credentialsRef, and listDatasourceDefs is absent #12805

Description

@claude

Filed unassigned by the os-dev seat implementing #12758, session session_01LZbWd2jNV1FErXTPSS4Dry. ⛔ Not graded, not routed. #12758's dispatch fenced packages/spec out of that card as the spec seat's surface, so this is filed rather than edited.

Blocked-by: #12758 (describes the surface that card creates).

Measured on the #12758 branch

packages/spec/src/contracts/data-engine.ts:359 declares the datasource-registration member on IDataEngine:

  registerDatasourceDef?(def: {
    name: string;
    schemaMode?: string;
    external?: { allowWrites?: boolean };
  }): void;

ObjectQL (which implements IObjectQLEngine extends IDataEngine) now accepts external.credentialsRef on the same call, and answers a new listDatasourceDefs(). Two consequences:

  1. A host typed against the published contract still cannot pass the reference. ObjectQL satisfies the interface — method parameters are bivariant, so a wider implementation parameter type-checks, and the Widen registerDatasourceDef to retain external.credentialsRef, so the sys_secret reference union can answer family 3 without the caller — schedule BEFORE #8103's deletion half #12758 branch's pnpm --filter @objectstack/objectql typecheck is green on exactly that. But a caller holding an IDataEngine (the 'data' slot contract) gets the NARROW parameter, so a fresh literal with credentialsRef is refused with TS2353 at that seam even though the runtime accepts and retains it. That is the same defect Widen registerDatasourceDef to retain external.credentialsRef, so the sys_secret reference union can answer family 3 without the caller — schedule BEFORE #8103's deletion half #12758 fixed, one layer up.
  2. listDatasourceDefs is not on the contract at all. Any consumer that wants the engine to answer "which code-declared datasources hold a sys_secret handle" (see the follow-up filed alongside this one) must either name ObjectQL concretely or re-declare the member in a consumer-local structural type — the very pattern the finding: two consumer-local structural DataEngineLike re-declarations remain after the #11493 deletion (datasource-admin-plugin, service-analytics) #11833 sweep exists to retire and which the 2026-08-25 ruling's item 4 adjudicated onto this contract for the three datasource-lifecycle members already there.

⚠️ Note the shape is NOT invention: credentialsRef: z.string().optional() is declared on ExternalDatasourceSettingsSchema (packages/spec/src/data/datasource.zod.ts:319) and is valid in every schemaMode per #8153. The contract file is the one place that has not caught up.

What a taker has to decide (this is why it is filed, not fixed)

⛔ Not a mechanical copy of the widening. IDataEngine's members are OPTIONAL by design — "only engines that own a datasource registry answer" — and packages/spec/src/contracts/data-engine.test.ts:512 pins the accepted set of registerDatasourceDef in both directions. Adding a member and widening a parameter on a published contract needs the spec seat's judgement on:

  • whether listDatasourceDefs earns a place on IDataEngine at all, or belongs on the narrower IObjectQLEngine;
  • what the return element type is on the contract side, given @objectstack/objectql now exports DatasourceDef and the contract cannot import from a package that depends on it;
  • whether the pin test grows the positive case or gains a negative one.

Re-check

git show origin/main:packages/spec/src/contracts/data-engine.ts | sed -n '355,365p'
git grep -n "listDatasourceDefs" -- packages/spec/src
git grep -n "credentialsRef" -- packages/spec/src/data/datasource.zod.ts

⛔ The listDatasourceDefs zero above is a finding only against the credentialsRef positive control in the same tree (21 hits in datasource.zod.ts alone) — a zero with no control is "did not read", not "does not exist".

Duplicate check

Covered by the same targeted search_issues round as the sibling filing (the repo-scoped REST search endpoint is 403 from this seat; channel switch declared). Control fired — #12758 returned at rank 1. Nine matches reviewed, only #12758 open, no open card covers the contract lag. ⚠️ Not exhaustively deduped outside the datasource/secrets neighbourhood.


Generated by Claude Code


Generated by Claude Code

Metadata

Metadata

Assignees

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions