Uh oh!
There was an error while loading. Please reload this page.
feat(spec): IDataEngine datasource-def contract catches up to the engine — external.credentialsRef accepted, listDatasourceDefs declared - #12949
Conversation
…ine — external.credentialsRef accepted, listDatasourceDefs declared Part of #12805 (report and regenerated artifacts follow). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4
…sourceDef; add changeset Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4
…tasource-contract-catchup
📓 Docs Drift CheckThis PR changes 1 package(s): 12 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 126 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 86bfd8ea369f6fddd15e480004a58937d0fd0b13 && git checkout 86bfd8ea369f6fddd15e480004a58937d0fd0b13
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 8beb3deaf6755311ed6ef88dcce4b5dcbebbdac3 6c7577623edd7c8d3eb44b6341df2fa28721fd6b && git checkout -B drift-repro 8beb3deaf6755311ed6ef88dcce4b5dcbebbdac3 && git merge --no-ff 6c7577623edd7c8d3eb44b6341df2fa28721fd6b
node scripts/docs-audit/affected-docs.mjs --json 8beb3deaf6755311ed6ef88dcce4b5dcbebbdac3
|
Patch round on #12414/PR #12899: CI flagged check:export-origins STALE on ai.json/kernel.json/root.json/ui.json -- the seven re-exports this branch adds regenerated api-surface but not the sibling export-origins artifact when the branch was first merged with origin/main (the #12949 precedent this diff follows regenerates both). Root cause, precisely: merging origin/main (which had since landed #12718, retiring PreviewModeConfig) picked up main's source changes but the two GENERATED artifacts derived from that merged source were never rebuilt -- kernel.json's api-surface still listed the retired PreviewModeConfig/PreviewModeConfigParsed/PreviewModeConfigSchema, and export-origins hadn't gained entries for this branch's seven new re-exports at all. Fix: pnpm --filter @objectstack/spec build (fresh dist reflecting both this branch's re-exports and #12718's retirement), then gen:export-origins + gen:api-surface. Read the resulting diff per the gate's own #4411 dual-source-trap remedy: each of the seven names' newly-gained export-origins entry was cross-checked against its origin on every sibling entry that already carried it (root vs /system vs /ui, kernel vs /data, /ai and /ui vs /data and /automation) -- all match byte-for-byte, so this is the harmless re-export shape, never dual-source. kernel.json's api-surface diff is exactly the PreviewModeConfig removal #12718 made; nothing from this branch's own repair moved. Verified: check:export-origins, check:dual-source-exports and check:generated (14/14 generated artifacts) all green on the merged + rebuilt tree. Part of #12414 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LpRNHxWZgSUgVnFT9mQQo4
Uh oh!
There was an error while loading. Please reload this page.
Fixes#12805
What
The published
IDataEnginecontract catches up to declared-and-enforced engine reality (#12758 remains the engine-side change this follows):registerDatasourceDefnow acceptsexternal.credentialsRef— the secrets-store handleObjectQLhas accepted and retained since WidenregisterDatasourceDefto retainexternal.credentialsRef, so the sys_secret reference union can answer family 3 without the caller — schedule BEFORE #8103's deletion half #12758. Before this, a caller typed against the published contract was refused with TS2353 at the consumer seam for a value the runtime keeps.listDatasourceDefsreturningEngineDatasourceDef[]— the read-back of the same registry, the fourth datasource-lifecycle member under the 2026-08-25 finding: two consumer-local structuralDataEngineLikere-declarations remain after the #11493 deletion (datasource-admin-plugin, service-analytics) #11833 ruling's item-4 precedent (which adjudicated the first three onto this contract in the change for IDataEngine contract adoption ruled by #11833: declare resolveEffectiveDatasource + getDriverForObject (optional members), and give getObject a real return contract #12248).EngineDatasourceDefinterface. Both stay OPTIONAL — only engines that own a datasource registry answer.Regenerated artifacts:
api-surface/contracts.jsonandexport-origins/contracts.json(one added line each: the new interface). Changeset:minorfor@objectstack/spec, following the additive-public-surface precedent (root-entry-nameability-data-delta.md).Judgment calls (the three the triage grading named)
listDatasourceDefslands onIDataEngine, notIObjectQLEngine— follows the ruling's item-4 precedent rather than reopening it. The member meets the same evidence bar as the three already there: implemented onObjectQL(engine.ts,listDatasourceDefs, shipped by WidenregisterDatasourceDefto retainexternal.credentialsRef, so the sys_secret reference union can answer family 3 without the caller — schedule BEFORE #8103's deletion half #12758), cross-package pull exists (Wire the sys_secret reference union to self-serve family 3 from ObjectQL.listDatasourceDefs(), and correct the three prose sites #12758 falsified #12804 is the consumer: asys_secretreference sweep must ask the engine which code-declared datasources hold a handle, since code-declared datasources never reach the metadata store), and without the declared member that consumer must name the engine class concretely or re-declare a consumer-local structural type — the pattern the finding: two consumer-local structuralDataEngineLikere-declarations remain after the #11493 deletion (datasource-admin-plugin, service-analytics) #11833 sweep retired. Optionality preserved: same population asregisterDatasourceDef("only engines that own a datasource registry answer"). My measurement agrees with the precedent; no fork to report.EngineDatasourceDefin the contract file, used by BOTH the parameter and the return element — not two inline literals. Evidence: the engine itself namesDatasourceDefbecause "three copies of one shape is a second de-facto contract that drifts silently" (engine.ts docblock); at the contract level two members now share the shape, and an unnamed element type would push Wire the sys_secret reference union to self-serve family 3 from ObjectQL.listDatasourceDefs(), and correct the three prose sites #12758 falsified #12804's sweep back into indexed-access gymnastics or a consumer-local structural re-declaration — the exact retired pattern. The name follows the contract's existing Engine-prefixed family (EngineQueryOptions,EngineUpdateOptions). It is deliberately NOT namedDatasourceDef:@objectstack/objectqlexports a structurally identical type of that name which this contract cannot import (dependency direction); the distinct name keeps the two declarations tellable apart until the engine converges on the contract's. The keys mirror exactly what the engine retains (name,schemaMode,external.allowWrites,external.credentialsRef) — a deliberate SUBSET ofExternalDatasourceSettingsSchema, not invention (its docblock says so and forbids growing it).credentialsRef; the existing name-required negative stays; a NEW negative pins that the widening admits exactly the ruled key (an inlinecredentialskey is still refused) — matching the block's own both-directions convention (themarkDatasourceUnavailablekind-union case). New cases pin: all FOUR members optional; register parameter and list return share ONE declaration (mutual-extends againstEngineDatasourceDef); the Wire the sys_secret reference union to self-serve family 3 from ObjectQL.listDatasourceDefs(), and correct the three prose sites #12758 falsified #12804 sweep expressible through the data-slot contract type alone; implementations answering nameless or inline-credential defs refused.Verification — the consumer seam, both directions
The engine's typecheck is green either way (method-parameter bivariance), so it is NOT offered as proof — it was run as corroboration only (
@objectstack/objectqltypecheck exit 0;datasource-def-credentials-ref.test.ts9/9 passed).The proof is a compile probe typed against the published contract (resolved through the package exports map to the built
distdeclarations), run at both endpoints:external.credentialsRefpassed throughregisterDatasourceDefon anIDataEngine-typed value →error TS2353: 'credentialsRef' does not exist in type '{ allowWrites?: boolean | undefined; }'. Probe B —listDatasourceDefscalled through the data-slot contract type →error TS2551: Property 'listDatasourceDefs' does not exist on type 'IDataEngine'.credentialskey →error TS2561 … does not exist in type '{ allowWrites?: boolean | undefined; credentialsRef?: string | undefined; }'— the printed target type itself names the widened member.Spec tree at the probe head is byte-identical to this PR's final head (the merge with current main brought no
packages/spec/srcchange), so the probe evidence stands at6c7577623.Gates (local, at final head 6c75776)
pnpm --filter @objectstack/spec build·typecheck(incl.check:test-typecheck: OK) · targeted vitestsrc/contracts/data-engine.test.ts+src/contracts/core-service-contracts.test.ts: 2 files, 39 tests passed. Both edited files confirmed inside the compiled tsc programs via listFiles (the new expect-error pins are live, not phantom).check:generated: 2 artifacts proved stale (api-surface, export-origins), regenerated with--fix, re-checked clean.scripts/pm/dispatch-gates.mjs(no hand-fed paths) and run:check:authorable-surfacecheck:docscheck:livenesscheck:strictness-ledgercheck:empty-statecheck:variant-docscheck:skill-refscheck:exported-anycheck:dual-source-exportscheck:doc-authoringcheck:spec-parsed-aliascheck:changeset-gate-self-testscheck:cross-package-test-inputscheck:merge-drivercheck:objectql-double-limitcheck:page-declaration-shapecheck:published-filescheck:slot-lookupcheck:test-source-aliascheck:type-source-resolutioncheck:query-options-erasurecheck:engine-double-contractcheck:where-matchercheck:objectui-changesetcheck:pm-half-statescheck:type-check-coveragecheck:nul-bytescheck:dev-prereqscheck:doc-formula-expressionscheck:type-check-debt(--re-measure verdict: "31 ledger entries re-measured … none above its recorded number") plus the adr-0087 / changeset-no-major / empty-changeset / ci-filter-parity / comment-mask-adoption / plugin-teardown-shape / release-rehearsal-clone self-test node scripts — all exit 0, statuses captured before any pipe.scripts/pm/check-half-states.mjsexits 3 (no GitHub credential in this container — its own output states "no reading at all"; a board patrol, not a tree gate).Scope notes
registerDatasourceDefto retainexternal.credentialsRef, so the sys_secret reference union can answer family 3 without the caller — schedule BEFORE #8103's deletion half #12758 remains the engine-side change; finding: two consumer-local structuralDataEngineLikere-declarations remain after the #11493 deletion (datasource-admin-plugin, service-analytics) #11833's analytics half stays with the services seat. This PR touches exactly: the contract file, its pin test, the two regenerated artifacts, one changeset.Generated by Claude Code
Generated by Claude Code