feat(foundry): close the operational map data loop

This commit is contained in:
Codex
2026-07-20 20:45:05 +03:00
parent aac44d057f
commit a02c3ff3dd
44 changed files with 4158 additions and 811 deletions
+58 -7
View File
@@ -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-контуры отработаны.