Skip to content

feat(analytics): analytics over federated objects honors the remote table (ADR-0062 Phase 3, D6)#2200

Merged
os-zhuang merged 4 commits into
feat/adr-0062-credentials-p2from
feat/adr-0062-analytics-external-p3
Jun 22, 2026
Merged

feat(analytics): analytics over federated objects honors the remote table (ADR-0062 Phase 3, D6)#2200
os-zhuang merged 4 commits into
feat/adr-0062-credentials-p2from
feat/adr-0062-analytics-external-p3

Conversation

@xuyushun441-sys

Copy link
Copy Markdown
Contributor

ADR-0062 Phase 3 — native-analytics SQL over external objects (D6)

Stacked on #2199 (Phase 2) → #2198 (Phase 1). Merge those first; this PR's base is the Phase 2 branch.

Analytics over a federated object now aggregates against the correct remote table instead of silently querying the wrong one.

Problem

NativeSQLStrategy hand-compiles FROM "<object>" and bare column references. These bypass the driver's physical-table resolution (external.remoteName / remoteSchema / columnMap), so for a federated object whose object name ≠ remote table it queries the wrong table (or errors).

Fix (reuse the driver's resolution — don't re-implement it)

A native-SQL fast path for external objects (exposing physicalTableFor/physicalColumnFor on the driver) and deeper columnMap-in-GROUP BY support are noted as follow-ups in the ADR.

Tests

  • 4 unit tests on canHandle: declines external base object, declines external joined object, accepts managed object, no-hook legacy path unchanged. Full service-analytics suite green (147).

Closes (partially) #2163 — Phase 3.

🤖 Generated with Claude Code

os-zhuang and others added 4 commits June 22, 2026 19:12
… (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>
@vercel

vercel Bot commented Jun 22, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Ready Ready Preview, Comment Jun 22, 2026 11:36am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/m labels Jun 22, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): packages/services, @objectstack/spec.

91 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/cloud-artifact-api.mdx (via packages/spec)
  • content/docs/concepts/cluster-semantics.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/implementation-status.mdx (via @objectstack/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/concepts/packages.mdx (via @objectstack/spec)
  • content/docs/concepts/setup-app.mdx (via @objectstack/spec)
  • content/docs/concepts/skills.mdx (via @objectstack/spec)
  • content/docs/concepts/webhook-delivery.mdx (via @objectstack/spec)
  • content/docs/getting-started/architecture.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/spec)
  • content/docs/getting-started/core-concepts.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/guides/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/guides/ai-capabilities.mdx (via @objectstack/spec)
  • content/docs/guides/airtable-dashboard-analysis.mdx (via @objectstack/spec)
  • content/docs/guides/analytics-datasets.mdx (via @objectstack/spec)
  • content/docs/guides/api-reference.mdx (via @objectstack/spec)
  • content/docs/guides/business-logic.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/error-catalog.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-type-gallery.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/field-validation-rules.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/protocol-diagram.mdx (via packages/spec)
  • content/docs/guides/cheatsheets/query-cheat-sheet.mdx (via @objectstack/spec)
  • content/docs/guides/cheatsheets/quick-reference.mdx (via @objectstack/spec)
  • content/docs/guides/client-sdk.mdx (via @objectstack/spec)
  • content/docs/guides/common-patterns.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/auth-service.mdx (via packages/spec)
  • content/docs/guides/contracts/cache-service.mdx (via packages/spec)
  • content/docs/guides/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/index.mdx (via @objectstack/spec)
  • content/docs/guides/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/guides/contracts/storage-service.mdx (via packages/spec)
  • content/docs/guides/data-modeling.mdx (via @objectstack/spec)
  • content/docs/guides/deployment-vercel.mdx (via @objectstack/spec)
  • content/docs/guides/driver-configuration.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/guides/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/guides/formula.mdx (via @objectstack/spec)
  • content/docs/guides/hook-bodies.mdx (via packages/spec)
  • content/docs/guides/kernel-services.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/dashboard.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/field.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/flow.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/index.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/object.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/validation.mdx (via @objectstack/spec)
  • content/docs/guides/metadata/workflow.mdx (via @objectstack/spec)
  • content/docs/guides/packages.mdx (via packages/services, @objectstack/spec)
  • content/docs/guides/plugin-development.mdx (via @objectstack/spec)
  • content/docs/guides/plugins.mdx (via @objectstack/spec)
  • content/docs/guides/project-scoping.mdx (via @objectstack/spec)
  • content/docs/guides/public-forms.mdx (via @objectstack/spec)
  • content/docs/guides/runtime-services/audit-service.mdx (via packages/services)
  • content/docs/guides/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/index.mdx (via packages/services, packages/spec)
  • content/docs/guides/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/settings-service.mdx (via packages/services)
  • content/docs/guides/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/guides/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/guides/security.mdx (via @objectstack/spec)
  • content/docs/guides/seed-data.mdx (via @objectstack/spec)
  • content/docs/guides/skills.mdx (via @objectstack/spec)
  • content/docs/guides/standards.mdx (via @objectstack/spec)
  • content/docs/guides/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/i18n-standard.mdx (via packages/services, @objectstack/spec)
  • content/docs/protocol/objectos/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/plugin-spec.mdx (via @objectstack/spec)
  • content/docs/protocol/objectos/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via packages/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/feat/adr-0062-credentials-p2 → pass the list as args.docs.

@xuyushun441-sys
xuyushun441-sys force-pushed the feat/adr-0062-credentials-p2 branch from 688a28b to 9911bc2 Compare June 22, 2026 12:18
@os-zhuang
os-zhuang merged commit 8f9203f into feat/adr-0062-credentials-p2 Jun 22, 2026
7 checks passed
@os-zhuang
os-zhuang deleted the feat/adr-0062-analytics-external-p3 branch 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants