docs(platform): align connector, EDP, and deploy canon
This commit is contained in:
@@ -1,274 +1,238 @@
|
||||
# ADR: L2-owned external connectors and provider-neutral Data Plane
|
||||
# ADR: внешние коннекторы принадлежат NDC L2 workflow
|
||||
|
||||
Статус: **accepted**.
|
||||
Дата: 2026-07-14.
|
||||
Дата: 2026-07-16.
|
||||
Владелец решения: NODE.DC Platform.
|
||||
|
||||
## Контекст
|
||||
|
||||
NODE.DC — платформа разработки. Подключение внешнего API не должно создавать
|
||||
ещё один provider-specific сервис, в котором навсегда зашиты логика клиента,
|
||||
нормализация и правила отображения. Иначе каждый новый account или новый тип
|
||||
объекта превращается в изменение Platform runtime.
|
||||
NODE.DC состоит из двух разных слоёв:
|
||||
|
||||
Нужна одна повторяемая форма: Platform даёт безопасные границы, контракт
|
||||
хранения и выдачи данных; изолированный workflow NDC Agent L2 является
|
||||
адаптером конкретного API и остаётся редактируемым через предоставленный
|
||||
Codex/Engine MCP.
|
||||
- платформенный слой даёт NDC L1, NDC L2, Ontology, credentials, Data Products
|
||||
и Foundry-boundaries;
|
||||
- пользовательские автоматизации собирают из этих возможностей конкретную
|
||||
бизнес-логику.
|
||||
|
||||
Это решение заменяет provider-adapter часть
|
||||
`ADR_EXTERNAL_PROVIDER_DATA_PLANE.md` и все provider-specific runtime
|
||||
предписания `ADR_GELIOS_DATA_PLANE.md`. Они сохраняются как исторические
|
||||
черновики, но не являются каноном для новой реализации.
|
||||
Новый account, provider credential, tenant, расписание или интерфейс не должны создавать
|
||||
новый platform service и не должны требовать изменения NODE.DC source. Команда
|
||||
NODE.DC подключается только для нового поставщика либо для расширения
|
||||
подтверждённых capabilities и ontology уже поддержанного поставщика.
|
||||
|
||||
Gelios — первый живой источник и acceptance-кейс этого канона, а не отдельная
|
||||
архитектурная ветка. Документ заменяет provider-runtime решения из
|
||||
`ADR_EXTERNAL_PROVIDER_DATA_PLANE.md` и `ADR_GELIOS_DATA_PLANE.md`; те
|
||||
документы остаются только историей решения.
|
||||
|
||||
## Решение
|
||||
|
||||
### 1. Адаптер внешнего API принадлежит L2
|
||||
### 1. Пакет поставщика создаётся один раз
|
||||
|
||||
Один изолированный L2 workflow представляет одно connection instance и
|
||||
является единственным местом для:
|
||||
Каждый поддержанный поставщик получает один версионируемый **provider package**.
|
||||
Он является знанием платформы о внешнем API и содержит:
|
||||
|
||||
- обращения к API поставщика через ссылку на credential из Engine;
|
||||
- выбора read-capability, cursor/pagination, rate limit, retry и расписания;
|
||||
- получения raw envelope, разбиения большого ответа на native batch-операции;
|
||||
- семантического mapping к версии ontology и формирования canonical facts;
|
||||
- idempotency key, watermark и lifecycle источника;
|
||||
- deploy/run/execution/trace через Engine MCP.
|
||||
- стабильный `providerId` и версии подтверждённого API;
|
||||
- credential contract без значения секрета;
|
||||
- каталог safe-read capabilities, pagination/rate-limit metadata и response
|
||||
shapes;
|
||||
- mappings из provider fields в версии Ontology;
|
||||
- совместимые Data Products и scrubbed contract fixtures;
|
||||
- явно отделённый каталог команд без активного command transport.
|
||||
|
||||
L2 не хранит значение provider secret или writer token: он использует только
|
||||
Engine-bound credential references. Plaintext writer token выдаётся trusted
|
||||
provisioner ровно один раз при create/rotate binding и затем хранится только в
|
||||
Engine credential store, привязанном к этому L2; External Data Plane хранит
|
||||
лишь его hash. Provisioner читает отдельный runner-owned secret file, который
|
||||
read-only монтируется только в EDP и позднее в dedicated Engine provisioner,
|
||||
работающий под выделенным UID/GID `11006`; это не shared `.env`, не
|
||||
`NODEDC_INTERNAL_ACCESS_TOKEN` и не provider credential. До deployment этого
|
||||
provisioner `EXTERNAL_DATA_PLANE_PROVISIONING_ENABLED=false`, поэтому issuance
|
||||
routes fail closed. Token не попадает в L2 graph/profile, contract artifact,
|
||||
execution log/trace, raw envelope, Foundry или UI. Command/write-capabilities
|
||||
не получают transport route в read workflow.
|
||||
Пакет не является runtime service, scheduler, базой данных или customer
|
||||
configuration. Он расширяется только когда фактически подтверждён новый API,
|
||||
новый тип данных или новая ontology revision.
|
||||
|
||||
Для новой учётной записи создаётся новый instance/profile этого workflow с
|
||||
другой credential reference и connection configuration. Это не требует
|
||||
изменения Platform source. Если поставщик раскрывает новый объект или поле,
|
||||
сначала расширяется ontology/capability contract, затем изменяется именно
|
||||
соответствующий L2 workflow.
|
||||
Одна учётная запись поставщика задаётся данными, а не кодом:
|
||||
|
||||
### 2. Platform Data Plane нейтрален к provider и домену
|
||||
`provider package + credential reference + connection profile + NDC L2 workflow instance`
|
||||
|
||||
Platform предоставляет один versioned **External Data Plane**. Он принимает
|
||||
batch по внутреннему аутентифицированному контракту, хранит raw envelope с
|
||||
retention/provenance, canonical facts, current/history projections и отдаёт
|
||||
scoped data products/realtime updates. В нём запрещены:
|
||||
Поэтому второй account или другая provider credential pair создаёт ещё один credential/profile и
|
||||
workflow instance. Платформенный source, Data Plane и Foundry при этом не
|
||||
меняются.
|
||||
|
||||
- ветвления по названию provider, customer, account, vehicle или renderer;
|
||||
- provider field mapping, unit allowlist, business filtering и visual rules;
|
||||
- provider token, прямой browser-to-provider доступ и command transport.
|
||||
### 2. NDC L1 проектирует, NDC L2 workflow исполняет
|
||||
|
||||
Его canonical write-форма, которую Data Plane валидирует и сохраняет после
|
||||
авторизации, содержит только нейтральные элементы:
|
||||
NDC L1 получает пользовательское намерение, проверяет доступные capabilities и
|
||||
Ontology, проектирует или изменяет разрешённый NDC L2 workflow через NDC MCP и
|
||||
анализирует execution evidence.
|
||||
|
||||
```text
|
||||
source: providerId + tenantId + connectionId
|
||||
contract: contractVersion + ontologyRevision + dataProductId
|
||||
batch: runId + sequence + idempotencyKey + receivedAt
|
||||
raw: optional restricted ref + contentType + hash + retention policy
|
||||
facts: stable sourceId + semanticType + observedAt + attributes + geometry?
|
||||
```
|
||||
Один изолированный NDC L2 workflow представляет один connection instance и
|
||||
владеет исполняемой механикой:
|
||||
|
||||
Для нового L2 writer-а это не wire-форма. Он вызывает
|
||||
`POST /internal/data-plane/v1/data-products/:dataProductId/publish` с bearer
|
||||
writer token и формой `nodedc.data-product.publish/v1`, в которой вообще нет
|
||||
`source`, contract metadata, transport или persistence policy. Любой caller
|
||||
scope и scope headers запрещены.
|
||||
- safe-read вызовами provider API через credential reference;
|
||||
- pagination, cursor, retry, rate limit, batch size и collection cadence;
|
||||
- проверкой response shape и разбиением ответа на items;
|
||||
- mapping к точной ontology revision;
|
||||
- idempotency, watermark и публикацией canonical facts;
|
||||
- private workflow state, когда он действительно нужен.
|
||||
|
||||
External Data Plane разрешает token в собственный immutable writer binding
|
||||
`(tenantId, connectionId, providerId, allowedDataProductIds, expiresAt)`,
|
||||
проверяет active/non-expired binding, совпадение `providerId` и разрешение
|
||||
`dataProductId`, затем сам materializes canonical `source` с tenant/connection
|
||||
и только после этого валидирует и сохраняет batch. Присланный caller scope
|
||||
отклоняется, а не merge/override-ится. Изменение tenant, connection, provider,
|
||||
allowed data products или срока требует нового binding; для существующего
|
||||
binding допустимы только token rotation и revoke.
|
||||
Provider-specific mapping сначала реализуется штатными workflow nodes и малым
|
||||
Code-преобразователем. Это позволяет проверить реальный API без преждевременного
|
||||
создания custom nodes. В custom NDC nodes переносится только повторившаяся и
|
||||
доказанная **платформенная boundary-механика**, а не уникальная логика
|
||||
поставщика.
|
||||
|
||||
Выпуск, rotation и revoke binding принимаются только от dedicated provisioning
|
||||
principal с runner-owned secret file; он не монтируется в shared `.env` или L2.
|
||||
Shared legacy bearer не может создавать writer capability.
|
||||
### 3. Credentials являются данными connection instance
|
||||
|
||||
Идентификатор источника стабилен в пределах `(providerId, connectionId,
|
||||
sourceId)`. Отсутствие объекта в очередном ответе помечается lifecycle-state
|
||||
или временем последнего наблюдения; запись и её история не удаляются.
|
||||
Gelios выдаёт ровно два provider secrets: access token и refresh token. Текущий
|
||||
HTTP request binding `httpBearerAuth` использует access token. Автоматический
|
||||
refresh в принятом runtime не доказан, поэтому provider package фиксирует его
|
||||
как `operator_managed`; ни один из token values не попадает в graph, package,
|
||||
Ontology, Data Plane, Foundry, execution logs, MCP или Ops. Новый account или
|
||||
provider-issued token pair означает новые native credential records и
|
||||
connection instance, но не новую Platform-сущность.
|
||||
|
||||
### 3. Граница данных и интерфейса
|
||||
Локальное имя credential (например, с суффиксом `read access`) не является
|
||||
provider scope. В target-контракте Read-классификацию задаёт allowlisted
|
||||
method/endpoint в capability catalog и Engine workflow policy; тот же access
|
||||
token нельзя называть отдельным «read token» или «write token» только из-за
|
||||
label. Сейчас deployed Engine safe-ref policy ограничивает generic HTTP
|
||||
credential только по host, но ещё не связывает его с package/version и exact
|
||||
method/path. Поэтому Gelios `GET /api/v1/units` пока является декларативной
|
||||
capability, а не завершённой runtime-security гарантией; canonical acceptance
|
||||
требует capability-bound Engine policy и её MCP proof.
|
||||
|
||||
```text
|
||||
Provider API (safe read)
|
||||
-> Engine provider-credential reference
|
||||
-> L2 connector instance (adapter + mapping + batches)
|
||||
-> Engine writer-credential reference
|
||||
-> External Data Plane Data Product publish (scope materialized server-side)
|
||||
-> External Data Plane (generic persistence + projections)
|
||||
-> scoped data product / realtime stream
|
||||
-> Foundry binding / user interface
|
||||
```
|
||||
Writer capability для публикации Data Product — отдельный внутренний native NDC
|
||||
L2 credential, не третий Gelios token. Generic Engine/Platform control plane
|
||||
генерирует capability внутри native credential boundary, сохраняет её там же и
|
||||
передаёт EDP только SHA-256 digest вместе с точным provider, connection и
|
||||
набором Data Products. Пользователь и MCP получают только opaque
|
||||
reference/status. Capability не записывается в graph, provider package, env,
|
||||
file, Ops или trace и не копируется через пользовательский UI.
|
||||
|
||||
Ontology Core описывает semantic types, связи, capability catalog и mapping
|
||||
versions, но не хранит runtime payloads или секреты. Foundry получает только
|
||||
approved data product и решает presentation: pins, visibility, layers and
|
||||
filters. Оно не получает provider endpoint или credential.
|
||||
Широкий credential sink, resolver/daemon с произвольной записью secret и любой
|
||||
provider-specific credential service запрещены. Нужна одна узкая операция
|
||||
`ensure data-product publish grant`: scope выводится из granted L1→L2 target,
|
||||
зарегистрированного connection profile и разрешённого Data Product; issuance,
|
||||
rotation и native binding должны быть idempotent, CAS/crash-safe и auditable.
|
||||
Engine генерирует capability внутри credential boundary и передаёт EDP только
|
||||
SHA-256 digest через idempotent binding key + generation; EDP не возвращает
|
||||
plaintext. Новая generation создаётся до переключения node reference, а старая
|
||||
отзывается только после успешного bind/acceptance.
|
||||
Старые ручные EDP `POST/rotate` endpoints, которые возвращают capability один
|
||||
раз, включаются отдельным legacy-флагом и не входят в canonical acceptance.
|
||||
Digest-only managed endpoint имеет независимый флаг и принимает только
|
||||
Ed25519-signed Engine service requests: exact audience/method/request target/raw
|
||||
body hash входят в подпись, timestamp ограничен по skew, nonce защищён bounded
|
||||
fail-closed replay cache. Legacy provisioner bearer на managed routes не
|
||||
действует. EDP получает только deployment public key; matching private key
|
||||
остаётся только внутри Engine server boundary. Endpoint остаётся выключенным,
|
||||
пока key provisioning, Engine signer и exact native credential binding policy
|
||||
не пройдут runtime acceptance.
|
||||
В deployed Engine MCP этой операции пока нет — это текущий platform gap перед
|
||||
canonical publish proof, а не действие пользователя. Это решение не заявляет
|
||||
автоматический refresh Gelios: до отдельного runtime proof он остаётся
|
||||
`operator_managed`.
|
||||
|
||||
### 4. Полнота без entity allowlist
|
||||
### 4. External Data Plane нейтрален к поставщику
|
||||
|
||||
Collection profile выбирает разрешённые **read-capabilities**, а не список
|
||||
конкретных объектов. Если выбранный read endpoint возвращает все доступные
|
||||
источнику сущности, L2 передаёт все валидные элементы. Новые сущности
|
||||
добавляются автоматически; скрытие/отображение — задача data product/UI, а не
|
||||
сбора. Технические лимиты существуют только как размер batch, backpressure,
|
||||
quota и защита от повреждённого ответа, но не как бизнес-фильтр по ID.
|
||||
Platform предоставляет один versioned External Data Plane. Он принимает
|
||||
canonical facts через scoped writer binding, хранит current/history
|
||||
projections и публикует snapshot/patch contracts. В нём запрещены:
|
||||
|
||||
### 5. Масштабирование и native NDC Agent nodes
|
||||
- ветвления по provider, customer, account, entity или renderer;
|
||||
- provider field mapping и бизнес-фильтрация;
|
||||
- provider credential, endpoint, schedule или command transport;
|
||||
- caller-supplied tenant/connection scope.
|
||||
|
||||
L2 не запускает отдельный execution на каждую сущность. Он использует native
|
||||
nodes NDC Agent: HTTP Request, Split Out, Split In Batches/Loop Over Items,
|
||||
Aggregate, Postgres (когда нужен private workflow state), Set/If/Merge,
|
||||
Schedule Trigger and Respond to Webhook. Code node допустим только как малый
|
||||
преобразователь boundary-shape, когда эквивалентной native node нет; он не
|
||||
становится скрытым сервисом или provider database.
|
||||
`NDC Data Product Publish` отправляет только
|
||||
`nodedc.data-product.publish/v1`. External Data Plane materializes immutable
|
||||
scope из writer binding, проверяет разрешённый Data Product и его ontology
|
||||
revision, затем сохраняет batch.
|
||||
|
||||
Shared telemetry/history не записывается L2 напрямую в физические таблицы
|
||||
Platform Postgres: это создало бы coupling к schema. Direct Postgres допустим
|
||||
для private state конкретного workflow или отдельной project-owned базы.
|
||||
Общий контур использует только External Data Plane contract и bulk batches.
|
||||
EDP runtime импортирует только package subpath
|
||||
`@nodedc/external-provider-contract/data-plane`. Его deploy artifact и image
|
||||
содержат только provider-neutral wire validators; `providers/gelios`, mappings,
|
||||
fixtures и tests туда не входят. Изменение или добавление provider package не
|
||||
пересобирает и не перезапускает EDP: каталог поставщиков разворачивается через
|
||||
Engine/Ontology/control-plane путь отдельно.
|
||||
|
||||
### 5.1. Каталог custom nodes NODE.DC
|
||||
Collection cadence, history cadence и presentation cadence независимы:
|
||||
|
||||
Встроенные узлы runtime сохраняют свои штатные названия (`HTTP Request`,
|
||||
`Schedule Trigger`, `Loop Over Items` и т. п.). Любой узел, код которого
|
||||
принадлежит NODE.DC, обязан одновременно выполнять три условия:
|
||||
- NDC L2 забирает источник с частотой, нужной бизнес-задаче;
|
||||
- current projection принимает каждое валидное изменение;
|
||||
- declarative history policy может хранить все точки или sampling;
|
||||
- Foundry читает snapshot+patch и отдельно ограничивает частоту render.
|
||||
|
||||
- видимое имя начинается с `NDC `;
|
||||
- runtime type принадлежит package namespace `n8n-nodes-ndc.*`;
|
||||
- package-level test отклоняет публикацию узла без этого префикса и namespace.
|
||||
Для разной частоты БД и интерфейса не создаются второй provider sink, отдельный
|
||||
gateway или параллельный прямой push в renderer.
|
||||
|
||||
Первый канонический набор состоит из:
|
||||
### 5. Полнота означает все сущности разрешённой capability
|
||||
|
||||
- `NDC Data Product Publish` — runtime write boundary L2 → Data Plane;
|
||||
- `NDC Data Product Read` — scoped current snapshot read по reader grant;
|
||||
- `NDC Foundry Binding` — deploy/control-plane связь Data Product с
|
||||
`Application → Page → typed slot`, но не транспорт каждого realtime tick.
|
||||
Connection profile выбирает safe-read capabilities, а не зашитый в Platform
|
||||
список entity IDs. Если разрешённый endpoint возвращает все доступные credential
|
||||
сущности, NDC L2 обрабатывает каждый валидный item. Новый объект появляется
|
||||
автоматически.
|
||||
|
||||
`NDC Foundry Output` не используется как техническое имя: оно ошибочно
|
||||
подразумевает прямой transport L2 → renderer. Provider-specific adapter,
|
||||
mapping и collection profile остаются логикой конкретного L2 workflow на
|
||||
штатных nodes; они не оформляются как custom NODE.DC nodes и не добавляют
|
||||
provider branch в Data Plane или Foundry.
|
||||
Пользовательская фильтрация, слои и видимость находятся после сбора — в
|
||||
automation/Data Product/Foundry. Технические ограничения допустимы только как
|
||||
pagination, quota, batch size, backpressure и защита от повреждённого ответа.
|
||||
|
||||
`NDC Foundry Binding` отправляет только
|
||||
`nodedc.foundry.binding-upsert/v1`. Её постоянный L2 credential — отдельный
|
||||
revocable `ndc_fndbg_*` workload grant с allowlist точных
|
||||
`Application → Page → Binding → Slot → Data Product` targets. Короткоживущая
|
||||
`fnd1.*` capability интерактивного Foundry MCP, browser session, EDP
|
||||
writer/reader grant и `NODEDC_INTERNAL_ACCESS_TOKEN` для этой ноды запрещены.
|
||||
### 6. Custom NDC nodes ограничены платформенными границами
|
||||
|
||||
Runtime node не содержит URL, endpoint, provider ID, tenant ID, connection ID,
|
||||
token, contract version или history cadence. Узел выбирает только разрешённый
|
||||
Data Product; всё остальное materializes из opaque writer/reader binding и
|
||||
immutable Data Product definition.
|
||||
Первый канонический набор:
|
||||
|
||||
Package `n8n-nodes-ndc` устанавливается как штатный private community package в
|
||||
`/home/node/.n8n/nodes/node_modules`, чтобы n8n `PackageDirectoryLoader`
|
||||
сохранил namespace `n8n-nodes-ndc.*`. `~/.n8n/custom` и
|
||||
`N8N_CUSTOM_EXTENSIONS` запрещены для этого пакета: они создают namespace
|
||||
`CUSTOM.*`. Ручное копирование или `npm install` в живом container, patch
|
||||
Engine core и подмена built-in node запрещены. Production использует
|
||||
проверенный offline tarball, immutable release, atomic current/previous switch,
|
||||
read-only mount и restart всех n8n execution processes; acceptance завершается
|
||||
только когда Engine schema и MCP catalog возвращают точные package-qualified
|
||||
types.
|
||||
- `NDC Data Product Publish` — NDC L2 → External Data Plane;
|
||||
- `NDC Data Product Read` — scoped snapshot/patch read;
|
||||
- `NDC Foundry Binding` — control-plane связь Data Product с
|
||||
`Application → Page → typed slot`.
|
||||
|
||||
### 5.2. Realtime delivery contract
|
||||
Эти nodes не содержат provider ID, tenant ID, connection ID, endpoint, token,
|
||||
mapping или cadence. Runtime package сохраняет технический namespace
|
||||
`n8n-nodes-ndc.*`, но пользовательские документы и интерфейсы используют
|
||||
только терминологию NDC.
|
||||
|
||||
Новый writer использует:
|
||||
`NDC Foundry Binding` не транспортирует каждый realtime tick. Он создаёт
|
||||
постоянную связь интерфейса с Data Product; Foundry затем читает его
|
||||
snapshot+patch contract.
|
||||
|
||||
```text
|
||||
POST /internal/data-plane/v1/data-products/:dataProductId/publish
|
||||
Authorization: Bearer <opaque writer binding>
|
||||
```
|
||||
### 7. Реальный Gelios acceptance-кейс
|
||||
|
||||
Body имеет schema `nodedc.data-product.publish/v1` и содержит только batch
|
||||
identity и canonical facts. Data Plane одной транзакцией:
|
||||
Первая версия provider package должна доказать путь:
|
||||
|
||||
1. проверяет idempotency;
|
||||
2. обновляет current projection только более новым или изменившимся фактом;
|
||||
3. применяет declarative history policy (`none`, `all`, `sampled`);
|
||||
4. добавляет changed facts в durable patch outbox;
|
||||
5. фиксирует монотонный cursor.
|
||||
`Gelios safe read → все доступные units → map.moving_object facts →
|
||||
fleet.positions.current.v1 → Foundry map`
|
||||
|
||||
Reader grant получает snapshot `nodedc.data-product.snapshot/v1`, затем
|
||||
подключается к SSE stream с `after=<snapshot.cursor>` или `Last-Event-ID`.
|
||||
Каждый outbox event имеет schema `nodedc.data-product.patch/v1`. Если cursor
|
||||
уже удалён retention policy, stream отвечает `409 resync_required`, и consumer
|
||||
повторяет snapshot. Browser не получает Data Plane token или scope: Foundry BFF
|
||||
разрешает persisted binding и читает server-only reader grant.
|
||||
Canonical product использует ontology revision
|
||||
`ontology.map.moving_object.v1` и только объявленные snake_case поля. NDC L2
|
||||
не передаёт caller scope и не собирает собственный batch envelope вокруг
|
||||
`NDC Data Product Publish`.
|
||||
|
||||
`snapshot+patch` в v1 является **bounded product contract**. Current projection
|
||||
одного scoped Data Product не может содержать больше 5000 entity keys
|
||||
`(sourceId, semanticType)`. Snapshot возвращает целую согласованную projection
|
||||
и один barrier cursor из одной `REPEATABLE READ` transaction. Query-параметр
|
||||
`limit` — только защитный потолок, а не размер страницы: если полная projection
|
||||
не помещается, Data Plane отвечает `413 data_product_snapshot_limit_exceeded`
|
||||
и consumer не начинает patch stream с неполной базой.
|
||||
Acceptance выполняется по порядку:
|
||||
|
||||
Наивная pagination current snapshot по `sourceId`, offset или независимо
|
||||
полученным page cursors запрещена: изменения между страницами могут быть
|
||||
пропущены или продублированы относительно patch cursor. Product с ожидаемой
|
||||
cardinality выше 5000 обязан **до включения realtime** выбрать один из двух
|
||||
отдельно версионируемых контрактов:
|
||||
1. Platform выполняет generic `ensure data-product publish grant`, выпускает
|
||||
scoped EDP binding и атомарно сохраняет capability в native NDC L2
|
||||
Credentials;
|
||||
2. NDC MCP видит только совместимый opaque writer credential reference/status;
|
||||
3. применить подтверждённый graph patch без legacy intake;
|
||||
4. validate/preflight;
|
||||
5. один успешный manual run и проверка execution/trace/Data Product;
|
||||
6. только затем отдельным изменением добавить Schedule Trigger;
|
||||
7. после доказанного snapshot+patch подключить Foundry binding.
|
||||
|
||||
- stable partitioning в несколько Data Products, где partition key является
|
||||
частью definition, а каждый partition имеет собственный полный snapshot и
|
||||
независимый patch cursor;
|
||||
- новый query delivery contract с явно определёнными snapshot barrier,
|
||||
continuation cursor, query scope и правилами перехода к patch stream.
|
||||
### 8. Capacity и topology
|
||||
|
||||
Такой query contract не входит в `nodedc.data-product.snapshot/v1` и не может
|
||||
быть имитирован полем `nextPageCursor`. До его отдельного утверждения runtime и
|
||||
`NDC Data Product Read` работают только с bounded products до 5000 сущностей.
|
||||
|
||||
### 6. Порядок первой реализации
|
||||
|
||||
1. Версионировать нейтральный intake/read contract и поднять External Data
|
||||
Plane без provider-specific logic.
|
||||
2. Пересобрать существующий L2 proof в native-node pipeline: safe read →
|
||||
split/batch → semantic mapping → generic append → safe summary. Никаких
|
||||
provider ID filters и provider gateway endpoint.
|
||||
3. Выполнить manual run, проверить execution/trace, idempotency and current
|
||||
projection; только затем включить Schedule Trigger.
|
||||
4. Provision immutable writer binding, one-time place its token into an opaque
|
||||
Engine credential, then switch the L2 to
|
||||
`/data-products/:dataProductId/publish` and remove caller scope/headers and
|
||||
the shared legacy credential.
|
||||
5. Подключить Foundry к data product current positions. История, геозоны и
|
||||
новые сущности добавляются отдельными L2 collection profiles and ontology
|
||||
revisions.
|
||||
Количество одновременно активных NDC L2 проектов ограничивается фактическими
|
||||
ресурсами железа и профилем нагрузки. Пока capacity проверяется оператором и не
|
||||
автоматизируется. Канон не объявляет отдельные worker/webhook generations или
|
||||
high-load topology, которых ещё нет в принятом runtime.
|
||||
|
||||
## Последствия
|
||||
|
||||
- `services/<provider>-gateway` не является шаблоном для новых интеграций.
|
||||
Существующий experimental code не расширяется и не деплоится как часть этого
|
||||
решения.
|
||||
- Data Plane может иметь собственную БД/Timescale/PostGIS implementation, но
|
||||
физическая схема остаётся внутренней деталью neutral service, а не API для
|
||||
L2 или Foundry.
|
||||
- Inline raw запрещён в L2 → Data Plane v1: до отдельного raw-vault допускается
|
||||
только restricted ref/hash либо отсутствие raw envelope. Retention reference
|
||||
вычисляется по серверному acceptance time, а не по timestamp из batch; Data
|
||||
Plane выполняет bounded retention sweeps после готовности сервиса и по таймеру.
|
||||
- Обычный Codex Desktop получает ровно те L2 grants, которые выданы владельцем
|
||||
connection/workflow, и может безопасно развивать adapter только в этой
|
||||
границе.
|
||||
- `POST /internal/data-plane/v1/intake` остаётся временным migration-only route:
|
||||
он выключен по умолчанию (`EXTERNAL_DATA_PLANE_LEGACY_INTAKE_ENABLED=false`),
|
||||
требует `NODEDC_INTERNAL_ACCESS_TOKEN`, canonical scoped batch и совпадающие
|
||||
scope headers. Новый или migrated L2 не получает этот shared token и не
|
||||
использует fallback в legacy route. После миграции всех writers он удаляется.
|
||||
- `services/<provider>-gateway` не является частью канона и не создаётся для
|
||||
новых provider integrations. Существующий self-hosted Gelios Gateway и его
|
||||
Timescale volume остаются frozen compatibility contour, воспроизводятся из
|
||||
source/deploy и не изменяются новым L2 pilot без отдельного решения.
|
||||
- Новый account или provider-issued access/refresh pair — configuration change,
|
||||
а не platform release.
|
||||
- Новый provider или неподдержанная capability — versioned provider/Ontology
|
||||
change с contract tests.
|
||||
- Существующий legacy L1/SDK workflow является frozen compatibility boundary:
|
||||
новый L2 pilot его не редактирует, не отзывает его credential и не ставит его
|
||||
вывод условием acceptance.
|
||||
- Legacy `/internal/data-plane/v1/intake` остаётся выключенным migration-only
|
||||
route и не используется новыми NDC L2 workflows.
|
||||
- Команды устройствам остаются отдельным red-domain контуром с явным
|
||||
подтверждением, scope, idempotency и аудитом.
|
||||
- Foundry развивается после доказанного Data Product path; provider API и
|
||||
credentials в Foundry не попадают.
|
||||
|
||||
Reference in New Issue
Block a user