Repository navigation
Description
director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8
Ruled: 6486145005 · letter B · 2026-10-29T02:26Z
Filing gate ② (a decision only the maintainer can make), filed on the maintainer's instruction in this session, 2026-10-28, verbatim: 「你说的问题立决策卡,挂在专题下面」. It follows the re-assessment of #27261 against the connector survey behind #26702.
Placement. Epic: #27261 (parent; pm:epic subtree). Filed by session_01J8VVAmeQhJepVXSad145da. ⛔ Not a claim. No domain:* label: triage sets it, and domain:spec is expected because the answer decides whether D2's keys exist.
维护者速读
- 一句话问题: 声明式档上线后,客户用无代码方式绑定一个 ERP 或 HR 系统的列表。如果平台没法把筛选和排序交给对方系统去做,超过 1000 行的列表就会被拒收。[Decision] Ontology over external systems: virtual objects on ADR-0015 federation — two driver tiers (plugin code · declarative OpenAPI), pushdown/identity/catalog/cache rules, Studio and AI drafts (2026 ontology research + deep design) #27261 把声明式档定成 OpenAPI。但 OpenAPI 只描述"有哪些参数",不描述"怎么筛选"。主流平台在这一档用的是 OData:Salesforce Connect 和 Dataverse 都内置 OData 适配器,都没有 OpenAPI 适配器。
- 谁撞上(实测): 今天没有人。P2 要等第二个客户(D1)。这张卡是"P2 立卡前先定方言"。
- 选项:
- A 维持 OpenAPI(D2 的两个键照加)。
- B OData 优先:筛选、排序、分页能完整下推,
$metadata直接生成对象草稿,不需要 D2 的两个新键。OpenAPI 只在拉动方系统不支持 OData 时再做。 - C 到拉动时按对方协议二选一。
- 推荐 B。 置信缺口:国内 ERP/HR(金蝶、用友等)是否支持 OData 没有核实。
- 工作量: A 约 L + S,还要补
connector-openapi已实测的四个解析缺口。B 约 L,没有新对象键。C 是 A 和 B 的上界。时机都随 P2。 - 请回:
A / B / C
Background
-
[Decision] Ontology over external systems: virtual objects on ADR-0015 federation — two driver tiers (plugin code · declarative OpenAPI), pushdown/identity/catalog/cache rules, Studio and AI drafts (2026 ontology research + deep design) #27261 Tier B (ruling 6471382887, D1/D2) is one platform driver,
openapi. An object binds throughobject.external.operations { list, get, create?, update?, delete? }(operationIds) plusobject.external.idField. Pushdown is "declared per object: filterable / sortable / pageable fields". Everything else is applied in memory under a 1,000-row cap that refuses loudly. D2 placed the two keys; D1 gated all of Tier B on a second customer pull. -
What mainstream operational platforms ship for the same capability:
- Salesforce Connect external data sources take the adapter values
OData(2.0),OData4,SfdcOrg(cross-org), a custom Apex adapter (Apex Connector Framework),AmazonAthenaandAmazonDynamoDB. - Dataverse virtual tables ship an OData v4 provider installed by default, custom provider plug-ins, and the virtual connector provider.
- Neither ships an OpenAPI adapter. The end state is "OData declaratively, custom code for the rest", which maps onto Tier B (OData) plus Tier A (plugin driver).
- Salesforce Connect external data sources take the adapter values
-
Why the dialect decides pushdown.
- OData standardises the query (
$filter,$orderby,$top,$skip,$count,$select) and publishes the model ($metadata: entity sets, keys, types, navigation properties). A driver can mapDriverQueryonto it generically, sosupportsclaims nearly everything and the row cap rarely bites. - OpenAPI describes parameters, not their semantics. Mainstream SaaS list endpoints use bespoke query forms: SOQL, JQL, HubSpot's POST search body, Stripe's
created[gte]with cursor paging. Pushdown therefore has to be authored by hand per object and per operator, or it falls to memory and the cap. - Measured on
microsoft/PowerPlatformConnectorsat2bb74ad3: of 1,170 parsable Swagger definitions, 18 carryx-ms-pageable. Even vendor-annotated specs rarely declare paging semantics.
- OData standardises the query (
-
OData fits the existing binding.
- The entity set is
object.external.remoteName. - The key comes from
$metadata, soidFieldis not needed. - The operations are implied by the protocol, so
operationsis not needed. $metadatafeedsgenerateObjectDraftfor D6's import flow.
- The entity set is
-
Measured gaps in the
connector-openapiparsing that P2 plans to reuse:- Swagger 2.0 is refused as a fatal config fault, so the document must be converted offline.
- Parameters given as
$refare skipped; the caller must pre-dereference. - Request bodies are JSON only.
- YAML is not accepted.
- The ADR-0023 CLI follow-up is unbuilt.
Under A these are P2 work, and they are shared with connectors.
Governing text
- Ruling 6471382887 on [Decision] Ontology over external systems: virtual objects on ADR-0015 federation — two driver tiers (plugin code · declarative OpenAPI), pushdown/identity/catalog/cache rules, Studio and AI drafts (2026 ontology research + deep design) #27261: D1 (Tier B gated on the second pull), D2 (
object.external.operations+idField). This card asks to amend D2's premise, that Tier B is OpenAPI. - ADR-0015 §3.1: one Object shape, external is a property of the binding. Re-check:
git grep -n "remoteName" origin/main -- packages/spec/src/data/object.zod.ts. - ADR-0023 (OpenAPI → connector generator) status line: the CLI is pending. Re-check:
git grep -n "CLI + examples pending" origin/main -- docs/adr/0023-openapi-to-connector-generator.md.
Protocol statement.
- A:
Metadata-protocol: added, two optional object keys (as D2) plus theopenapidriver config contract. - B: no new object key. The
odatadriver's own config contract is added (service root URL, version, credential per the sibling credential card). - C: either, decided at the pull.
Premises (read at origin/main e9c88f7c)
- Swagger 2.0 refused. Re-check:
git grep -n "a Swagger 2.0 document" origin/main -- packages/connectors/connector-openapi/src/openapi-provider.ts. $refparameters skipped. Re-check:git grep -n "'\$ref' in p" origin/main -- packages/connectors/connector-openapi/src/openapi-connector.ts.- JSON-only bodies. Re-check:
git grep -n "JSON.stringify(input.body)" origin/main -- packages/connectors/connector-openapi/src/openapi-connector.ts. - No YAML. Re-check:
git grep -n -i yaml origin/main -- packages/connectors/connector-openapi/srcanswers nothing. - The
x-ms-pageablecount: a census ofmicrosoft/PowerPlatformConnectorsat2bb74ad3(1,197 folders, 1,166 with parsable JSON, Swagger 2.0 throughout). It is outside this repository; the method was a JSON walk counting connectors whose definition carries the extension.
Options
| Option | What it does | What the customer sees | Effort |
|---|---|---|---|
| A OpenAPI (as designed) | driver-openapi; D2's two keys; pushdown declared per object field; parsing upgrades in connector-openapi (2.0 conversion, $ref, YAML, non-JSON bodies) |
Any spec'd REST API is bindable. Large lists work only where the author declared the filters. | spec S + server L + parsing M (not measured) · precedent: connector-openapi (ADR-0023) |
| B OData first | driver-odata (v4; v2 when a pull needs it); $metadata import; no new object keys; OpenAPI only on a pull from a non-OData source |
SAP S/4HANA, SuccessFactors and Dynamics-class sources bind with full filtering and paging. Spec-only REST APIs wait for Tier A code or a later OpenAPI pull. | server L + ui M (import) · no precedent |
| C per pull | At the second pull, read the source's protocol and file A's or B's children | The same as whichever is chosen | the upper bound of A and B |
In business terms. A: a universal plug that fits every socket loosely, so heavy loads slip. B: the industry-standard plug, which fits standard sockets exactly and leaves the rest for now. C: buy the plug when you see the socket.
四维分析(业务立场)
- 项目长远合理性(领起)。 两年后的样子:外部业务系统的数据以对象的形式被无代码绑定,筛选、排序、分页由源系统执行,大列表照常可用;标准协议的源零代码,非标准的源写一个代码档 driver。Salesforce Connect(OData 2.0/4.0 + Apex 自定义适配器)和 Dataverse(OData v4 provider + 自定义 provider)都是这个终态。B 直接到达,而且用现有的
remoteName就能表达绑定。A 把声明式档建在一个不描述查询语义的格式上,下推能力只能靠作者逐对象逐字段手写,规模一上来就撞行上限。 - 实际业务拉动。 今天零拉动,Tier B 本来就等第二个客户(D1)。D1 说的目标是 ERP / HR / MES 的无代码接入,这一类里 SAP、SuccessFactors、Dynamics 原生支持 OData;国内系统是否支持未核实,这是本推荐最大的盲区。所以只定方言优先级,实施随拉动。
- 防 AI 犯错。 B 的查询语义由协议定义,AI 只写实体集名,没有可以写错的下推声明;
$metadata漂移在启动时可检测。A 让 AI 为每个对象手写"哪些字段可筛选、映射到哪个参数",写错时要么静默不下推(列表变慢,最终撞上限被拒),要么映射到错误参数而返回错误的行。后者在引擎兜底之外,最危险。 - 创业阶段不扩散。 B 不加对象键,D2 的两个键不再需要;A 加两个键,外加一份解析升级。C 推迟决定,但 P2 立卡时还要再裁一次。
os-decision-facets
- ① 项目长远合理性:B 是 Salesforce Connect 与 Dataverse 的同形终态(OData 声明式 + 自定义代码),用现有
remoteName表达;A 建在不描述查询语义的格式上,下推靠手写。 - ② 实际业务拉动:今天零拉动(D1 等第二个客户);目标类 ERP/HR 里的 SAP / SuccessFactors / Dynamics 原生 OData,国内系统未核实。
- ③ 防 AI 犯错:B 的查询语义由协议给定、无手写下推声明;A 的手写映射写错会返回错误的行,在引擎兜底之外。
- ④ 创业阶段不扩散:B 零新对象键;A 两个键加解析升级;C 推迟但要再裁一次。
Prior rulings read: "OData datasource driver external objects" → 9 hits, none on a declarative dialect (#27279 open, P1 Studio marking; the rest closed ADR-0015 door fixes); ruling 6471382887 D1 / D2; ADR-0015 §3.1; ADR-0023 status; thread: none.
Recommendation
- B. A is not taken: it fixes the format before knowing whether its queries can be pushed down. C is not taken: it defers the same question to the pull and still needs a ruling then.
- 只看①选 B;②③④ 是否翻转:否(② 只决定时机:仍随第二个客户)。
- Confidence gap:
- The second customer's source protocol is unknown. If it is a domestic ERP / HR / MES without OData, B's first deliverable does not serve it, and either a Tier A driver or an OpenAPI pull is needed.
- OData v2 versus v4 coverage was not measured.
- The Salesforce Connect and Dataverse readings come from search summaries of their public docs, not from pages fetched in this session.
After the ruling
- B: the epic PM amends [Decision] Ontology over external systems: virtual objects on ADR-0015 federation — two driver tiers (plugin code · declarative OpenAPI), pushdown/identity/catalog/cache rules, Studio and AI drafts (2026 ontology research + deep design) #27261's body: Tier B reads "declarative OData, OpenAPI on a non-OData pull". D2's keys are not filed. P2's children on the pull become
driver-odata(server L), the$metadataimport (ui M) and the guide section (devx S). - A: P2 stands as designed. A
connector-openapiparsing card (Swagger 2.0,$ref, YAML, non-JSON bodies) joins P2's children, shared with the connector lane. - C: P2's first child on the pull is a protocol reading of the source. A's or B's children follow from it.
Related
#27261 (epic) · ruling 6471382887 · #27130 · ADR-0015 · ADR-0023 · #26702 (the connector survey) · and the sibling decision card on datasource credentials, filed alongside this one.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 29, 2026
director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8
Brief-claimed-by: session_01Utp6CbQLcy8yg6vhJVXXi8 · batch #426 · 2026-10-29T02:15Z
Director seat, summon #54 (ledger objectstack#12708, opening mark 6485456694). Presented to the maintainer in batch #426 as item 2 of 3, together with #27298 and #27302.
Seat increment (re-read at
origin/main73725c20, 2026-10-29T02:15Z):$refparameters skipped (openapi-connector.ts L295); JSON-only bodies (L195);yaml0 hits underconnector-openapi/src;remoteNameis the object binding's table name (object.zod.ts L1344–1346); ADR-0023 status still "CLI + examples pending". Added:odataappears in 23 files underpackages/spec/srcalready (the query-transport vocabulary), so the word is not new to the contract.check-prior-rulings.mjs --card 27299names ADR-0076 D9, ADR-0023 §4, ADR-0080 §3, ADR-0027 §12, ADR-0059 §3, ADR-0062 D5 — term matches, none chooses a declarative dialect for external datasources. Thread: [Decision] Ontology over external systems: virtual objects on ADR-0015 federation — two driver tiers (plugin code · declarative OpenAPI), pushdown/identity/catalog/cache rules, Studio and AI drafts (2026 ontology research + deep design) #27261 ruling 6471382887 D1 (Tier B filed on the second pull) and D2 (object.external.operations+idField), whose premise — Tier B is OpenAPI — is what this card asks to amend. The epic body §4 and its P2 row still say OpenAPI anddriver-openapi.remoteNamebinding already expresses it; OpenAPI describes parameters, not query semantics, so pushdown would be hand-authored per object and the 1,000-row cap would bite on every large list. ② the pull is still zero (D1); the card's own blind spot is the one that matters for timing: the first no-code customer may bring a domestic ERP / HR system (金蝶、用友、北森 and the like) whose OData support is unverified — under B that customer waits for a Tier A driver or an OpenAPI pull. ③ B leaves the author nothing to get wrong in pushdown; A's hand-written filter maps can return wrong rows outside the engine's fallback. ④ B files no new object key; D2's two keys are then not filed.$metadataimport, no new object keys; OpenAPI only on a pull from a non-OData source. Not A (fixes a format before knowing whether its queries push down), not C (the same ruling again at the pull, with P2's children unfiled until then). Nothing is dispatched now.domain:serverdriver-odataL +domain:ui$metadataimport M +domain:devxguide S · at P2 · no precedent (A would be spec S + server L + parsing M on top ofconnector-openapi). Confidence gaps kept from the card: the second customer's protocol; OData v2 versus v4 coverage; the Salesforce / Dataverse readings come from public documentation summaries, not pages fetched in this session.pm:epic.Prior rulings read: OData, OpenAPI, declarative, datasource, pushdown, remoteName → ADR-0015 §3.1, ADR-0023; thread: 6471382887 D1 / D2 (#27261); repo: objectstack-ai/objectstack
objectstack-fleet commentedon Oct 29, 2026
director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8
Ruling: batch #426 item 2 · letter B · maintainer 「同意」 2026-10-29T02:23Z
Director seat, summon #54 (ledger objectstack#12708, opening mark 6485456694, brief 6486027050). The maintainer answered batch #426 in the summon chat with one word, verbatim: 「同意」 — the seat's letter on each of the three cards; for this card B.
What the ruling binds (letter B — OData first): #27261's Tier B is a declarative OData datasource driver (v4; v2 when a pull needs it), not OpenAPI. The object binding is the existing
object.external.remoteName(the entity set); the key comes from$metadata, the operations are implied by the protocol, so D2's two keys (object.external.operations,object.external.idField) are not filed.$metadatafeedsgenerateObjectDraftfor D6's import. Filtering, sorting, paging and$countpush down generically; whateversupportsdoes not claim stays under the engine's in-memory fallback and row cap (standing rule of 6471382887). OpenAPI returns only on a pull from a source that has no OData endpoint, as its own card; an OAuth-protected or non-OData source meanwhile takes a Tier A plugin driver. D1 stands: Tier B's children are filed on the second customer pull, not now. Not taken: A (fixes the format before its queries are known to push down; hand-written filter maps can return wrong rows), C (the same ruling again at the pull).Governing text: ruling 6471382887 D1 / D2 (D2's premise amended here); ADR-0015 §3.1 (one Object shape, external is a property of the binding); ADR-0023 (
connector-openapistays the connector-side parser, untouched by this ruling). Premises re-read atorigin/main73725c20(brief 6486027050).Workload of the letter:
domain:serverdriver-odataL +domain:ui$metadataimport M +domain:devxguide S · filed with P2 on the second customer pull · no precedent. Recorded blind spot for P2's filing: the second customer's protocol (a domestic ERP / HR / MES without OData takes a Tier A driver or an OpenAPI pull); OData v2 versus v4 coverage unmeasured.Execution: nothing is dispatched. The epic PM of #27261 amends the epic body — Tier B reads "declarative OData; OpenAPI on a non-OData pull", the P2 row's children become
driver-odata,$metadataimport and the guide section, D2's keys struck — and this card closescompletedin this act (the ruling is its content; P2's children cite this comment on aRuling-ref:line when filed).os-decision-facets
① 长远:Salesforce Connect 与 Dataverse 的同形终态(OData 声明式 + 自定义代码档),现有
remoteName即可表达② 拉动:今天零(D1 等第二个客户);国内 ERP/HR 的 OData 支持未核实,是记录在案的盲区
③ 防错:查询语义由协议给定,AI 无可写错的下推声明;A 的手写映射会返回错误的行
④ 不扩散:零新对象键,D2 的两个键不再立
objectstack-fleet commentedon Oct 29, 2026
director#1 · os-bill · session_01Utp6CbQLcy8yg6vhJVXXi8
Closed
completed· 2026-10-29T02:30Z · ruling 6486145005 (batch #426 item 2, letter B: Tier B is a declarative OData driver, OpenAPI only on a non-OData pull, D2's two keys not filed). The epic PM amends #27261's Tier B wording and P2 row (pointer left there); P2's children cite the ruling when filed.needs-user-decisionleaves with the close;pm:epicstays.