feat(foundry): close the operational map data loop
This commit is contained in:
@@ -62,6 +62,8 @@ Dropdown владеет floating-layer поведением:
|
||||
|
||||
Содержимое меню передаётся приложением. Selection, action menu и filter menu используют один engine.
|
||||
|
||||
Поверх Cesium/map imagery dropdown получает класс `nodedc-map-glass` (`MapGlassSurface`): это отдельный светлый полупрозрачный материал, совпадающий с Map Toolbar. Он не заменяет обычный theme-dependent floating surface вне карты.
|
||||
|
||||
## Select
|
||||
|
||||
Select добавляет к Dropdown контролируемое значение, options и необязательный поиск. У него две канонические формы:
|
||||
@@ -210,6 +212,10 @@ Sortable-строки ограничены вертикальной осью: г
|
||||
|
||||
Статус использует semantic tone: neutral, success, warning, danger или accent. Бизнес-статус приложения маппится на tone в самом приложении.
|
||||
|
||||
## ToastStack
|
||||
|
||||
`ToastCard` и `ToastStack` фиксируют Tasker-derived bottom-right уведомления для `success`, `error`, `warning`, `info` и `loading`. Приложение владеет текстом и состоянием операции; стек владеет portal, геометрией, aria-live и таймерами. Loading не закрывается автоматически и обновляется тем же id после завершения операции. Toast не используется вместо modal confirmation.
|
||||
|
||||
## Environment Controls: Inspector и ControlRow
|
||||
|
||||
Единая accordion-панель для settings и definition controls. Источник — только новый Environment Settings и NDC Agent Inspector.
|
||||
|
||||
+36
-6
@@ -5,7 +5,7 @@
|
||||
## Границы ответственности
|
||||
|
||||
- Page Template владеет компоновкой страницы, Inspector, Toolbar, Assistant entry point, слотами данных и системными действиями.
|
||||
- Map Scene Fixture задаёт минимальный проверочный набор пространственных сущностей и состояний.
|
||||
- Empty Map Scene Fixture проверяет shell без каких-либо shipped domain-объектов.
|
||||
- Application Manifest фиксирует экземпляр страницы, выбранный Design Profile и feature visibility.
|
||||
- Platform capability binding связывает слоты шаблона с scoped data products через Foundry runtime BFF.
|
||||
- Renderer adapter преобразует provider-neutral scene в Cesium или другой поддерживаемый renderer.
|
||||
@@ -26,14 +26,30 @@ Engine/NDC остаётся средой создания и исполнени
|
||||
- selection;
|
||||
- ready/loading/empty/stale/error/offline states.
|
||||
|
||||
Размеры и внешний вид разновидностей сущностей задаются ссылками на `styleProfiles`. Это позволяет одному доменному типу иметь разные подтверждённые варианты, не создавая новый renderer-specific тип.
|
||||
Размеры и внешний вид разновидностей сущностей задаются ссылками на
|
||||
`styleProfiles`. Для live entity-stream Application page хранит отдельные
|
||||
versioned `presentationProfiles`, а binding выбирает один из них через
|
||||
`presentationProfileId`. Это позволяет одному доменному типу иметь разные
|
||||
подтверждённые варианты, не создавая новый renderer-specific тип.
|
||||
|
||||
Канонический moving-object профиль находится в
|
||||
`registry/map-presentation-profiles.json`. Он задаёт универсальную геометрию
|
||||
таргета, плашку подписи, LOD и два пользовательских status facets: связь и
|
||||
движение. Для текущего Gelios binding значения и подписи повторяют официальный
|
||||
статусный набор: `Онлайн`, `Офлайн`, `В движении`, `Стоят`. Position
|
||||
quality и freshness остаются внутренними фактами качества и не дублируют
|
||||
пользовательские фильтры. Классы, фильтры, счётчики и sort order читают один
|
||||
profile; renderer не содержит provider-specific условий.
|
||||
|
||||
Кнопка `Объекты` открывает вверх текстовый dropdown из Application bindings. Выбор строки открывает или фокусирует отдельное canonical `WorkspaceWindow`, а его универсальное содержимое строится из presentation profile/facets. Несколько binding-окон могут быть открыты одновременно; stable identity всегда `bindingId`, поэтому пользовательское переименование не ломает сохранённый layout.
|
||||
|
||||
Facet-фильтры поддерживают мультивыбор: OR внутри одного facet и AND между facets. Missing facet означает отсутствие ограничения, а явно пустой список — ноль совпадений. Отжатие последнего chip не включает `Все`; `Все` включается и выключается только явным кликом. Переключение фильтра не двигает камеру, обзор выполняется отдельным действием.
|
||||
|
||||
## Acceptance fixtures
|
||||
|
||||
- `registry/fixtures/map/map-operational-v0.1.json` — минимальная рабочая сцена с сеткой, транспортом, станциями, маршрутом, железнодорожным путём, зоной и selection.
|
||||
- `registry/fixtures/map/map-empty-offline-v0.1.json` — отсутствие provider/live data без разрушения shell и управляющих действий.
|
||||
|
||||
Fixtures малы и детерминированы. Большие геоданные, tile cache, credentials и реальные streaming snapshots в репозиторий гайдлайнов не входят.
|
||||
Page/Visual/Application previews не содержат shipped domain fixtures. Объекты появляются только из declared Application bindings. Большие геоданные, tile cache, credentials и реальные streaming snapshots в репозиторий гайдлайнов не входят.
|
||||
|
||||
## Sandbox credit overlay
|
||||
|
||||
@@ -41,7 +57,7 @@ Fixtures малы и детерминированы. Большие геодан
|
||||
|
||||
## Cesium adapter 1.143
|
||||
|
||||
Текущий reference adapter использует CesiumJS `1.143.0`. Он загружается отдельным lazy chunk только при открытии Map Page и преобразует fixture в реальные Cesium entities: points, labels, routes, tracks, zones и selection. Без настроенного ion gateway используется development fallback `WGS84 globe + OpenStreetMap imagery`.
|
||||
Текущий reference adapter использует CesiumJS `1.143.0`. Он загружается отдельным lazy chunk только при открытии Map Page и преобразует только declared Application bindings в реальные Cesium entities. Пустая Map Page не содержит domain entities.
|
||||
|
||||
Server-side runtime contract:
|
||||
|
||||
@@ -82,7 +98,8 @@ Runtime tile cache не является исходным кодом и не х
|
||||
## Live data-product runtime
|
||||
|
||||
`Map Page` хранит только provider-neutral binding: `dataProductId`, approved
|
||||
semantic types, field projection и `slotId` (`points` для live point entities).
|
||||
semantic types, field projection, `presentationProfileId` и `slotId` (`points`
|
||||
для live point entities).
|
||||
При открытии Application page browser делает same-origin запрос к Foundry:
|
||||
|
||||
```text
|
||||
@@ -94,6 +111,9 @@ runtime. При первом exact consumer apply Foundry генерирует t
|
||||
передаёт EDP только его digest в запросе с отдельной service-подписью; EDP сам
|
||||
разрешает unique active writer scope и fail-closed отклоняет ambiguity. Legacy
|
||||
root-owned deployment directory используется только как совместимый fallback.
|
||||
При смене versioned Data Product Foundry создаёт successor reader generation,
|
||||
bootstrap-ит новый snapshot и только затем отзывает predecessor; существующий
|
||||
grant никогда не переписывается другим request hash внутри одного поколения.
|
||||
Browser, manifest и Cesium adapter не получают provider
|
||||
endpoint, tenant/connection scope, reader token или raw provider payload.
|
||||
Сначала server-owned Foundry consumer коммитит snapshot, затем применяет patch
|
||||
@@ -104,3 +124,13 @@ history route (`from/to/resolution/sourceIds/cursor`) через тот же BFF
|
||||
занимает общую L2 execution queue. Renderer держит отдельный `CustomDataSource`
|
||||
на binding и обновляет stable entity id без пересоздания viewer. Sampling и
|
||||
retention остаются политикой Data Plane, а не Map Template.
|
||||
|
||||
`fleet.positions.current.v2@2.0.0` является первым state-aware moving-object
|
||||
контрактом. Пользовательский status contract ограничен
|
||||
`availability_state=online|offline` и `motion_state=moving|stationary`;
|
||||
границы берутся из настроек объекта Gelios (`lostConnectionTimeValue` и
|
||||
`minimumMovementSpeed`), а не из придуманных Foundry thresholds. Технические
|
||||
`position_state`, `freshness_state` и `state_policy_version` могут оставаться в
|
||||
факте для quality/diagnostics, но не образуют дополнительные UI-фильтры. Цвет,
|
||||
геометрия таргета, label и порядок фильтров остаются в Foundry presentation
|
||||
profile.
|
||||
|
||||
@@ -15,6 +15,8 @@ MCP не вводит новую оркестрацию. Доступ выдаё
|
||||
| Изменять название, slug и описание instance | Создавать свободный canvas или произвольный React-интерфейс |
|
||||
| Добавлять повторные instances зарегистрированной страницы | Вызывать Engine, provider API или произвольный внешний endpoint из Foundry MCP |
|
||||
| Создавать/обновлять provider-neutral map pin bindings | Хранить provider tokens, transport payload или credentials в manifest |
|
||||
| Создавать/обновлять versioned provider-neutral `map.style_profile` | Хардкодить provider-specific statuses, цвета или размеры в renderer |
|
||||
| Задавать text label/order binding и сохранять полный Map view/window layout по `bindingId` | Использовать редактируемое имя как machine identity или превращать empty selection в all |
|
||||
| Связывать versioned data product с approved Map entity-stream slot | Хранить provider ID, tenant/connection, endpoint или credential в data binding |
|
||||
| Управлять server-owned consumer только для persisted approved binding | Передавать reader capability, EDP URL или raw provider payload через MCP |
|
||||
|
||||
@@ -55,6 +57,10 @@ Endpoint поддерживает два существующих контура
|
||||
- `foundry_update_application_metadata`
|
||||
- `foundry_add_page_instance`
|
||||
- `foundry_upsert_map_pin_binding`
|
||||
- `foundry_remove_map_pin_binding`
|
||||
- `foundry_upsert_map_presentation_profile`
|
||||
- `foundry_update_map_page_settings`
|
||||
- `foundry_save_map_page_view_state`
|
||||
- `foundry_upsert_map_data_product_binding`
|
||||
- `foundry_plan_map_data_product_consumer`
|
||||
- `foundry_apply_map_data_product_consumer`
|
||||
@@ -62,11 +68,43 @@ Endpoint поддерживает два существующих контура
|
||||
- `foundry_accept_map_data_product_consumer`
|
||||
- `foundry_rollback_map_data_product_consumer`
|
||||
|
||||
`foundry_upsert_map_pin_binding` хранит только визуальную, provider-neutral привязку `elevated-spike`: стабильный id, subject, координаты, semantic status и ссылку на источник сущности. Поток живых данных не передаётся в MCP по одной позиции: визуальная привязка и поток данных будут связываться следующими contract/ontology слоями.
|
||||
`foundry_upsert_map_pin_binding` хранит только визуальную, provider-neutral привязку `elevated-spike`: стабильный id, subject, координаты, semantic status и ссылку на источник сущности. Поток живых данных не передаётся в MCP по одной позиции.
|
||||
|
||||
`foundry_remove_map_pin_binding` удаляет одну устаревшую визуальную привязку по
|
||||
стабильному `bindingId`. Операция не затрагивает data-product consumer, его
|
||||
последний безопасный snapshot или канонический шаблон `Page Library`.
|
||||
|
||||
`foundry_upsert_map_presentation_profile` управляет отдельным версионированным
|
||||
`map.style_profile` страницы. Профиль содержит renderer-neutral геометрию
|
||||
таргета, label contract, semantic styles, правила классов, facet filters,
|
||||
counters и sort order. Условия классов могут ссылаться только на объявленные
|
||||
provider-neutral facet fields. Data Product binding выбирает профиль через
|
||||
`presentationProfileId`; binding также может задавать пользовательский
|
||||
`displayName` и порядок строки в dropdown `Объекты`. Provider raw status,
|
||||
endpoint и credential в профиль не допускаются. Полная machine-readable JSON Schema профиля публикуется прямо
|
||||
в `tools/list`: label использует `mode`, `fields`, плашку, `fontWeight` и
|
||||
`sizePx`, а target,
|
||||
facets, styles, classes и sort имеют закрытые наборы полей. Поэтому новый MCP
|
||||
клиент может создать профиль для другого spatial domain без чтения исходников
|
||||
Foundry и без неописанного generic JSON.
|
||||
|
||||
`foundry_update_map_page_settings` меняет подложку, terrain, здания, атмосферу,
|
||||
освещение и сетку только у указанного экземпляра Map внутри `Application`.
|
||||
Операция не пишет в `Page Library`, принимает закрытый typed patch и поэтому
|
||||
может безопасно воспроизводить визуальное окружение через MCP.
|
||||
|
||||
`foundry_save_map_page_view_state` является MCP-эквивалентом одной Application
|
||||
кнопки `Сохранить`. Операция атомарно сохраняет camera/map height, typed patch
|
||||
base settings, exact visibility/facet selections и все canonical binding
|
||||
windows (`open`, `rect`, `maximized`, `zIndex`). Состояние keyed только по
|
||||
`bindingId`: editable `displayName` не участвует в identity. Missing facet не
|
||||
ограничивает выборку, явно пустой список остаётся empty после reopen и не
|
||||
мигрирует обратно в `Все`.
|
||||
|
||||
`foundry_upsert_map_data_product_binding` сохраняет только декларацию
|
||||
`data product → Map entity-stream slot`: versioned data product id, semantic
|
||||
types и допустимую field projection. Endpoint, provider, tenant, connection,
|
||||
types, допустимую field projection и необязательную ссылку на существующий
|
||||
presentation profile. Endpoint, provider, tenant, connection,
|
||||
token, credential и raw payload валидатор отклоняет. Page runtime получает
|
||||
scoped snapshot/patch поток через Platform, но не через Foundry MCP.
|
||||
|
||||
@@ -82,6 +120,15 @@ target-scoped token, коммитит snapshot и включает consumer; `st
|
||||
сохраняет последний safe snapshot. Capability value, grant path, internal URL и
|
||||
fact attributes в MCP diagnostics не возвращаются.
|
||||
|
||||
Reader grant версионируется поколениями. При замене Data Product Foundry не
|
||||
перезаписывает immutable request generation и не ослабляет EDP conflict fence:
|
||||
он выпускает отдельный successor token/generation, проверяет им новый catalog и
|
||||
коммитит новый snapshot. Только после успешного snapshot predecessor generation
|
||||
отзывается exact revoke. Если bootstrap не удался, persisted predecessor
|
||||
snapshot и его grant остаются рабочими. Если временно не удался только revoke,
|
||||
следующий exact plan получает action `finalize-reader-grant-rotation` и завершает
|
||||
отзыв без повторного bootstrap.
|
||||
|
||||
## Runtime data-product boundary
|
||||
|
||||
Для Map Page Foundry предоставляет только same-origin runtime routes:
|
||||
@@ -93,8 +140,10 @@ GET /api/applications/:applicationId/pages/:pageId/data-bindings/:bindingId/stre
|
||||
```
|
||||
|
||||
Маршрут разрешает persisted binding, а затем server-owned consumer находит
|
||||
opaque EDP reader grant по `sha256(applicationId/pageId/bindingId)`. Нормальный
|
||||
grant создаётся внутри persistent private runtime Foundry; runner монтирует
|
||||
opaque EDP reader grant по `sha256(applicationId/pageId/bindingId)` и persisted
|
||||
active generation. Generation 1 сохраняет совместимый legacy filename, а
|
||||
successor capabilities хранятся отдельными root-owned immutable files.
|
||||
Нормальный grant создаётся внутри persistent private runtime Foundry; runner монтирует
|
||||
отдельный Ed25519 private key только для подписи digest-only provisioner
|
||||
request, а EDP получает только public trust. Старый root-owned read-only grant
|
||||
directory остаётся fallback для уже выданных grant. Сам token передаётся
|
||||
@@ -121,7 +170,9 @@ Freshness и remove принадлежат versioned provider-neutral policy и
|
||||
ошибка не удаляет subject. Удаление допустимо только при отсутствии в
|
||||
авторитетном snapshot rebase или по canonical `tombstone`/`revoked` operation.
|
||||
Renderer получает стабильный `sourceId + semanticType`, persisted coordinates
|
||||
и Foundry-owned `presentationStatus`; provider identity на стиль и lifecycle не
|
||||
и Foundry-owned `presentationStatus`. Операционные visual classes, фильтры,
|
||||
счётчики и сортировка разрешаются отдельно из orthogonal state facets и
|
||||
page-owned `map.style_profile`; provider identity на стиль и lifecycle не
|
||||
влияет.
|
||||
|
||||
## Внешний Codex: Foundry + отдельная Ontology MCP
|
||||
@@ -246,7 +297,7 @@ curl http://127.0.0.1:9920/healthz
|
||||
## Следующие слои
|
||||
|
||||
1. Онтологический contract приложения, страницы, page instance, Map Page и visual entities.
|
||||
2. Runtime adapter между ontology/gateway потоками и сохранёнными visual bindings.
|
||||
3. Реальные `elevated-spike`, targets, zones, routes и toolbar commands на instance Map Page.
|
||||
2. Расширение runtime adapter с points на targets, zones, routes и tracks.
|
||||
3. Управляемая публикация и повторное использование presentation profiles между Applications.
|
||||
4. Access/Hub registration и публикация module route.
|
||||
5. Отдельная пустая программируемая страница — только после того, как готовые page templates и их MCP-контуры отработаны.
|
||||
|
||||
@@ -20,9 +20,7 @@
|
||||
|
||||
Каноническая JSON Schema: `registry/schemas/map-scene-fixture-v0.1.schema.json`. Проверочные сцены перечислены прямо в контракте `map@0.1.0` и лежат в `registry/fixtures/map`.
|
||||
|
||||
Fixture фиксирует provider-neutral viewport, capabilities, общие style profiles, слои, города, движущиеся объекты, станции, маршруты, пути, зоны, selection и ожидаемое поведение. Он не хранит Cesium types, токены, renderer instances, Engine workflow или transport payload конкретного источника.
|
||||
|
||||
`map-operational-v0.1.json` проверяет содержательную сцену и переиспользуемый язык подписей/маркеров. `map-empty-offline-v0.1.json` проверяет, что shell и системные действия остаются работоспособными без live-данных. Registry validation дополнительно проверяет уникальность id, ссылки на style profiles, selection и непрерывность LOD-диапазонов.
|
||||
`map-empty-offline-v0.1.json` проверяет, что shell и системные действия остаются работоспособными без live-данных. Operational demo fixture удалён: Visual Library, Page Library и Applications не поставляют города, движущиеся объекты, станции, маршруты, пути, зоны или selection. Domain entities появляются только из declared Application bindings.
|
||||
|
||||
LOD вынесен в отдельный контракт `registry/schemas/map-lod-policy-v0.1.schema.json` и policy set `registry/fixtures/map/map-lod-policies-v0.1.json`. Он использует расстояние камеры в метрах, полуоткрытые диапазоны и hysteresis, поэтому не зависит от Cesium `DistanceDisplayCondition`. Дальнейшая калибровка bands выполняется на живом Map shell, а не в отрыве от визуального результата.
|
||||
|
||||
@@ -40,7 +38,7 @@ Manifest фиксирует:
|
||||
- favicon source;
|
||||
- server-controlled timestamps.
|
||||
|
||||
Manifest не хранит runtime credentials, capability bindings, arbitrary component tree, свободные координаты элементов или deployment secrets.
|
||||
Manifest не хранит runtime credentials, arbitrary component tree или deployment secrets. Map page instance хранит provider-neutral capability bindings и контролируемый view state: camera, base settings, exact facet selection и геометрию canonical binding windows, keyed by stable `bindingId`.
|
||||
|
||||
## Draft lifecycle
|
||||
|
||||
@@ -72,6 +70,10 @@ Catalog server предоставляет минимальный временн
|
||||
|
||||
Visual Library использует отдельный Hub-style selector профилей. Общая кнопка Save открывает каноническую модалку `Сохранить / Сохранить как новый / Опубликовать`. Приложение хранит pinned `profile id + version + status + theme`; media, favicon и material settings принадлежат Design Profile.
|
||||
|
||||
Design Profile также хранит независимые design-only фрагменты по зарегистрированному типу страницы (`pageTypes["map@0.1.0"]`). Для Map в такой фрагмент входят только `settings` и provider-neutral `presentationProfiles`. Camera, высота рабочего окна, pin/data-product bindings, subjects, endpoints и credentials остаются состоянием Application/runtime и никогда не попадают в профиль.
|
||||
|
||||
Кнопка Save в Page Library не изменяет канонический Page Template: она открывает ту же модалку Design Profile и обновляет только фрагмент текущего типа страницы. Сохранение следующего типа страницы сливает его фрагмент в тот же профиль, не перезаписывая глобальные поля и ранее сохранённые типы. Application разрешает визуальное состояние в порядке `canonical page defaults → pinned Design Profile page fragment → Application designOverrides`; runtime bindings при этом сохраняются отдельно.
|
||||
|
||||
`Draft` — изменяемая рабочая голова профиля. Каждое сохранение увеличивает patch-версию. `Published` — неизменяемый снимок конкретной версии: повторная публикация той же версии запрещена. Application Manifest может ссылаться на draft для внутренней разработки, но стабильный модуль должен фиксировать published release. Изменение будущего draft или публикация следующей версии не меняют уже закреплённое приложение.
|
||||
|
||||
Временный catalog server предоставляет:
|
||||
@@ -87,13 +89,15 @@ Visual Library использует отдельный Hub-style selector про
|
||||
|
||||
Catalog server проверяет полный layout-контракт Design Profile и существование выбранной Application Manifest ссылки при создании и сохранении модуля. Опубликованные снимки лежат отдельно от draft-head в `runtime-data/design-profile-releases` и исключены из Git; в production этот lifecycle должен перейти в Platform `design-profile-core` без изменения публичного контракта.
|
||||
|
||||
Все save/update/publish операции показывают канонический `ToastStack` снизу справа. Loading-state обновляется в success/error в том же toast; blocking confirmation остаётся отдельной modal-механикой.
|
||||
|
||||
## Baseline MCP
|
||||
|
||||
Foundry предоставляет базовый MCP-контур для уже существующего сквозного AI Workspace Assistant. Он не создаёт отдельную оркестрацию: штатный entitlement adapter выдаёт доступ к Foundry только авторизованному пользователю, после чего ассистент получает ограниченный набор инструментов.
|
||||
|
||||
- `Page Library` и канонические шаблоны доступны только на чтение;
|
||||
- изменяются только экземпляры в `Applications`;
|
||||
- доступны создание модуля, изменение его metadata, добавление экземпляра готовой страницы и upsert provider-neutral map pin bindings;
|
||||
- доступны создание модуля, изменение его metadata, добавление экземпляра готовой страницы, upsert provider-neutral map pin bindings, versioned Map presentation profiles и data-product bindings;
|
||||
- удаление модуля через MCP намеренно отсутствует;
|
||||
- каждая write-операция требует idempotency key и сохраняет аудит операции в persistent runtime store.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user