feat(datasource): reject field.columnName on external + drop showcase onEnable bridge (ADR-0062 Phase 4, D7/D8)#2203
Merged
os-zhuang merged 5 commits intoJun 22, 2026
Conversation
… (ADR-0062 Phase 1) Declare an external datasource → it auto-connects to a live ObjectQL driver and its federated objects are queryable with ZERO app code (no onEnable). Implements ADR-0062 Phase 1 (D1/D2/D5) toward epic #2163. D1 — one connect path: new DatasourceConnectionService owns the single "definition → live driver" path (factory build → credentialsRef resolve → connect → registerDriver under the datasource name → registerDatasourceDef → DDL-free syncObjectSchema per bound object). The runtime-admin registerPool now delegates to it; AppPlugin auto-connects code-defined datasources. Exposed as the 'datasource-connection' kernel service. D2 — opt-in-safe gate: connect only when external, an object explicitly binds via object.datasource, or autoConnect:true. Managed datasources referenced only by a datasourceMapping rule (e.g. app-crm's :memory: datasources) stay metadata-only — existing apps byte-for-byte unchanged. Adds datasource.autoConnect to the spec. D5 — lifecycle/ordering/policy: connect in AppPlugin.start() before the kernel:ready validation gate (init-all-then-start-all). Fail-fast for declared external + onMismatch:'fail'; degrade otherwise (always for runtime-admin/ rehydrate). New host-injectable DatasourceConnectPolicy (open-core default allows; multi-tenant host binds a stricter fail-closed policy) consulted before connect. Tests: 15 connection-service unit tests + 5 runtime integration tests (auto-connect, managed-unrouted stays metadata-only, queryable end-to-end, deny policy). onEnable + ctx.drivers.register remains a supported, idempotent escape hatch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…TS build)
The context logger interface types error(message, error?: Error) — passing a meta
object {appId, error} tripped the tsup DTS build (TS2353) even though tsc --noEmit
passed. Switch to a single interpolated message; the rethrow still surfaces the
real cause to the kernel.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…062 Phase 2, D3) A declared external.credentialsRef MUST resolve to a cleartext secret before the driver is built — an absent secret store or an unresolvable/undecryptable ref now fails closed (clear message, datasource left unconnected) instead of silently building a driver without the credential. Follows the same fail-fast (declared external + onMismatch:fail) vs degrade policy as connect failures. Converges with the runtime-admin secret path (same SecretBinder threaded through the shared connection service). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ADR-0062 Phase 3, D6) NativeSQLStrategy hand-compiles FROM/columns that bypass the driver's physical resolution (remoteName/remoteSchema/columnMap), so it would aggregate against the wrong table for a federated object. It now declines any query whose base or joined object is external (new optional StrategyContext.isExternalObject hook, reported by the analytics plugin from the object's external block), routing it to the ObjectQLStrategy whose engine.aggregate goes through the driver's getBuilder (#2138/#2149). Reuses the driver's resolution rather than re-implementing it; until a native-SQL fast path exists, external analytics is correct (via ObjectQL) instead of silently wrong. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…owcase onEnable bridge (ADR-0062 Phase 4) D7: os compile/build (validateStackExpressions) rejects field.columnName on a federated object — external.columnMap is authoritative; managed objects untouched. D8: examples/app-showcase declares its external datasource with NO onEnable driver registration; the declared datasource auto-connects (D1). onEnable now only provisions the remote fixture tables. The @objectstack/verify harness wires the datasource-admin plugin (→ datasource-connection service) when an app declares datasources, mirroring os dev/serve, so a new dogfood test exercises the federated read end-to-end (incl. remoteName remap + filter pushdown). onEnable + ctx.drivers.register stays supported as the dynamic-driver escape hatch. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
📓 Docs Drift CheckThis PR changes 3 package(s): 15 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
Base automatically changed from
feat/adr-0062-analytics-external-p3
to
feat/adr-0062-credentials-p2
June 22, 2026 12:20
xuyushun441-sys
added a commit
that referenced
this pull request
Jun 22, 2026
…062 Phase 2, D3) (#2199) * feat(datasource): fail-closed credential resolution at connect (ADR-0062 Phase 2, D3) A declared external.credentialsRef MUST resolve to a cleartext secret before the driver is built — an absent secret store or an unresolvable/undecryptable ref now fails closed (clear message, datasource left unconnected) instead of silently building a driver without the credential. Follows the same fail-fast (declared external + onMismatch:fail) vs degrade policy as connect failures. Converges with the runtime-admin secret path (same SecretBinder threaded through the shared connection service). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(analytics): analytics over federated objects honors the remote table (ADR-0062 Phase 3, D6) (#2200) * feat(datasource): reject field.columnName on external + drop showcase onEnable bridge (ADR-0062 Phase 4, D7/D8) (#2203) --------- Co-authored-by: Jack Zhuang <277994282+os-zhuang@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ADR-0062 Phase 4 — reconciliation + cleanup (D7, D8)
Stacked on #2200 (Phase 3) → #2199 → #2198. Merge those first.
D7 —
columnMapis authoritative; rejectfield.columnNameon external objectsos compile/build(validateStackExpressions) now errors when a federated object (one declaring anexternalbinding) has a field withcolumnName. The driver's query pipeline does not applyfield.columnNamefor external objects —external.columnMap(remoteColumn → localField) is the single source of truth — so allowing both is a silent dual-source ambiguity. The error message points toexternal.columnMap. Managed objects are untouched.D8 — drop the
onEnabledriver bridge from the canonical exampleexamples/app-showcasenow declares its external datasource with noonEnabledriver registration.onEnableonly provisions the "remote" fixture tables; the declared datasource auto-connects at boot (Phase 1, D1).onEnable+ctx.drivers.registerstays documented as the escape hatch for drivers built dynamically at runtime.To cover this end-to-end in the dogfood gate, the
@objectstack/verifyharness now wires the datasource-admin plugin (registering'datasource-connection') when an app declares datasources — so the harness mirrorsobjectstack dev/serve. Previously the harness imported only an app's default export, soonEnablenever ran there and external objects were never read; now auto-connect handles the driver and a new dogfood test reads the federated objects through the real REST stack.Tests / validation
clivalidate-expressions suite green (29).showcase-external-autoconnect.dogfood.test.ts— readsshowcase_ext_customer/_order(incl.remoteNameremapcustomers/orders+?region=EUpushdown), with noonEnabledriver wiring. ✅objectstack verify --app examples/app-showcase --rls✅ and--app examples/app-crm --rls✅ (D2 gate keeps app-crm metadata-only — byte-for-byte unchanged under the harness change).Closes #2163 — Phase 4 (final functional phase; the
default-driver bootstrap refactor is the remaining standalone follow-up).🤖 Generated with Claude Code