Document AI Inference architecture and freeze current baseline

This commit is contained in:
DCCONSTRUCTIONS
2026-09-05 10:05:01 +03:00
parent e56eb42507
commit 57f2537af3
19 changed files with 5280 additions and 53 deletions
@@ -53,7 +53,7 @@ export const LABORATORY_REPORT_TEMPLATE_VERSION =
const EXECUTION_LABELS: Record<LaboratoryExecutionClass, string> = {
deterministic: "Детерминированный",
"ai-inference": "AI inference",
"ai-inference": "AI Inference",
hybrid: "Гибридный",
};
@@ -177,7 +177,7 @@ export async function renameAICompositionRunProjection(
displayName: string,
): Promise<string> {
if (!/^ai-composition-[a-f0-9]{64}$/.test(runId)) {
throw new Error("Некорректная идентичность результата AI inference.");
throw new Error("Некорректная идентичность результата AI Inference.");
}
const normalized = displayName.trim();
if (!normalized || normalized.length > 160) {
@@ -193,19 +193,19 @@ export async function renameAICompositionRunProjection(
});
const body = await bodyOf(response);
if (!response.ok) throw apiError(body, response.status);
const row = record(body, "результат AI inference");
const row = record(body, "результат AI Inference");
exactKeys(row, ["display_name", "run_id", "schema_version"]);
if (
row.schema_version !== "missioncore.observatory-ai-composition-run-projection/v1"
|| row.run_id !== runId
|| row.display_name !== normalized
) throw new Error("Сервер не подтвердил переименование результата AI inference.");
) throw new Error("Сервер не подтвердил переименование результата AI Inference.");
return normalized;
}
export async function deleteAICompositionRunProjection(runId: string): Promise<void> {
if (!/^ai-composition-[a-f0-9]{64}$/.test(runId)) {
throw new Error("Некорректная идентичность результата AI inference.");
throw new Error("Некорректная идентичность результата AI Inference.");
}
const response = await fetch(`/api/v1/observatory/ai-composition-runs/${encodeURIComponent(runId)}`, {
method: "DELETE",
@@ -96,7 +96,7 @@ export async function deleteObservatoryLabProjection(
headers: { Accept: "application/json" },
signal,
},
"Не удалось удалить лабораторный результат из Обсерватории.",
"Не удалось удалить лабораторный результат из AI Inference.",
);
const body = await responseBody(response);
if (!response.ok || response.status !== 204) {
@@ -132,7 +132,7 @@ function admittedProjectionId(binding: ObservatoryRecordedRunBinding): string {
|| !SAFE_SESSION_ID.test(sessionId)
) {
throw new ObservatoryCatalogMutationError(
"Выбранный результат не допущен к изменению каталога Обсерватории.",
"Выбранный результат не допущен к изменению каталога AI Inference.",
);
}
return sessionId;
@@ -39,7 +39,7 @@ type ObservatoryCatalogMutationDraft =
function errorMessage(error: unknown): string {
return error instanceof Error && error.message.trim()
? error.message
: "Каталог Обсерватории недоступен.";
: "Каталог AI Inference недоступен.";
}
function isAbortError(error: unknown): boolean {
+3 -3
View File
@@ -170,9 +170,9 @@ export const workspaces: WorkspaceDefinition[] = [
{
id: "observatory",
root: "polygon",
label: "Обсерватория",
title: "AI inference",
eyebrow: "ТЕСТОВЫЙ КОНТУР / ОБСЕРВАТОРИЯ",
label: "AI Inference",
title: "AI Inference",
eyebrow: "ТЕСТОВЫЙ КОНТУР / AI INFERENCE",
description: "Сессии и квалификация без доступа к управлению.",
icon: "eye",
kind: "observatory",
@@ -165,7 +165,7 @@ function compositionProducedEvidence(
function mutationErrorMessage(error: unknown): string {
return error instanceof Error && error.message.trim()
? error.message
: "Не удалось изменить лабораторный результат в Обсерватории.";
: "Не удалось изменить лабораторный результат в AI Inference.";
}
function evidenceConfigurationLabel(
@@ -276,12 +276,12 @@ function aiJobStageDetail(
return "Не удалось запустить модель. Конфигурацию можно отправить повторно";
}
if (job.publication.state === "failed") {
return "Результат рассчитан, но не сохранён в Обсерватории";
return "Результат рассчитан, но не сохранён в AI Inference";
}
if (job.state === "succeeded") {
if (job.publication.state === "pending") return "Завершаем сохранение результата";
if (job.publication.state === "not-required") return "Публикация результата не требуется";
return "Результат сохранён в Обсерватории";
return "Результат сохранён в AI Inference";
}
if (!progress) {
return "Готовим конфигурацию и место в очереди";
@@ -862,7 +862,7 @@ export function ObservatoryWorkspace({
{run.state === "ready" ? (
<>
<IconButton
label={`Удалить ${run.displayName ?? run.presentation.configurationLabel} из Обсерватории`}
label={`Удалить ${run.displayName ?? run.presentation.configurationLabel} из AI Inference`}
onClick={() => openCompositionDelete(run)}
>
<Icon name="trash" size={16} />
@@ -952,7 +952,7 @@ export function ObservatoryWorkspace({
{evidence.recordedRun ? (
<>
<IconButton
label={`Удалить ${evidence.lab.labId} из Обсерватории`}
label={`Удалить ${evidence.lab.labId} из AI Inference`}
onClick={() => openDelete(evidence)}
>
<Icon name="trash" size={16} />
@@ -1094,7 +1094,7 @@ export function ObservatoryWorkspace({
<Window
open={renameTarget !== null || compositionRenameTarget !== null}
title="Переименовать лабораторный результат"
subtitle="Меняется только отображаемое название в Обсерватории"
subtitle="Меняется только отображаемое название в AI Inference"
size="sm"
closeOnBackdrop={mutationPending !== "rename"}
closeOnEscape={mutationPending !== "rename"}
@@ -1161,12 +1161,12 @@ export function ObservatoryWorkspace({
<ConfirmationModal
open={deleteTarget !== null || compositionDeleteTarget !== null}
title="Удалить результат из Обсерватории?"
title="Удалить результат из AI Inference?"
description={deleteTarget || compositionDeleteTarget ? (
<div className="observatory-delete-confirmation">
<p>
Будут удалены только каталожная проекция <strong>{deleteTarget?.label ?? compositionDeleteTarget?.displayName ?? compositionDeleteTarget?.presentation.configurationLabel}</strong>
{" "}и её отображаемое название в Обсерватории.
{" "}и её отображаемое название в AI Inference.
</p>
<p>
Исходная сессия, запечатанный лабораторный результат и файлы доказательств
@@ -1177,7 +1177,7 @@ export function ObservatoryWorkspace({
) : null}
</div>
) : null}
confirmLabel="Удалить из Обсерватории"
confirmLabel="Удалить из AI Inference"
pendingLabel="Удаляем…"
danger
onClose={() => {
@@ -114,10 +114,10 @@ test("Observatory mutations reject response drift and preserve API detail", asyn
);
await assert.rejects(
deleteObservatoryLabProjection(binding, {
fetcher: async () => Response.json({ detail: "Проекция не принадлежит Обсерватории." }, { status: 409 }),
fetcher: async () => Response.json({ detail: "Проекция не принадлежит AI Inference." }, { status: 409 }),
}),
(error) => error instanceof ObservatoryCatalogMutationError
&& error.status === 409
&& error.message === "Проекция не принадлежит Обсерватории.",
&& error.message === "Проекция не принадлежит AI Inference.",
);
});
@@ -34,9 +34,9 @@ test("Observatory is the third independent Polygon workspace", () => {
{
id: "observatory",
root: "polygon",
label: "Обсерватория",
title: "AI inference",
eyebrow: "ТЕСТОВЫЙ КОНТУР / ОБСЕРВАТОРИЯ",
label: "AI Inference",
title: "AI Inference",
eyebrow: "ТЕСТОВЫЙ КОНТУР / AI INFERENCE",
description: "Сессии и квалификация без доступа к управлению.",
icon: "eye",
kind: "observatory",
@@ -200,7 +200,7 @@ test("Observatory rename and delete use admitted projection mutations and canoni
assert.match(workspace, /<Window[\s\S]*title="Переименовать лабораторный результат"/);
assert.match(workspace, /<TextField[\s\S]*label="Название"[\s\S]*maxLength=\{160\}/);
assert.match(workspace, /<WindowFooterActions>[\s\S]*Сохранить/);
assert.match(workspace, /<ConfirmationModal[\s\S]*title="Удалить результат из Обсерватории\?"/);
assert.match(workspace, /<ConfirmationModal[\s\S]*title="Удалить результат из AI Inference\?"/);
assert.match(workspace, /Исходная сессия, запечатанный лабораторный результат и файлы доказательств/);
assert.match(workspace, /renameAICompositionRunProjection/);
assert.match(workspace, /deleteAICompositionRunProjection/);
@@ -1,4 +1,10 @@
# Observatory: модульные Docker-композиции → записанные LAB → CUDA-борт
# AI Inference: история модульных Docker-композиций → записанные LAB → CUDA-борт
> Срез 2026-09-05: этап временно зафиксирован владельцем. Текущая фактическая
> архитектура, ограничения и состояние приёмки описаны в
> [AI Inference](audits/2026-09-05-ai-inference-architecture.md) и отдельной карте
> Ops / MISSION CORE. Ниже сохранена история маршрута; старые «следующие шаги»
> не означают поручение автоматически продолжать запуск или мигрировать legacy LAB.
## ЕДИНСТВЕННЫЙ ТЕКУЩИЙ МАРШРУТ — 2026-09-03, модульное решение
@@ -2,6 +2,13 @@
Date: 2026-09-03. Owner-approved target; the first local modular vertical slice is installed.
Current implementation snapshot (2026-09-05): [AI Inference architecture](../audits/2026-09-05-ai-inference-architecture.md).
The owner has temporarily frozen this stage; user acceptance remains incomplete.
This ADR describes the target boundaries. The snapshot explicitly distinguishes
the implemented setup mapping and source/result reuse from the not-yet-wired
general DAG executor and per-node cache. The product name is now AI Inference;
technical Observatory identifiers remain compatible.
## Decision and supersession
A reusable module is an independently packaged Docker image for a model or a
@@ -0,0 +1,289 @@
# AI Inference — принципы работы и фактическая архитектура
Срез на 5 сентября 2026 года. Репозиторий MISSION CORE, ветка `main`, исходный код аудита `e56eb42507d005cc372ac4a53785a080b116e227`. Изменения этого среза: терминология интерфейса и фиксация архитектуры. Исполнитель, модели, очередь, Rerun и способы обмена данными не рефакторились.
## 01. Решение и границы закрытия
AI Inference — текущий лабораторный путь применения выбранной AI-конфигурации к сохранённой физической записи и просмотра сохранённых доказательств. Раздел находится в LAB приложения Mission Core. Название «Обсерватория» больше не используется в текущем пользовательском интерфейсе. Технические `observatory` в URL, схемах, именах Python/TypeScript, Docker labels и старых evidence сохраняются для совместимости.
По решению владельца этот этап временно зафиксирован. Завершены архитектурный срез и консолидация контекста; пользовательская приёмка ещё не завершена. Это не статус production-ready, не доказательство real-time и не разрешение на управление транспортом. Поля `actuation_allowed`, `commands_enabled`, `navigation_or_safety_accepted`, `production_accepted` у действующих portable definitions имеют значение false.
Новые эксперименты строятся через этот путь. Старые LAB V1/M4.x и их приложения не становятся основой новых пользовательских поверхностей. Их результаты, код квалификации и происхождение алгоритмов сохраняются как история. Использование действующего TGS executor, выросшего из M4.9, не требует возвращать старый интерфейс лаборатории.
Worker выключен. В этом аудите его не включали, Docker daemon на нём не опрашивали, ничего не устанавливали и не запускали. Факты разделены на код и текущую конфигурацию Core, локальный сохранённый каталог/журнал, исторические измерения и непроверенные возможности.
## 02. Что является источником правды
Для текущей реализации первичны `config/observatory-ai-modules.json`, `config/observatory-portable-run-definitions.json`, `config/observatory-worker-runtime-candidates.json`, `config/observatory-domain-ontology.json` и соответствующие исполнители в `src/k1link/observatory/`. Наличие записи `executor.state=ready` означает сохранённую регистрацию executor identity, а не работающую сейчас машину.
Машинный срез: [2026-09-05-ai-inference-evidence.json](2026-09-05-ai-inference-evidence.json). В нём сохранены каталожные identities, ресурсные профили, текущая композиция и отобранные поля локальных jobs. Снимок не содержит ключей доступа, исходного видео, облаков, весов моделей и полных runtime-логов.
Связанные решения: [ADR 0051](../adr/0051-modular-observatory-profiles.md), [история маршрута](../OBSERVATORY_REALTIME_PROFILES_EXECPLAN.md), [handoff 3 сентября](../../experiments/perception/OBSERVATORY_MODULAR_HANDOFF_2026-09-03.md), [runbook Worker](../runbooks/OBSERVATORY_PORTABLE_WORKER_006.md). Старые слова CURRENT/«следующий шаг» в исторических отчётах не являются новыми поручениями и не отменяют этот срез.
Ops MISSION CORE: #75 «AI Inference · Принципы работы и архитектура» (`e5768b6c-0817-4e9e-a786-f9167586c7dc`) с полным содержанием этого отчёта; #73 — история перехода к модульным профилям; #74 — подробный реестр кастомизации Rerun; #66 — канон Rerun; #9 — история AI Worker; #65 — историческая LAB V1. Новая карта не стирает свидетельства ошибок в старых картах. Статус Done у #75 означает завершение документирования среза; открытые пункты пользовательской/target-приёмки перечислены в checker и ниже.
## 03. Основные сущности и их владельцы
| Сущность | Значение и владелец |
|---|---|
| Физическая сессия | Запись оборудования: видео, LiDAR, pose/trajectory, временные шкалы, калибровка и provenance. Каталог сессий Core; не результат AI. |
| Версия модуля | Модель либо связанная алгоритмическая функция с точными image/code/model/contract identities, входами и выходами. Реестр модулей и sealed package. |
| CompositionSpec | Неизменяемый проверенный набор версий, параметров, зависимостей и execution policy; не привязан к одной конкретной записи. |
| LAB / composition run | Применение композиции к точному source snapshot; связывает состав, member jobs и опубликованные результаты. |
| Recorded job / attempt / lease | Единица выдачи работы и её конкретное владение исполнителем. Durable очередь Core, claim token и generation fencing. |
| Portable result | Неизменяемые артефакты и метаданные доказательства, identities, покрытие и authority. Публикуются на Core. |
| LAB display profile | Изменяемое оформление просмотра, отдельно от расчётной конфигурации и raw evidence. Хранится на Core по result_id. |
| Viewer session | Временное положение камеры, FOLLOW, включённые слои и пропорции окон. Не следует отождествлять с сохранением всего LAB profile. |
| Worker / installed executor | Доверенный исполнитель, которому разрешены конкретные версии packages и ресурсы. Не произвольная удалённая shell-машина из UI. |
Изменение цвета или размера точек не пересчитывает модель. Переименование отображаемой LAB не меняет immutable composition/result identity. Удаление из пользовательского каталога не следует трактовать как переписывание доказательства или автоматический Docker prune.
## 04. Пользовательский путь
Оператор выбирает сохранённую сессию. Core сообщает доступные каналы и применимость setup. Кнопка «Сконфигурировать AI-слой» открывает выбор по функциональным группам. UI получает каталог с сервера; он не извлекает возможности из свободного названия LAB.
Выбранные модули проходят проверку зависимостей и совместимости источника. Сохраняется точная композиция. Core создаёт либо использует уже существующие подходящие member jobs/results, показывает их совместный статус, а после публикации открывает связанный визуальный разбор. Повторный просмотр готовой LAB не должен запускать inference.
Название строки состоит из реальных конфигурационных значений. Название исходной сессии в строках списка не дублируется; в заголовке открытого результата сохраняется полный контекст. Дата и время расчёта, сортировка по времени, просмотр, переименование и удаление доступны в каталоге. Прогресс относится к активной обработке; готовая строка не должна навсегда оставаться шкалой 100%.
Глобальный смысл состояний: инициализация → передача на сервер → расчёт. Внутри расчёта могут быть подготовка камеры/LiDAR, загрузка модели, собственно inference и сборка результата. Эти подэтапы должны называться по фактической операции. Процент очереди/пакета нельзя интерпретировать как долю кадров модели или обещание точного ETA.
## 05. Каталог модулей и зависимости
| Модуль | Входы → выходы | Текущее назначение |
|---|---|---|
| camera-source | source.camera → camera.frames | Служебная подготовка камеры, добавляется зависимостью. Не отдельный пользовательский эксперимент. |
| DDRNet-39 · GOOSE | camera.frames → segmentation.mask | Семантическая сегментация выбранной версией DDRNet. |
| EoMT Large · Cityscapes | camera.frames → segmentation.mask | Альтернативный провайдер сегментации. |
| RF-DETR Large | camera.frames → detections.2d | Детекция объектов; текущий package содержит TensorRT engine. |
| Дистанция до объектов | detections.2d + source.calibration + source.lidar + source.pose → objects.ranged | Сопоставление детекций с калиброванными LiDAR/pose; собственных обученных весов нет. |
| TRAVEL TGS | source.calibration + source.lidar + source.pose → geometry.costmap + geometry.ground | Геометрическая обработка, ground/costmap; без отдельной ML-модели. |
В новой композиции допускается не более одного провайдера в группе. DDRNet и EoMT — альтернативы, не два одновременно выбранных segmentation provider. Зависимости включаются детерминированно; range требует RF-DETR. Циклы, неоднозначные провайдеры и пустой недопустимый граф отвергаются.
Группы motion и policy присутствуют в модели каталога, но в текущем реестре пусты. Это не доказательство установленных модулей движения или управления. Полный исторический perception prototype имел более широкий состав; его нельзя автоматически приписать текущему UI.
Разрешённые параметры расчёта ограничены версией модуля: у текущих stateless AI modules cadence допускает 1; у TGS causal history-seconds допускает 1 и действует reset-at-source-start. Это вычислительные контракты. Пользовательский slider накопления SLAM 0–500 секунд относится к отображению и не увеличивает расчётную историю TGS.
## 06. Граф: декларация и реальное исполнение
`modular_composition.py` проверяет capabilities, identities, параметры и топологический порядок. `modular_composition_store.py` сохраняет неизменяемую спецификацию. Execution policy текущих композиций: `recorded-observation-only`, `max_parallel_nodes=1`. `composition_runs.py` связывает source, composition и результаты запуска.
Важная граница реализации: `web/modular_observatory_api.py` переводит известный набор модулей в заранее поддержанные setup IDs. Это работающий ограниченный композитор, но ещё не универсальный runtime, который исполняет произвольный DAG из любого числа новых Docker-узлов под одной lease.
Текущие AI setup IDs: `ai-segmentation-ddrnet-v1`, `ai-segmentation-eomt-v1`, `ai-detection-rf-detr-v1`, `ai-range-object-distance-v1`; геометрия — `m49-tgs-portable-v2`. Когда выбран range, отдельный standalone RF-DETR job не создаётся: RF-DETR выполняется внутри range package. Поэтому полная выбранная конфигурация DDRNet + RF-DETR + range + TGS даёт три member jobs, а не четыре.
Подходящий ранее созданный non-failed job может быть использован снова; опубликованный member result связывается с новой композиционной проекцией. Точная повторная отправка композиции с существующей допустимой работой не должна размножать расчёты; конфликт сообщает API. Failed execution допускает повторную попытку по действующему маршруту.
Очередь отдельного job durable. Создание группы member jobs и запись composition-run projection не являются одной общей SQL-транзакцией универсального DAG. Нельзя обещать атомарность всей композиции на основании транзакционности очереди. Полноценное расширение scheduler и его аварийная приёмка остаются отдельной работой.
## 07. Схема коммуникации
```mermaid
flowchart LR
UI[Web UI: AI Inference] -->|same-origin HTTP| Core[Mission Core API :8000]
Core --> Catalog[Sessions / composition / ontology projection]
Core --> Queue[Durable recorded queue]
Worker[Installed Worker agent] -->|claim / renew / progress / terminal| Core
Core -->|verified source package| Worker
Worker -->|local Docker API| Steps[Sequential compute containers]
Steps -->|sealed output| Worker
Worker -->|manifest + verified member uploads| Core
Core --> Publish[Publication / artifact store / result catalogue]
Publish -->|base + overlay + profile| Viewer[Official Rerun in Web UI]
```
Браузер обращается к Core, не управляет Docker и не соединяется напрямую с Worker. Worker забирает работу у Core по HTTP pull-протоколу. Нынешний recorded-путь не отправляет каждый кадр через отдельный браузерный запрос или gRPC-поток: исходный пакет передаётся, вычислительные шаги работают с локальными входами, выход затем публикуется обратно.
Live telemetry оборудования — отдельный контур. Telegraf → MQTT → normalizer → Timescale → Core/System не заменяет HTTP job protocol. Свежая телеметрия не доказывает успешную публикацию LAB, а сохранённая LAB остаётся читаемой без работающего Worker.
## 08. Адресация, туннель и доверие
Файлы: `worker_http_transport.py`, `worker_tunnel_launchd.py`, `worker_container_proxy.py`, `worker_agent.py`. Текущий Core слушает локально `127.0.0.1:8000`. На Mac управляется SSH reverse tunnel через alias `mission-gpu`: `-R 127.0.0.1:18080:127.0.0.1:8000`, с BatchMode, ExitOnForwardFailure и keepalive.
Внутри agent container клиент обращается к loopback proxy :18080. Proxy направляет запросы на `host.docker.internal:18080`; на Windows host это loopback endpoint SSH-туннеля к Core. Следовательно, loopback HTTP защищён транспортом SSH на межмашинном участке. Здесь нет утверждения о публичном HTTP-порту Worker без защиты.
Transport принимает HTTPS либо HTTP только для loopback, передаёт Bearer auth и contour identity. Текущее исполнение привязано к `worker-006`. Два HTTP connection slots оставляют возможность служебного обмена при передаче пакета. Ключи, значения credentials и файлы с ними намеренно не входят в карту.
Это конкретная топология Mac Core ↔ Windows/Docker Desktop Worker. Наличие протокола не означает, что имя другого компьютера можно просто подставить в UI. Linux host networking и `host.docker.internal`, доверие SSH, токен, contour binding и установленный release потребуют согласованной адаптации. Реализация регистрации нового Worker в этот этап не входит.
## 09. Lease, очередь и восстановление
Worker вызывает `/api/v1/worker/observatory/recorded-jobs/claims` с claim schema v3 и перечнем поддержанных executor identities. При отсутствии работы получает 204. Затем идут start, lease renew, progress и terminal; upload result package имеет отдельные plan/member/complete операции.
Core сверяет source/definition/executor/resource/result contracts. Claim token и generation защищают от публикации запоздалым исполнителем. UI не может передать произвольный image, shell command, mount или network target через job. Вычислитель получает выбранный установленный package.
Ресурсные профили текущего Worker закрепляют последовательную работу на NVIDIA RTX 4090 и concurrency=1. Это не доказательство параллельного исполнения всех модулей. Политика допускает преимущество live-работы над recorded; текущие тяжёлые recorded jobs non-checkpointable. После вытеснения/ошибки до sealed результата нельзя обещать продолжение ровно с последнего кадра.
Worker имеет ограниченное восстановление транспортных ошибок и heartbeat; Core хранит durable job/publication state. Если вычисление завершено и результат запечатан, повтор публикации не должен повторять inference. Если результат ещё не запечатан, повторный запуск может начать обработку заново. История failed attempts сохраняется, а не становится фиктивным успехом при появлении следующего успешного результата.
## 10. Docker: что действительно упаковано
Нужно различать agent image, compute module image, installed package и реально запущенный контейнер. Agent опрашивает Core и управляет этапами. Compute container выполняет ограниченный шаг. Package закрепляет последовательность, изображения, assets, команды и contracts. Контейнерный ID — конкретный экземпляр на машине; его текущего значения этот offline-аудит не устанавливает.
Dockerfiles находятся в `experiments/perception/worker/observatory_portable/`: `Dockerfile.ai-module-camera-source`, `Dockerfile.ai-module-ddrnet`, `Dockerfile.ai-module-eomt`, `Dockerfile.ai-module-rf-detr`, `Dockerfile.ai-module-object-distance`, файлы installed-lab worker agent и специализированного M4.9 executor. Builder: `scripts/build_modular_ai_worker_release.py`. Исполнение: `installed_lab_packages.py`, `installed_lab_package_runner.py`, `modular_installed_package_steps.py`, installed worker service/container main; для TGS — `m49_worker_service.py` и соответствующий main.
Модульность сейчас прежде всего логическая и контрактная. Camera-source использует private base `ndc/mission-core-installed-lab-v1-eomt-step:ee0efdd9af72`; DDRNet — `ndc/mission-core-installed-lab-v1-ddrnet-step:439127908dba`; RF-DETR и object-distance опираются на `ndc-k1-perception-ddrnet39-rfdetr-tgs:stage1-joint-20260901`. Поэтому нельзя описывать каждый модуль как уже минимальный полностью независимый образ без наследованных окружений.
Некоторые FROM закреплены tag, хотя установленный release и готовые images проверяются по SHA. Для воспроизводимой чистой пересборки нужны именно соответствующие private bases, внешние assets и версии инструментов; один текст Dockerfile без них недостаточен. Отдельные conda/Python/model environments внутри compute stages остаются частью переносимого комплекта.
`ModuleSpec.docker_name` и ownership labels задают идентичность/наименование, а не доказывают наличие отдельного постоянно работающего сервиса на каждый модуль. В частности, TRAVEL TGS в текущем пути использует квалифицированный специализированный executor. Старые контейнеры LAB V1/других исследований не удалялись этой фиксацией.
## 11. Зафиксированные образы, модели и releases
SHA ниже взяты из текущих versioned registries; это конфигурационный срез, не сегодняшняя команда docker inspect на выключенном Worker.
| Модуль | Compute image SHA-256 |
|---|---|
| camera-source | da926459aee0a841bbdfaf80a0eb5fbead354c56794d1f3384eeba66d0a49e00 |
| DDRNet | 489fc7d1157fd0f1cd1d82e06a15737b7b2aaaf72b2ddb2aca2992b91a97488e |
| EoMT | 5b770178e4a5c8fbe8f8ddab3b83a598973dbe103b669851110b11a0918ab846 |
| RF-DETR | 2b8b44be8e9ee4060aa6997fc4c025ad7120f37ecd720a9e59b5e02ac6c90f66 |
| object-distance | 69d68f64981b41e5bcce1e642433e3d466b88c51942a5ba3aec9180d8ed04263 |
| TRAVEL TGS | f9278ab21aa65045be993dd19bffc25f49955e19598893ac78cc4761ca63ecf3 |
Веса DDRNet: `b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6`. EoMT weights: `c265da9a74f58f5c3f4826d23ca4ca78beac0b106cca5842beca61580de5b782`. RF-DETR TensorRT engine: `b8a40b3580edff001ec9680de68707242294ff590ab296000fae371f1083f695`. TensorRT engine не следует считать универсальным переносимым checkpoint для любого GPU/runtime.
У четырёх новых AI setup текущий executor image SHA `7a1d425b4678dcade7d7d6ffd14733d639a4df29f45e1759ba4c512e930da8ab`, release ID `ai-modular-installed-package-v1`, release SHA `97bfe743689766285b22627c4020d10df7949ef1f4546ef904dccb9ca4c6f721`. Все привязаны к worker-006.
TGS definition v3 использует image `f9278ab2…`, release `m49-tgs-portable-executor-v1`, release SHA `c5b0670d943fe0452ef4bbfbc144ab2439a1a674f9ef164798ad9f8b1ecc29fa`. Старая совместная LAB V1 definition v2 с executor `5ad7d95b…` и release `66785862…` остаётся в совместимом реестре; она не заменяет новые modular setups.
Важно сохранять provenance каждого результата: успешно опубликованный DDRNet member произведён предыдущим release `ecbb0edc1c4c3708329247a2210ef98dfa776bf948974e778ba6d131ad17a924`, хотя image agent совпадает. Range member использует текущий `97bfe743…`. Совпадение agent image не означает одинаковость sealed package. Каталоги `.runtime/*v8/v9/v10` — локальные артефакты сборки; наибольший номер папки не является источником истины о фактически установленном release.
## 12. Ресурсы и изоляция compute
Installed agent — доверенный оркестратор с доступом к Docker API/socket. Его нельзя описывать как полностью непривилегированный компонент без влияния на host.
Дочерние вычислительные контейнеры запускаются с ограничениями package runner: `network=none`, read-only root filesystem, drop ALL capabilities, no-new-privileges, без privileged mode. Входы, модели и проверенные code assets монтируются read-only; writable output ограничен каталогом шага. Заданы RAM/MemorySwap, CPU NanoCpus, Pids, SHM/tmpfs и GPU DeviceRequests. Точное значение бюджета зависит от resource profile/package, а не от свободного UI ввода.
GPU device admission не является жёсткой квотой VRAM. На имеющейся конфигурации действует последовательный допуск. Обещание безопасной параллельной работы N разных GPU моделей требует отдельного замера памяти и admission policy.
Историческая инвентаризация 3 сентября сообщала 11 containers, 7 running/4 stopped, 80 images, 9 volumes. Эти числа сохранены в архиве, но не являются текущим состоянием выключенного Worker. Другие исследования/сервисы, включая Gaussian и retained LAB packages, не следует автоматически считать зависимостями AI Inference или удалять по этой карте.
## 13. Передача данных и фактический кэш
Source package строится из конкретной сессии и проверенных members. Проверяются digest, размер и допустимость путей. `worker_source_cache.py` содержит source CAS (`.source-cas-v1`), который позволяет повторно использовать совпадающие исходные bytes. Кэш не разрешает смешивать похожие записи или произвольные версии калибровки.
Холодная подготовка остаётся существенной: загрузка camera archive завершается до extraction; декодирование/согласование камеры и LiDAR может предшествовать модельному этапу. Model-neutral camera-source убирает логическую зависимость подготовки от выбора segmentation, но не доказывает, что каждый отдельный job уже использует один готовый общий prepared-frame cache.
`portable_result_cache.py` и composition member reuse работают на уровне совпадающих сохранённых результатов. Чтение уже опубликованного результата не должно требовать GPU Worker.
Особенно важная проверка: `modular_node_cache.py` и `node_input_identity` существуют и покрыты тестами, но поиск production call sites обнаруживает определения и тесты без подключения `ModularNodeCache` к основному исполнителю. Поэтому универсальный кэш каждого узла композиции пока не заявляется работающей функцией. Старое намерение «каждый модуль считается один раз для всех LAB» ещё не равно реализации.
## 14. Результат и публикация
Результат связывает source snapshot, exact definition, module/package/model identities, временное покрытие и артефакты. `portable_artifact_transport.py` принимает manifest и members, `portable_result_publisher.py` создаёт опубликованную проекцию, `portable_publication_reconciler.py` доводит durable publication/outbox до согласованного состояния.
Результат проверки/расчёта и построенный для Rerun cache — разные артефакты. Смена renderer identity может потребовать перестроить производный cache; она не должна переписать исходные sealed results. Недоступный или неподходящий source должен давать явное состояние, а не демонстрационные точки вместо реальных данных.
Готовность полной LAB означает доступность требуемых member results по composition projection. Она не делает timestamps всех member jobs одинаковыми и не доказывает, что весь состав был вычислен одним совместным запуском. Сохранённая точная конфигурация важнее свободного названия строки.
## 15. Что действительно есть в текущем каталоге
Проверено через локальный Core API 5 сентября, без подключения Worker. Источник: `20260828T130511Z_viewer_live`, имя RAVNOVES004TREE, XGRIDS LixelKity K1, capture profile `xgrids-k1.viewer-live.fw-3.0.2.v1`, длительность 808.779 секунды (13:28.779).
В текущей проекции есть ready composition `ai-composition-33389babab33b801e8892f7b991683487eef2deea507486e52569fe943082e4b`, composition SHA `230396b858b09eea3d1d3a190c5e32d1d5e379da0058d32341026937fbb5cf24`. Создана 4 сентября в 06:59:35 UTC. Состав: DDRNet, RF-DETR, object-distance, TGS. Связаны три опубликованных member result; в UI также доступны отдельные сохранённые DDRNet и TGS строки.
| Member | Job | От создания job до публикации, UTC |
|---|---|---|
| DDRNet | observatory-run-ef3c14a64fca4d5a8674df82a5a0fca2 | 04.09 03:57:16.996 → 04:26:44.704; 29 мин 27.708 с |
| TRAVEL TGS | observatory-run-b230216709dc4c59bc56c98c7e329bf1 | 03.09 08:08:03.013 → 08:31:39.776; 23 мин 36.763 с |
| object-distance, включая RF-DETR | observatory-run-185e25280d58472ab8b4a0245a35c888 | 04.09 06:29:36.181 → 07:00:02.263; 30 мин 26.082 с |
Result IDs: `ai-layer-ddrnet-7c6a79942683933390f5ff0ecf2c6da1867d40032e91303746a567198772ce5c`; `m49-tgs-portable-review-a09d2b4a07d103e4f3693ba746a51be2197214768774eabfded4f109ae80dce4`; `ai-layer-object-distance-05f3931621585c9ac32132bef8c7afa961cea317cc29def09a8312339f8421e4`.
Это wall time конкретных успешных jobs, включая всё между enqueue и publication; это не model latency. Не надо складывать эти числа и называть суммой latency одного composition run: его members переиспользованы из разных дат.
История по этой сессии и setup при запросе до 100 jobs: DDRNet — 7, из них 1 succeeded/published и 6 failed; range — 7, из них 1 succeeded/published и 6 failed; TGS — 4, из них 1 succeeded/published, 1 succeeded с publication not-required и 2 failed. У новых standalone EoMT и RF-DETR setup — 0 jobs для этой сессии. Ноль здесь не означает отсутствия модели или старых экспериментов; успешный standalone recorded прогон ими в этом срезе не подтверждён. Действующие failures не стираются итоговой готовностью одной LAB.
## 16. Реальное покрытие и смысл измерений
Полная длительность источника и фактическое покрытие результатов должны быть отдельными полями. Исторический TGS handoff для этой записи указывает 6830 camera anchors, 6811 LiDAR matches и 19 unobserved; processing schedule примерно 39.215–757.160 секунды внутри источника 808.779 секунды. Надпись «полный маршрут» не должна скрывать начальные/конечные непокрытые интервалы и отсутствующие наблюдения.
В сохранённом TGS performance: candidate TGS p50=1.204 ms, p95=2.6075 ms, p99=3.2357 ms, max=4.651 ms. Более широкий stage wall: p50=17.676102 ms, p95=29.99172 ms, p99=36.24682261 ms, max=1269.499327 ms. Это разные границы измерения внутри алгоритма и обвязки; они не опровергают десятки минут enqueue→publish при подготовке записи.
Для честного сравнения нужно сохранять source rate, coverage, cold/warm режим, hardware/runtime identity, sample count и границы: queue wait; source transfer; decode/align; warmup; model/algorithm compute; serialize/seal; result upload/publication; replay preparation. Нельзя вычитать p95 одной фазы из p95 другой и получать корректный p95 остатка. FPS визуального воспроизведения Rerun тоже не является inference FPS.
Текущий recorded-first путь предназначен для воспроизводимых сравнений и сохранённых доказательств. Из имеющихся результатов не следует ни обещание полного real-time, ни утверждение, что модель сама считает один кадр две секунды. Долгие пользовательские ожидания из истории были реальными и должны оставаться частью performance backlog.
## 17. Предыдущий streaming experiment и его результат
Сохранены исследования `experiments/perception/worker/streaming_profile_stage1/`, [stage 1](../../experiments/perception/PERCEPTION_STREAM_STAGE1_2026-09-01.md), [cross-host graph](../../experiments/perception/PERCEPTION_STREAM_STAGE2_CROSSHOST_GRAPH_2026-09-02.md), [control clock](../../experiments/perception/PERCEPTION_STREAM_STAGE2_CONTROL_CLOCK_2026-09-02.md), [TLS attribution](../../experiments/perception/PERCEPTION_STREAM_STAGE2_TLS_ATTRIBUTION_2026-09-02.md), [LAN route](../../experiments/perception/PERCEPTION_STREAM_STAGE2_LAN_ROUTE_2026-09-02.md). Подробные receipts также перенесены из Desktop в архив.
Это отдельный resident perception prototype: DDRNet/RF-DETR, LiDAR/range, motion, TGS/costmap и policy stages, бинарный обмен gRPC/TLS и pacing источника 1×. Он не является текущим recorded HTTP worker protocol и не становится автоматически модулем motion/policy в сегодняшнем UI.
Исторический joint image: `986dbe7126992359c69da0ddda674925a5efe8e3429a6d5f60765f9c9ad34a4e`, tag `ndc-k1-perception-ddrnet39-rfdetr-tgs:stage1-joint-20260901`. Использовались model/code mounts; это не полностью автономный образ. Конкретный приёмочный фрагмент: 32 released/accepted results с byte-exact доставкой; fresh scene outputs — 12. Эти числа нельзя заменять фразой «32 полностью свежих результатов сцены».
На Worker локально compute→local receiver p95/p99 = 74.243/76.322 ms. Межмашинная граница Mac source-due→consumer-ready p95/p99 = 205.864/213.751 ms при gate 125 ms: FAIL. Min 86.598 ms, median 121.85 ms не превращают хвосты в PASS. Историческая проверка выявила Wi-Fi с обеих сторон и TCP tails 67.92191.142 ms ниже приложения; это основание изучать сеть, а не основание объявить всё задержкой модели. Истощение VRAM в этом конкретном опыте не было доказано.
Опыты показывают полезный compute budget и нерешённый end-to-end gate на тогдашней сети. Перенос resident runtime на будущий борт, совместимость другого GPU и абсолютный real-time не квалифицированы этим отчётом. Повторный streaming benchmark сейчас не запускался.
## 18. Локальная онтология и связи с оборудованием
В Mission Core уже есть предметная проекция: `config/observatory-domain-ontology.json` и `src/k1link/observatory/domain_ontology.py`. Она связывает transport/equipment/mount, capture profile, source session, module version/image, worker, composition, run/job/result, LAB view profile и layers/panes.
Она обслуживает согласованные запросы планирования, dispatch, публикации и replay: точная подпись конфигурации, состав member results, доступные слои и готовность. Идентичности берутся из существующих реестров/хранилищ; это не конкурирующая база, самовольно переименовывающая raw evidence.
Онтология отдельного NDC Platform repository не изменялась, runtime dependency на неё для AI Inference не добавлялась. Архитектурный принцип связанной модели применён локально. Формальное присутствие transport/equipment сущностей не равно готовой регистрации любого оборудования, универсальному драйверу RealSense или автоматическому конструктору 50 камер.
## 19. Rerun: один runtime, локальные контролы и сохранение
Полная самостоятельная карта: Ops #74 и [2026-09-05-rerun-customization-inventory.md](2026-09-05-rerun-customization-inventory.md), с [проверкой upstream](2026-09-05-rerun-upstream-evidence.json). В ней перечислены все действующие и архивные надстройки, точные файлы, хеши и upgrade gates. Здесь только роль в AI Inference.
Используется официальный Rerun 0.36.3; установленные JS/WASM и Python SDK в предыдущем аудите побайтно сверены с upstream. Recorded viewer живёт в same-origin iframe, имеет один native renderer/store/clock. Камера и spatial — виды внутри общего viewer. Внешний SplitPane владеет разделением, контролы принадлежат своим секциям, native layout получает согласованную долю. Верхняя панель переносит не помещающиеся группы; refresh/fullscreen относятся к общему layout.
Слои строятся из capabilities результата: фон КАМЕРА независим от segmentation и РАМОК; кнопка рамок зависит от detections; TGS от geometry evidence. Отключённый фон камеры не должен выключать остальные 2D layers. Один тип источника допускает одно окно. Сегодня реализованы camera/spatial и single-pane варианты, а не произвольное дерево из 50 камер.
ИСХ. ТОЧКИ и ЛОК. SLAM сейчас используют одно sealed `/world/points`. Отличаются отображение/накопление и дополнительные trajectory controls; это не две независимые коллекции «математические» и «декоративные». Изменения размера/цвета не меняют raw/AI расчёт.
Надстройка FOLLOW и восстановления eye использует прикладной журнал native gestures и blueprint. Это не официальный универсальный get-camera-pose API. Не все gestures покрыты: WASD, double-click/picking-fit, inertia могут расходиться с журналом. Такие ограничения явно оставлены в #74; этот документ не объявляет все пользовательские сценарии зума принятыми.
Server-side LAB display profile сохраняет point_size, accumulation_seconds, color_mode, palette, show_grid, show_labels, show_camera_frustums отдельно от immutable result. Применение point size/накопления/цвета/grid подключено; show_labels и show_camera_frustums сохраняются, но визуально не подключены к текущему canonical LAB пути. Layer toggles, FOLLOW, eye и split ratio в этот durable profile не входят.
Slider накопления 0–500 s и точный ввод конечного неотрицательного значения без верхнего product cap; размер slider 0.1–10 px, точный ввод ≥0.1 без верхнего cap. Закрытие настроек отправляет PUT; ошибка не должна блокировать закрытие и показывается компактным сообщением. Только успешная серверная запись подтверждает сохранение после очистки локального кэша. Сохранение в памяти/localStorage само по себе этого не доказывает.
## 20. Переносимость — что возможно и чего ещё нет
| Объект переноса | Реальное условие |
|---|---|
| Просмотр готовых LAB на другом Core | Перенести каталог, source/result artifacts, lineage и profiles с сохранением identities; обеспечить renderer/SDK и восстановление производных caches. Worker для просмотра не требуется. |
| Та же композиция на другой записи K1 | Источник обязан пройти admission по требуемым каналам, калибровке, media epoch/codec, геометрии и timestamps. Один совпавший label недостаточен. |
| GPU-модули на другом AI Worker | Нужны compatible CPU architecture/GPU/CUDA/TensorRT, exact images, private bases для rebuild, models/code assets, installed package, resource profiles и протокол связи. Не один docker load. |
| Worker с другим именем/contour | Сейчас имеются worker-006 bindings и проверки. Общая динамическая регистрация/автовыбор любого Worker не заявляется готовой. В эту задачу не входит. |
| Linux вместо Windows Docker Desktop | Нужна проверка network/host bridge, paths, mounts, GPU runtime и SSH topology; host.docker.internal нельзя молча считать одинаковым. |
| Новая модель | Требуются ModuleSpec, versioned image/contract, adapter/installed steps, setup projection, input/result verification, capability→viewer mapping и evidence. Сейчас UI не универсальный marketplace Docker images. |
| Другое оборудование / 50 камер | Нужны source adapters, calibration/time contracts, admission и расширение layout/ресурсной модели. Сущности онтологии дают место для этого, но не готовую реализацию. |
| Бортовой real-time | Resident prototype, recorded LAB и бортовая qualification — разные границы. Нужен отдельный измеренный deployment на выбранном target. |
Переносимость достигнута в identities, пакетах, протоколах и сохранённых результатах. Привязки к Worker-006, K1 и имеющимся окружениям остаются конкретными. Утверждение «полностью независимо от host» сегодня было бы неточным. Изменять эти границы ради красивого отчёта без работающего Worker не стали.
## 21. Архив Desktop без потери контекста
Два относящихся к AI Inference документа перенесены побайтно в `docs/handoff/ai-inference-source-documents/` и снабжены [manifest.json](../handoff/ai-inference-source-documents/manifest.json). Это полные исходные тексты, включая ошибки, планы, замеры, списки Docker и последовательные обновления; не только краткий пересказ.
| Исходный файл Desktop | Bytes | SHA-256 |
|---|---:|---|
| _MISSING_CORE_MODULAR_AUDIT_AND_PLAN_2026-09-03.md | 53637 | d6c201d083fbec4b1db031379b515ff821a09ccfa0cea62443e211a9d76cb1c2 |
| _MISSING_CORE_OBSERVATORY_DOCKER_LABS_FINAL_STATUS_2026-09-01.md | 330260 | 45e870700baddab8f31a2f0f0bfe1f9e99e8e73a490195c1e6a3beb5265e49ee |
Другие документы на Desktop не объявляются перенесёнными этой картой. Исходники не удалялись автоматически. После публикации commit пользователь может удалить именно эти два оригинала: versioned копии и хеши остаются в репозитории, а их актуальная интерпретация — здесь и в Ops.
Исторические указания из этих файлов не исполняются как команды. Раннее требование «весь профиль в одном монолитном образе» заменено ADR 0051. Историческое описание node cache как цели отделено от фактического отсутствия production wiring. Старые Docker inventories и streaming receipts датированы; не выдаются за результаты сегодняшнего запуска.
## 22. Проверки этого изменения и открытые границы
Для переименования выполнены архитектурные frontend tests (4 passed), полный frontend typecheck, полный unit suite (759 passed), production build и targeted Python tests `test_modular_observatory_api.py`/`test_observatory_setups.py` (22 passed). Изменения runtime поведения и новые вычислительные jobs в этом этапе не выполнялись.
В открытом in-app browser обновлена сборка и пройден путь LAB → AI Inference. Новые sidebar label, eyebrow, title и aria-подсказки удаления подтверждены реальным UI. Проверены обычный и развёрнутый shell, три сохранённых строки с датами/действиями; открыта полная сохранённая конфигурация с камерой, DDRNet, рамками и TGS. Fullscreen самого результата и возврат по Escape проверены. Escape на shell сам по себе не меняет его состояние; это не объявляется успешным закрытием shell. Текущая задача не меняет политику Escape/диалогов. Реальная сохранённая конфигурация оставляется для просмотра владельцем.
Срез временно закрыт по документации. Открыты: окончательная пользовательская приёмка навигации Rerun и настроек; два неподключённых display fields; полный native camera-state API вместо неполного gesture journal; универсальный multi-pane constructor; универсальное исполнение DAG/production node cache; новые Worker/оборудование и target CUDA qualification; end-to-end real-time gate и полноценные cold/warm phase metrics. Это границы текущего продукта, не скрыто выполненные пункты.
При возобновлении работы исходная точка — этот срез, actual registry и конкретные new measurements. Legacy LAB приложения автоматически не возвращаются; неизвестные состояния выключенного Worker сначала проверяются после его появления. Любое следующее обновление Rerun проходит отдельно по карте #74.
## 23. Изменённые файлы и эксплуатационная фиксация
Переименование: `apps/control-station/src/productModel.ts`, `components/laboratory/LaboratoryPresentation.tsx`, `workspaces/observatory/ObservatoryWorkspace.tsx`, `core/observatory/{aiComposition,catalogMutations,useObservatoryCatalog}.ts` внутри frontend; `src/k1link/observatory/setups.py`, `src/k1link/web/{observatory_api,modular_observatory_api}.py`. Обновлены ожидания существующих `observatoryWorkspace.test.mjs` и `observatoryCatalogMutations.test.mjs`. Дизайн, identifiers, параметры расчёта и бинарные модели не изменены.
Документация: этот отчёт, JSON evidence, README/manifest и две полные копии в `docs/handoff/ai-inference-source-documents/`; указатели текущего среза в ADR 0051 и историческом ExecPlan. Ops #75 создана как текущая архитектурная карта; #73 переименована в историческую карту с указателем #75 и сохранением всех прежних блоков.
Production frontend bundle пересобран. Канонический локальный LaunchAgent `com.nodedc.mission-core.local` перезапущен из того же checkout для применения Python-текстов. `/api/health` на :8000 подтверждает operational=true, plugin runtimes 1/1, готовность источников и artifact store. Новый сервер на другом порту не создавался; удалённый Worker не запускался. Код и архив публикуются в main обычным commit/push без переписывания истории. Точный итоговый commit указывается в финальном блоке Ops #75.
@@ -0,0 +1,850 @@
{
"snapshot_date": "2026-09-05T06:51:04.590227+00:00",
"code_baseline": "e56eb42507d005cc372ac4a53785a080b116e227",
"worker_live_inspection": false,
"source_session_id": "20260828T130511Z_viewer_live",
"modules_registry": {
"schema_version": "missioncore.observatory-ai-module-registry/v1",
"modules": [
{
"module_id": "camera-source",
"label": "Подготовка камеры K1",
"group": "preparation",
"image_sha256": "da926459aee0a841bbdfaf80a0eb5fbead354c56794d1f3384eeba66d0a49e00",
"implementation_sha256": "a0b1a74887e5f1cf78e867f81f246bae08e872fed320a2939986c17913418524",
"model_sha256": null,
"contract_sha256": "87c9e8864f9469719e69bfd750c418e077944a6260ffc6fd3ce12daf4a1da7d5",
"requires": [
"source.camera"
],
"provides": [
"camera.frames"
],
"optional_inputs": [],
"parameter_choices": {
"cadence": [
1
]
},
"defaults": {
"cadence": 1
},
"state_policy": "stateless"
},
{
"module_id": "ddrnet",
"label": "DDRNet-39 · GOOSE",
"group": "segmentation",
"image_sha256": "489fc7d1157fd0f1cd1d82e06a15737b7b2aaaf72b2ddb2aca2992b91a97488e",
"implementation_sha256": "9a3fceb65374ccc3dccdbe02691c2b62376ff3a3a6d16439cb9f6266e73c78b0",
"model_sha256": "b99c2838051bcd7b092fd3970aa62a77d5c0bbb809c9b9afb2ff4b0ebdaa4ee6",
"contract_sha256": "197c9d7dd0f55f79992215a57e450c5442f3d1510d74083bcf123577f85da199",
"requires": [
"camera.frames"
],
"provides": [
"segmentation.mask"
],
"optional_inputs": [],
"parameter_choices": {
"cadence": [
1
]
},
"defaults": {
"cadence": 1
},
"state_policy": "stateless"
},
{
"module_id": "eomt",
"label": "EoMT Large · Cityscapes",
"group": "segmentation",
"image_sha256": "5b770178e4a5c8fbe8f8ddab3b83a598973dbe103b669851110b11a0918ab846",
"implementation_sha256": "17ac471d5c51f70b3af6fb6046e1880c731691253c338b1626702ce4ca375d2b",
"model_sha256": "c265da9a74f58f5c3f4826d23ca4ca78beac0b106cca5842beca61580de5b782",
"contract_sha256": "09ca841400b08af0607d19d346f78ab768567256c8c58789a6ade4ede8f425a0",
"requires": [
"camera.frames"
],
"provides": [
"segmentation.mask"
],
"optional_inputs": [],
"parameter_choices": {
"cadence": [
1
]
},
"defaults": {
"cadence": 1
},
"state_policy": "stateless"
},
{
"module_id": "tgs",
"label": "TRAVEL TGS · облако и карта проходимости",
"group": "geometry",
"image_sha256": "f9278ab21aa65045be993dd19bffc25f49955e19598893ac78cc4761ca63ecf3",
"implementation_sha256": "52813392aabd02efc5c2b8f7c22ed88e3ef4cc8ad3aafeba2792efe503e29fe9",
"model_sha256": null,
"contract_sha256": "9dd80c8e2504559d2156fca933de6eb27901e35305e6853aeb84707e1cb13892",
"requires": [
"source.calibration",
"source.lidar",
"source.pose"
],
"provides": [
"geometry.costmap",
"geometry.ground"
],
"optional_inputs": [],
"parameter_choices": {
"history-seconds": [
1
]
},
"defaults": {
"history-seconds": 1
},
"state_policy": "causal-reset-at-source-start"
},
{
"module_id": "rf-detr",
"label": "RF-DETR Large · рамки объектов",
"group": "detection",
"image_sha256": "2b8b44be8e9ee4060aa6997fc4c025ad7120f37ecd720a9e59b5e02ac6c90f66",
"implementation_sha256": "4eb580eb938164bf0624e94fdc3b046aacf32fb8022c93c67fa26bab7c3d19d0",
"model_sha256": "b8a40b3580edff001ec9680de68707242294ff590ab296000fae371f1083f695",
"contract_sha256": "815d0afd24355da3a462e0423dab8284165c89cebd136d7c8584a32602178b96",
"requires": [
"camera.frames"
],
"provides": [
"detections.2d"
],
"optional_inputs": [],
"parameter_choices": {
"cadence": [
1
]
},
"defaults": {
"cadence": 1
},
"state_policy": "stateless"
},
{
"module_id": "object-distance",
"label": "Дистанция до объектов · K1 LiDAR",
"group": "range",
"image_sha256": "69d68f64981b41e5bcce1e642433e3d466b88c51942a5ba3aec9180d8ed04263",
"implementation_sha256": "0e3e426e2f768bc019a3715a50fc77a88626869abd9fa919e1aef5763d0c53da",
"model_sha256": null,
"contract_sha256": "5a6e446f009420352587f83388331b368d00950ab2fb896c6350aaa9b31c2e2e",
"requires": [
"detections.2d",
"source.calibration",
"source.lidar",
"source.pose"
],
"provides": [
"objects.ranged"
],
"optional_inputs": [],
"parameter_choices": {
"cadence": [
1
]
},
"defaults": {
"cadence": 1
},
"state_policy": "stateless"
}
]
},
"configured_definitions": [
{
"setup_id": "lab-v1-eomt-ddrnet-portable-v1",
"definition_sha256": "269d71a24b4e63cff54e01273f9d4b35fc6cdd72bc6fadec206169ae0777e6ac",
"version": 2,
"executor": {
"contour_id": "worker-006",
"image_sha256": "5ad7d95baac63af13812cb693d492add4e806a333aba8e60edb2ea1aba754373",
"reason": null,
"reason_code": null,
"release_id": "lab-v1-installed-package-v1",
"release_sha256": "667858623962cd6d9849a8985b803f59e429916b5c56f76a6fc6c80c0c54526b",
"state": "ready"
},
"resource_profile": {
"accelerator_id": "nvidia-rtx-4090",
"allowed_checkpoints": [],
"checkpoint_policy": "non-checkpointable",
"concurrency": 1,
"contour_id": "worker-006",
"profile_id": "worker006-single-gpu-sequential-ai-v1",
"profile_sha256": "7468138cad115210eda18e7a3350e3423d3d39ac0aae650b3266cdc2bc63fd5d",
"schema_version": "missioncore.observatory-portable-resource-profile/v2"
}
},
{
"setup_id": "m49-tgs-portable-v2",
"definition_sha256": "f56d6321bd794ccdfb7d2e3b05d044b11f616ffb81ee29517386cc253046d4eb",
"version": 3,
"executor": {
"contour_id": "worker-006",
"image_sha256": "f9278ab21aa65045be993dd19bffc25f49955e19598893ac78cc4761ca63ecf3",
"reason": null,
"reason_code": null,
"release_id": "m49-tgs-portable-executor-v1",
"release_sha256": "c5b0670d943fe0452ef4bbfbc144ab2439a1a674f9ef164798ad9f8b1ecc29fa",
"state": "ready"
},
"resource_profile": {
"accelerator_id": "cpu-only",
"allowed_checkpoints": [],
"checkpoint_policy": "non-checkpointable",
"concurrency": 1,
"contour_id": "worker-006",
"profile_id": "worker006-cpu-single-run-portable-v2",
"profile_sha256": "49e373f1cbf314e7fab2d176db295f3d3d9ddbbcbd724bbde988ef60ad767dee",
"schema_version": "missioncore.observatory-portable-resource-profile/v2"
}
},
{
"setup_id": "ai-segmentation-ddrnet-v1",
"definition_sha256": "04dd11b9bca4956bc253c970a9020a5fac80e9ef5981ff1fffc32b9646087fec",
"version": 1,
"executor": {
"contour_id": "worker-006",
"image_sha256": "7a1d425b4678dcade7d7d6ffd14733d639a4df29f45e1759ba4c512e930da8ab",
"reason": null,
"reason_code": null,
"release_id": "ai-modular-installed-package-v1",
"release_sha256": "97bfe743689766285b22627c4020d10df7949ef1f4546ef904dccb9ca4c6f721",
"state": "ready"
},
"resource_profile": {
"accelerator_id": "nvidia-rtx-4090",
"allowed_checkpoints": [],
"checkpoint_policy": "non-checkpointable",
"concurrency": 1,
"contour_id": "worker-006",
"profile_id": "worker006-single-gpu-sequential-ai-v1",
"profile_sha256": "7468138cad115210eda18e7a3350e3423d3d39ac0aae650b3266cdc2bc63fd5d",
"schema_version": "missioncore.observatory-portable-resource-profile/v2"
}
},
{
"setup_id": "ai-segmentation-eomt-v1",
"definition_sha256": "387f42bdf707b0e3e357fec1cfb5aa90a64133ebf0095f9b01d749ca2364d47c",
"version": 1,
"executor": {
"contour_id": "worker-006",
"image_sha256": "7a1d425b4678dcade7d7d6ffd14733d639a4df29f45e1759ba4c512e930da8ab",
"reason": null,
"reason_code": null,
"release_id": "ai-modular-installed-package-v1",
"release_sha256": "97bfe743689766285b22627c4020d10df7949ef1f4546ef904dccb9ca4c6f721",
"state": "ready"
},
"resource_profile": {
"accelerator_id": "nvidia-rtx-4090",
"allowed_checkpoints": [],
"checkpoint_policy": "non-checkpointable",
"concurrency": 1,
"contour_id": "worker-006",
"profile_id": "worker006-single-gpu-sequential-ai-v1",
"profile_sha256": "7468138cad115210eda18e7a3350e3423d3d39ac0aae650b3266cdc2bc63fd5d",
"schema_version": "missioncore.observatory-portable-resource-profile/v2"
}
},
{
"setup_id": "ai-detection-rf-detr-v1",
"definition_sha256": "598ce44f087c392ee95a024c3c45c95bdd02ad8530a3ccbac13422c2ad2f4a94",
"version": 1,
"executor": {
"contour_id": "worker-006",
"image_sha256": "7a1d425b4678dcade7d7d6ffd14733d639a4df29f45e1759ba4c512e930da8ab",
"reason": null,
"reason_code": null,
"release_id": "ai-modular-installed-package-v1",
"release_sha256": "97bfe743689766285b22627c4020d10df7949ef1f4546ef904dccb9ca4c6f721",
"state": "ready"
},
"resource_profile": {
"accelerator_id": "nvidia-rtx-4090",
"allowed_checkpoints": [],
"checkpoint_policy": "non-checkpointable",
"concurrency": 1,
"contour_id": "worker-006",
"profile_id": "worker006-single-gpu-sequential-ai-v1",
"profile_sha256": "7468138cad115210eda18e7a3350e3423d3d39ac0aae650b3266cdc2bc63fd5d",
"schema_version": "missioncore.observatory-portable-resource-profile/v2"
}
},
{
"setup_id": "ai-range-object-distance-v1",
"definition_sha256": "af5e637b78c670930b60cd4527b611aba4af601e6da58aa4dc8326ea6e13c5c2",
"version": 1,
"executor": {
"contour_id": "worker-006",
"image_sha256": "7a1d425b4678dcade7d7d6ffd14733d639a4df29f45e1759ba4c512e930da8ab",
"reason": null,
"reason_code": null,
"release_id": "ai-modular-installed-package-v1",
"release_sha256": "97bfe743689766285b22627c4020d10df7949ef1f4546ef904dccb9ca4c6f721",
"state": "ready"
},
"resource_profile": {
"accelerator_id": "nvidia-rtx-4090",
"allowed_checkpoints": [],
"checkpoint_policy": "non-checkpointable",
"concurrency": 1,
"contour_id": "worker-006",
"profile_id": "worker006-single-gpu-sequential-ai-object-distance-v1",
"profile_sha256": "c244efed459915508044fed4ef0e73c810fbe750e5e379d06723f734bd4385ca",
"schema_version": "missioncore.observatory-portable-resource-profile/v2"
}
}
],
"composition_runs": {
"schema_version": "missioncore.observatory-ai-composition-run-list/v1",
"items": [
{
"schema_version": "missioncore.observatory-ai-composition-run/v1",
"run_id": "ai-composition-33389babab33b801e8892f7b991683487eef2deea507486e52569fe943082e4b",
"source_session_id": "20260828T130511Z_viewer_live",
"composition_sha256": "230396b858b09eea3d1d3a190c5e32d1d5e379da0058d32341026937fbb5cf24",
"module_ids": [
"tgs",
"ddrnet",
"rf-detr",
"object-distance"
],
"setup_ids": [
"ai-segmentation-ddrnet-v1",
"m49-tgs-portable-v2",
"ai-range-object-distance-v1"
],
"job_ids": [
"observatory-run-ef3c14a64fca4d5a8674df82a5a0fca2",
"observatory-run-b230216709dc4c59bc56c98c7e329bf1",
"observatory-run-185e25280d58472ab8b4a0245a35c888"
],
"created_at_utc": "2026-09-04T06:59:35.000Z",
"state": "ready",
"configuration_label": "RAVNOVES004TREE · DDRNet-39 · GOOSE · RF-DETR Large · TRAVEL TGS · Дистанция до объектов · K1 LiDAR",
"display_name": "DDRNet-39 · GOOSE · RF-DETR Large · TRAVEL TGS · Дистанция до объектов · K1 LiDAR",
"presentation": {
"schema_version": "missioncore.observatory-presentation-projection/v1",
"modules": [
{
"module_id": "ddrnet",
"label": "DDRNet-39 · GOOSE"
},
{
"module_id": "rf-detr",
"label": "RF-DETR Large"
},
{
"module_id": "tgs",
"label": "TRAVEL TGS"
},
{
"module_id": "object-distance",
"label": "Дистанция до объектов · K1 LiDAR"
}
],
"configuration_label": "DDRNet-39 · GOOSE · RF-DETR Large · TRAVEL TGS · Дистанция до объектов · K1 LiDAR",
"viewer_layers": [
{
"layer_id": "camera.source",
"pane_id": "camera",
"label": "КАМЕРА",
"control": "toggle",
"order": 10
},
{
"layer_id": "camera.ddrnet",
"pane_id": "camera",
"label": "DDRNET",
"control": "toggle",
"order": 20
},
{
"layer_id": "camera.detections",
"pane_id": "camera",
"label": "РАМКИ",
"control": "toggle",
"order": 40
},
{
"layer_id": "spatial.source-points",
"pane_id": "spatial",
"label": "ИСХ. ТОЧКИ",
"control": "toggle",
"order": 10
},
{
"layer_id": "spatial.local-slam",
"pane_id": "spatial",
"label": "ЛОК. SLAM",
"control": "toggle-with-settings",
"order": 20
},
{
"layer_id": "spatial.tgs",
"pane_id": "spatial",
"label": "TGS",
"control": "toggle",
"order": 30
}
]
},
"jobs": [
{
"schema_version": "missioncore.observatory-recorded-job/v1",
"job_id": "observatory-run-ef3c14a64fca4d5a8674df82a5a0fca2",
"idempotency_key": "ai-layer:fba5a33f38ba5beace38e4a4e99b4a468d2d6d760370027a9a6563b3c1279eae",
"request_sha256": "16c22588dc443c1296782a4c4034fb895f888fddc8777a6d892b9f94da99b064",
"identity_sha256": "47ddde3a49a77e9783a0ffaddff5f3219a0dc0cace1b77dbf71610575d5973b6",
"submission_receipt_sha256": "8d7267ed9f652054fc9b42afb5faa341195d3fcbaad7a3f4fcb3979f827d91da",
"source": {
"session_id": "20260828T130511Z_viewer_live",
"catalog_sha256": "2db6b8f109f5cc31bb32733ca633e03becca83d1f140a68ecc9ec9522010c24e",
"bundle_sha256": "ee8aa75ff7fbf747ad62161d6e3bc83e291253e6df219a4d1b3a07bc69c79e84",
"capability_manifest_sha256": "a4adc08ab0f867fcf7992aacaedd63328c9af222c829238c3f6e58903b95fa5e",
"adapter": {
"adapter_id": "xgrids-k1-recorded-ai-layer-v1",
"version": 1,
"adapter_sha256": "2b8e624b2b16b00c9dd75b96e4c56c5438aa6889b0b2fa7a2b2da39d6aa81c6e"
}
},
"setup": {
"setup_id": "ai-segmentation-ddrnet-v1",
"definition_id": "ai-segmentation-ddrnet",
"definition_version": 1,
"definition_sha256": "e2f1b59e8680e0ad7e715cf61cac1bfe53b183429f933a65fd3ec22e1e198f16"
},
"executor": {
"release_id": "ai-modular-installed-package-v1",
"release_sha256": "ecbb0edc1c4c3708329247a2210ef98dfa776bf948974e778ba6d131ad17a924",
"image_sha256": "7a1d425b4678dcade7d7d6ffd14733d639a4df29f45e1759ba4c512e930da8ab",
"model_release_ids": [
"lab-v1-ddrnet-39-goose-fine-64-v1"
],
"learned_models": [
"lab-v1-ddrnet-39-goose-fine-64-v1"
],
"model_manifest_sha256": "c9144b30d054e3d495961486a4aed70ae5f60bcadadb4e3309865ced4123739e",
"resource_profile_id": "worker006-single-gpu-sequential-ai-v1",
"resource_profile_sha256": "7468138cad115210eda18e7a3350e3423d3d39ac0aae650b3266cdc2bc63fd5d"
},
"checkpoint_policy": {
"mode": "non-checkpointable",
"allowed_checkpoints": [],
"last_checkpoint_id": null
},
"priority": {
"class": "recorded",
"rank": 100,
"server_owned": true
},
"state": "succeeded",
"preemption_requested": false,
"restart_from_zero": false,
"preemption_receipt_sha256": null,
"claim_generation": 1,
"claim_lease": null,
"result": {
"result_id": "ai-layer-ddrnet-7c6a79942683933390f5ff0ecf2c6da1867d40032e91303746a567198772ce5c",
"sha256": "cbc433c51f49c63f45673f53ab5491d1cdbca04f2da7c5c9515c9f47c61cf01e"
},
"terminal": {
"code": "result-sealed",
"message": "Recorded result was sealed by the Worker."
},
"publication": {
"state": "published",
"attempts": 1,
"error": null,
"published_at_utc": "2026-09-04T04:26:44.704Z"
},
"created_at_utc": "2026-09-04T03:57:16.996Z",
"updated_at_utc": "2026-09-04T04:26:44.704Z",
"authority": {
"commands_enabled": false,
"actuation_allowed": false,
"navigation_or_safety_accepted": false,
"production_accepted": false
}
},
{
"schema_version": "missioncore.observatory-recorded-job/v1",
"job_id": "observatory-run-b230216709dc4c59bc56c98c7e329bf1",
"idempotency_key": "observatory-ui:8966e8a8-cfde-4ff1-9361-e6becd9f0a87",
"request_sha256": "b18a41134bfc18d007b2d94aed7b71dcfdb51791ae1f1f78bf8665c719a33c59",
"identity_sha256": "bbf59ed8c0087b17e14b0f5f5ea903456e17f05bd4c7608744c05671c4e1382b",
"submission_receipt_sha256": "72b4d576ec79cf9df64d8a7c1f9c4decd316c52c1f0dcd48438dc3323cc4642b",
"source": {
"session_id": "20260828T130511Z_viewer_live",
"catalog_sha256": "2db6b8f109f5cc31bb32733ca633e03becca83d1f140a68ecc9ec9522010c24e",
"bundle_sha256": "2412ee2374590a3b0bca8849a2410188325397b1651b7ae2916c48ead664c417",
"capability_manifest_sha256": "c7c23096144bbb28b62edb1a8dad1b916decfac82c781687d22380721cafba96",
"adapter": {
"adapter_id": "xgrids-k1-recorded-observatory-v2",
"version": 2,
"adapter_sha256": "4e12be6d2503e2e237eddb290b28d6a7d16cf983855b6d8e6b4e3b65d2feb0de"
}
},
"setup": {
"setup_id": "m49-tgs-portable-v2",
"definition_id": "m49-tgs-portable",
"definition_version": 3,
"definition_sha256": "f56d6321bd794ccdfb7d2e3b05d044b11f616ffb81ee29517386cc253046d4eb"
},
"executor": {
"release_id": "m49-tgs-portable-executor-v1",
"release_sha256": "c5b0670d943fe0452ef4bbfbc144ab2439a1a674f9ef164798ad9f8b1ecc29fa",
"image_sha256": "f9278ab21aa65045be993dd19bffc25f49955e19598893ac78cc4761ca63ecf3",
"model_release_ids": [],
"learned_models": [],
"model_manifest_sha256": "489a43448f720a9b5c7993dc8279d167b77191a586f0d87b6d38b81cf728e2f1",
"resource_profile_id": "worker006-cpu-single-run-portable-v2",
"resource_profile_sha256": "49e373f1cbf314e7fab2d176db295f3d3d9ddbbcbd724bbde988ef60ad767dee"
},
"checkpoint_policy": {
"mode": "non-checkpointable",
"allowed_checkpoints": [],
"last_checkpoint_id": null
},
"priority": {
"class": "recorded",
"rank": 100,
"server_owned": true
},
"state": "succeeded",
"preemption_requested": false,
"restart_from_zero": false,
"preemption_receipt_sha256": null,
"claim_generation": 1,
"claim_lease": null,
"result": {
"result_id": "m49-tgs-portable-review-a09d2b4a07d103e4f3693ba746a51be2197214768774eabfded4f109ae80dce4",
"sha256": "52e8afd6aaa38b615008463b873b94feae160946a69ce67aba12efc5f12b1589"
},
"terminal": {
"code": "result-sealed",
"message": "Recorded result was sealed by the Worker."
},
"publication": {
"state": "published",
"attempts": 1,
"error": null,
"published_at_utc": "2026-09-03T08:31:39.776Z"
},
"created_at_utc": "2026-09-03T08:08:03.013Z",
"updated_at_utc": "2026-09-03T08:31:39.776Z",
"authority": {
"commands_enabled": false,
"actuation_allowed": false,
"navigation_or_safety_accepted": false,
"production_accepted": false
}
},
{
"schema_version": "missioncore.observatory-recorded-job/v1",
"job_id": "observatory-run-185e25280d58472ab8b4a0245a35c888",
"idempotency_key": "ai-layer:502ec972ec9e6d190720d1e820e6b204066ed31c560baf571797e6aed74b154b",
"request_sha256": "bf3cd7b4dd0738f1a52341ccd4b9cc39db542e83c2c7ce1dda31a80c4932bc8d",
"identity_sha256": "568a9d42642aee9ce798c5e2f8920651d1fd9b383293345a2a7ab322685900f2",
"submission_receipt_sha256": "e568e257e941e63a3e84b95311fa15e33dcf31defacacaa55b5a617c6a8731a7",
"source": {
"session_id": "20260828T130511Z_viewer_live",
"catalog_sha256": "2db6b8f109f5cc31bb32733ca633e03becca83d1f140a68ecc9ec9522010c24e",
"bundle_sha256": "2412ee2374590a3b0bca8849a2410188325397b1651b7ae2916c48ead664c417",
"capability_manifest_sha256": "c7c23096144bbb28b62edb1a8dad1b916decfac82c781687d22380721cafba96",
"adapter": {
"adapter_id": "xgrids-k1-recorded-observatory-v2",
"version": 2,
"adapter_sha256": "4e12be6d2503e2e237eddb290b28d6a7d16cf983855b6d8e6b4e3b65d2feb0de"
}
},
"setup": {
"setup_id": "ai-range-object-distance-v1",
"definition_id": "ai-range-object-distance",
"definition_version": 1,
"definition_sha256": "af5e637b78c670930b60cd4527b611aba4af601e6da58aa4dc8326ea6e13c5c2"
},
"executor": {
"release_id": "ai-modular-installed-package-v1",
"release_sha256": "97bfe743689766285b22627c4020d10df7949ef1f4546ef904dccb9ca4c6f721",
"image_sha256": "7a1d425b4678dcade7d7d6ffd14733d639a4df29f45e1759ba4c512e930da8ab",
"model_release_ids": [
"rf-detr-large-native-kb4-v1"
],
"learned_models": [
"rf-detr-large-native-kb4-v1"
],
"model_manifest_sha256": "edef8446597b801f67538e9e1f056cbb55e56bf61ca4127efd97ce98e7473788",
"resource_profile_id": "worker006-single-gpu-sequential-ai-object-distance-v1",
"resource_profile_sha256": "c244efed459915508044fed4ef0e73c810fbe750e5e379d06723f734bd4385ca"
},
"checkpoint_policy": {
"mode": "non-checkpointable",
"allowed_checkpoints": [],
"last_checkpoint_id": null
},
"priority": {
"class": "recorded",
"rank": 100,
"server_owned": true
},
"state": "succeeded",
"preemption_requested": false,
"restart_from_zero": false,
"preemption_receipt_sha256": null,
"claim_generation": 1,
"claim_lease": null,
"result": {
"result_id": "ai-layer-object-distance-05f3931621585c9ac32132bef8c7afa961cea317cc29def09a8312339f8421e4",
"sha256": "05e9431dd5cfb7e55b8d59644cdadccf67588974975455e376d37f880f4652f6"
},
"terminal": {
"code": "result-sealed",
"message": "Recorded result was sealed by the Worker."
},
"publication": {
"state": "published",
"attempts": 1,
"error": null,
"published_at_utc": "2026-09-04T07:00:02.263Z"
},
"created_at_utc": "2026-09-04T06:29:36.181Z",
"updated_at_utc": "2026-09-04T07:00:02.263Z",
"authority": {
"commands_enabled": false,
"actuation_allowed": false,
"navigation_or_safety_accepted": false,
"production_accepted": false
}
}
],
"result_ids": [
"ai-layer-ddrnet-7c6a79942683933390f5ff0ecf2c6da1867d40032e91303746a567198772ce5c",
"m49-tgs-portable-review-a09d2b4a07d103e4f3693ba746a51be2197214768774eabfded4f109ae80dce4",
"ai-layer-object-distance-05f3931621585c9ac32132bef8c7afa961cea317cc29def09a8312339f8421e4"
]
}
]
},
"recorded_jobs": {
"ai-segmentation-ddrnet-v1": [
{
"job_id": "observatory-run-ef3c14a64fca4d5a8674df82a5a0fca2",
"state": "succeeded",
"publication": {
"state": "published",
"attempts": 1,
"error": null,
"published_at_utc": "2026-09-04T04:26:44.704Z"
}
},
{
"job_id": "observatory-run-884ad2f787244abdb12373a8f6f2d2e0",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-db32fced93ad46b6a3f7d2ff7421a557",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-77f8470a8593454ab777bcacf2d47b9f",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-24de2abb929a42738e4cfef6c4e86b95",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-cc9c9c5cd18844f0ab25fb20524e5073",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-1079d7c81ea0499e86738abfc1c35f49",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
}
],
"ai-segmentation-eomt-v1": [],
"ai-detection-rf-detr-v1": [],
"ai-range-object-distance-v1": [
{
"job_id": "observatory-run-185e25280d58472ab8b4a0245a35c888",
"state": "succeeded",
"publication": {
"state": "published",
"attempts": 1,
"error": null,
"published_at_utc": "2026-09-04T07:00:02.263Z"
}
},
{
"job_id": "observatory-run-cef3ba45c2024c55b6fb461e653d7187",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-5ab19401156d4d05b770ba57384387f0",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-f1a3cd0475964d62867cf17f135efbaa",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-96c0b491ae604772af19bca478837599",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-ee9d0b283b68470c91db5199a0374146",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-500a5a3b31e34061b52e1c09ff4f9604",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
}
],
"m49-tgs-portable-v2": [
{
"job_id": "observatory-run-b230216709dc4c59bc56c98c7e329bf1",
"state": "succeeded",
"publication": {
"state": "published",
"attempts": 1,
"error": null,
"published_at_utc": "2026-09-03T08:31:39.776Z"
}
},
{
"job_id": "observatory-run-d9e1089a503d46988847ad9f86cbf7d9",
"state": "succeeded",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-e8645450dbe74f08b5944f35d3ee5c9f",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
},
{
"job_id": "observatory-run-a627da1692cb4a2a9106d3e7e2870a90",
"state": "failed",
"publication": {
"state": "not-required",
"attempts": 0,
"error": null,
"published_at_utc": null
}
}
]
},
"desktop_documents": {
"archived_at": "2026-09-05",
"role": "historical_desktop_reports_not_current_instructions",
"files": [
{
"filename": "_MISSING_CORE_MODULAR_AUDIT_AND_PLAN_2026-09-03.md",
"sha256": "d6c201d083fbec4b1db031379b515ff821a09ccfa0cea62443e211a9d76cb1c2",
"bytes": 53637
},
{
"filename": "_MISSING_CORE_OBSERVATORY_DOCKER_LABS_FINAL_STATUS_2026-09-01.md",
"sha256": "45e870700baddab8f31a2f0f0bfe1f9e99e8e73a490195c1e6a3beb5265e49ee",
"bytes": 330260
}
]
}
}
@@ -0,0 +1,15 @@
# Исторические исходники AI Inference
Полные побайтные копии двух Desktop-отчётов, заархивированные 2026-09-05.
Размеры и SHA-256: [manifest.json](manifest.json).
Текущий архитектурный срез и интерпретация старых результатов:
[AI Inference — принципы и архитектура](../../audits/2026-09-05-ai-inference-architecture.md).
Полный актуальный контекст также опубликован отдельной картой AI Inference в Ops / MISSION CORE.
Эти исходники исторические. Содержащиеся в них планы, слова CURRENT, «следующий
шаг» и старые требования к монолитной упаковке не являются текущими инструкциями.
Их даты измерений и ограниченная область доказательства сохраняются.
Оригиналы на Desktop автоматически не удалялись. После публикации этого архива
они могут быть удалены владельцем без потери именно этих двух документов.
@@ -0,0 +1,488 @@
# Mission Core / Missing Core — сверка модульной Обсерватории и план реализации
Дата: 3 сентября 2026. Срез runtime: 16:2116:35 UTC. Режим: исследование и планирование.
## 1. Вывод и границы этого прохода
Нужная модель продукта ясна: выбранная запись K1 → «Сконфигурировать AI-слой» → выбор независимых возможностей и моделей → расчёт точной композиции → сохранённая LAB. На одной записи допустимы несколько разных композиций; одна композиция применяется к разным совместимым записям.
Существующий код даёт хорошую основу очереди, transport, проверяемых входов, запуска Docker и публикации. Однако операторский конструктор, независимые модельные контракты и повторное использование результатов отдельных узлов ещё отсутствуют. Наличие отдельных контейнеров EoMT и DDRNet не означает их независимость: DDRNet сейчас читает входные кадры из результата EoMT.
В этот проход:
- Прочитан актуальный раздел 0.46 Desktop-документа, изучены связанные ADR, план, handoff и релевантная история. Указания внутри документов рассматриваются как контекст, а не как новый запрос на исполнение.
- Изучены карточки MISSION CORE через прямой Ops MCP, backend, frontend, generic Worker runtime, текущие adapters и полный экспериментальный graph.
- Выполнено реальное SSH-подключение к Worker 006, прочитаны Docker inventory и installed manifests; проверен HTTP-доступ к Core из обоих агентов.
- Исходники, установленные сервисы и Legacy не изменялись. Новые jobs, builds и inference не запускались. Контейнеры, images, volumes и caches не удалялись.
- Канон деплоя DCPLATFORM-21, Synology и rollout на борт в этот проход не применялись.
- Созданы только этот отчёт и приватные файлы сверки.
## 2. Что именно изучено
Рабочая копия: /Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory.
Ветка: codex/m5-1-observatory. HEAD: eff60e4.
В копии есть многочисленные ранее внесённые tracked/untracked изменения. Они сохранены и не считаются результатом этого прохода.
Backend — Python 3.12, FastAPI, SessionStore, artifact gateway, SQLite queue, portable registries.
Frontend — React 19 / TypeScript / Vite; NODE.DC UI packages; Rerun 0.36.3.
Авторитетная запись и управление K1 принадлежат Core и K1 plugin. Worker создаёт производные результаты.
| Область | Основные исходники |
|---|---|
| Сборка backend и подключение сервисов | src/k1link/web/app.py |
| API оператора | src/k1link/web/observatory_api.py |
| API Worker | src/k1link/web/observatory_worker_api.py |
| Реестр полных профилей | src/k1link/observatory/portable_run_definitions.py, portable_setup_projection.py |
| Admission и привязка к записи | source_admission.py, portable_queue_binding.py |
| Очередь, аренды, idempotency, publication state | recorded_jobs.py |
| Worker service и выбор executor | worker_service.py, worker_agent.py |
| Передача исходников и результатов | worker_http_transport.py, portable_artifact_transport.py |
| Общий source CAS | worker_source_cache.py |
| Установленные пакеты и запуск Docker | installed_lab_packages.py, installed_lab_package_runner.py, installed_lab_worker_service.py |
| Текущий LAB V1 | lab_v1_installed_package_steps.py, portable_lab_v1_executor.py; experiments/perception/worker/observatory_portable/ |
| Текущий M49 | m49_worker_service.py, m49_portable_executor.py, m49_portable_source.py |
| Сохранение и повторное открытие | portable_result_publisher.py, portable_result_cache.py, portable_publication_reconciler.py |
| Контракты просмотра | portable_replay.py, portable_semantic_replay.py, portable_tgs_replay.py, portable_result_view.py |
| Обсерватория frontend | apps/control-station/src/workspaces/observatory/ObservatoryWorkspace.tsx |
| Каталог, выбор, jobs и progress | apps/control-station/src/core/observatory/ |
| Общий LAB viewer | apps/control-station/src/components/laboratory/PortableResultReplay.tsx, CanonicalResultRerunReplay.tsx |
| Lifecycle spatial viewer | apps/control-station/src/components/RerunViewport.tsx и components/rerun/ |
| Полный экспериментальный graph | experiments/perception/worker/streaming_profile_stage1/pilot_graph.py, run_joint_pilot.py, pilot_model.py |
| Реальные алгоритмы | src/k1link/perception/{detector,geometry,motion,temporal,rolling_map,threat,rf_detr_native_object_detector}.py |
| Системная телеметрия | src/k1link/web/system_telemetry_api.py, src/k1link/compute/pipeline_telemetry.py |
Пути без префикса в строках таблицы относятся к src/k1link/observatory/.
Опорные документы: ADR0051, верхний текущий раздел OBSERVATORY_REALTIME_PROFILES_EXECPLAN, OBSERVATORY_MODULAR_HANDOFF_2026-09-03, каноны UI/компонентной архитектуры. Канонические Window, FieldFrame, Select и WindowFooterActions подтверждены в registry/components.json Design Guideline.
В Ops прочитаны, в частности:
- №73 «Обсерватория — модульные профили: решение и сверка Worker» — прямой контекст нового решения; карточка в Backlog.
- №71 «Milestone 5 · OSS-конструктор Mission Core» — общий M5 и границы Observatory.
- №50 «Фундаментальная архитектура Mission Core».
- №9 «Mission Core AI Server Worker — RTX 4090».
- №47 «[Mission Core] Worker telemetry: agent → MQTT → Timescale».
- №62/63 — отдельные TGS и integrated reference-graph испытания.
- №64/66 — sealed playback и канон интеграции Rerun.
Также просмотрены связанные карточки Worker, исходной архитектуры, LiDAR и perception. Исторические показатели этих карточек не выдаются за приёмку новых модулей. Чтение комментариев №73 завершилось транспортной ошибкой Ops MCP; содержимое самой карточки получено. Записей в Ops в этом проходе не было.
## 3. Фактический runtime
### Core
- http://127.0.0.1:8000/api/health: operational=true.
- PID 2421 слушает 127.0.0.1:8000; listener на 8765 не найден.
- Recording cache: 20 entries, 653 266 743 bytes.
- Artifact cache: 9 pinned objects, 721 626 746 bytes.
- Background reconciler работает; на последнем срезе consecutive_failures=0.
- В очереди 13 jobs: 11 failed, 2 succeeded, активных jobs и live leases нет.
- Из двух succeeded одна имеет publication_state=published, другая — историческое not-required. Это не две заново принятые модульные LAB.
Текущая опубликованная portable LAB:
job observatory-run-b230216709dc4c59bc56c98c7e329bf1;
result m49-tgs-portable-review-a09d2b4a07d103e4f3693ba746a51be2197214768774eabfded4f109ae80dce4.
Каталог API подтверждает open-existing для M49 × RAVNOVES004TREE без разрешения повторного вычисления. Последняя LAB V1 job observatory-run-67a6bf3e4d644e4a8ee3c03b915f8f01 остаётся failed, результата нет.
### Worker 006
SSH alias mission-gpu разрешён существующей конфигурацией в desktop-opj8j04.tail8d32ac.ts.net; hostname действительно DESKTOP-OPJ8J04.
| Объект | Текущий факт |
|---|---|
| GPU | RTX 4090; driver 610.47; 24 564 MiB |
| Моментальный GPU snapshot | 1 778 MiB занято, utilization 14%; это общий счётчик устройства, не замер нового LAB |
| Контейнеры | 11 всего: 7 running, 4 stopped |
| Images / named volumes | 80 / 9 |
| Generic Observatory agent | be85dc40147a; image bfdc94ae5190…; running, restart count 0 |
| M49 Observatory agent | d58b3872d2ab; image e545a47a7ea2…; running, restart count 0 |
| Rollback-пара | a01b0fc675a0 и c51bd8d95a85; stopped |
| Frigate / Ollama | stopped, restart=no |
| Прежние Gaussian | gateway/pipeline unhealthy; terrain executor healthy |
| Прежний perception worker | running на срезе, RestartCount=450 |
| Прежний Triton | healthy |
Повторно проверено наличие image полного прототипа:
sha256:986dbe7126992359c69da0ddda674925a5efe8e3429a6d5f60765f9c9ad34a4e
(tag ndc-k1-perception-ddrnet39-rfdetr-tgs:stage1-joint-20260901).
Сверены SHA-256 пяти файлов внутри работающего generic agent с checkout: worker_agent.py, worker_http_transport.py, worker_service.py, worker_source_cache.py, installed_lab_package_runner.py. Все пять совпали. Поэтому замечания об этих участках относятся и к проверенному установленному агенту.
### Текущие вычислительные пути
LAB V1 package:
1bc84be07634ff69ac7459a2c39dc8fc9bcee33f72985dfa2c6088bb78976d8e.
| Шаг | Image SHA-256, начало | GPU | Лимит RAM контейнера |
|---|---|---:|---:|
| prepare | 5ad7d95baac6… | 0 | 4 GiB |
| eomt | adba3dc8c97b… | 1 | 24 GiB |
| ddrnet | e6c986100613… | 1 | 16 GiB |
| assemble | 5ad7d95baac6… | 0 | 8 GiB |
Это фиксированная последовательность prepare → EoMT → DDRNet → assemble. Лимиты RAM не являются квотами VRAM.
M49 выполняет подготовку и CPU TRAVEL TGS через установленный бинарник внутри специализированного агента. Это ещё не самостоятельный модуль общего composer runtime.
Согласно handoff, сохранённый M49 обработал 6 830 camera anchors, 6 811 LiDAR bindings, 19 UNOBSERVED за 1 416.763 s. Покрытый интервал 39.215–757.160 s внутри записи длительностью 808.779 s. Эти числа в этом проходе не пересчитывались; свежо подтверждены queue/result binding и доступность сохранённого результата.
### Отдельное расхождение: hardware telemetry сейчас не работает
Свежая проверка /api/v1/system/worker-telemetry:
source=agent-mqtt, reachable=false, error_code=telemetry-agent-unavailable.
Дополнительные read-only проверки:
- 127.0.0.1:18030/health: Connection refused.
- Docker API Mac по текущему socket недоступен.
- Windows service telegraf / «NDC Mission Core Telemetry Agent»: Stopped.
Вычислительные Observatory agents при этом видят Core. Нельзя объединять эти два состояния в «Worker недоступен» или «вся телеметрия работает». Причина остановки не устанавливалась. Для будущих ресурсных замеров нужно отдельно вернуть телеметрию либо явно определить ограниченный measurement path; автоматического запуска служб в исследовании не было.
## 4. Как сейчас идут задания и данные
~~~mermaid
flowchart LR
UI["Обсерватория · React"] --> API["Core API · 8000"]
API --> Q["SQLite queue · exact identity"]
W["Worker agent"] -->|"pull claim v3 / heartbeat / progress"| API
Q -->|"sealed job"| W
A["Core source / artifact API"] -->|"verified source bytes"| CAS["Worker source CAS"]
CAS --> P["Подготовка записи"]
P --> C["Установленный executor / fixed-stack"]
C --> R["Запечатанный результат"]
R -->|"manifest + members"| O["Core publication / outbox"]
O --> S["Saved LAB / artifacts"]
S --> V["Общий viewer на Core"]
~~~
Фактический путь HTTP из каждого агента:
127.0.0.1:18080 внутри контейнера → фиксированный TCP bridge → host.docker.internal:18080 → существующий reverse SSH tunnel → Core 127.0.0.1:8000.
Mac-owned tunnel описан в worker_tunnel_launchd.py:
-R 127.0.0.1:18080:127.0.0.1:8000 через mission-gpu.
Оба текущих агента используют BASE_URL=http://127.0.0.1:18080 и общий /source-cache.
Это текущий лабораторный transport. Экспериментальные gRPC/binary streaming adapters полного graph существуют отдельно; они не заменяют установленную recorded queue.
Основные свойства, которые нужно сохранить:
1. Frontend передаёт идентификаторы данных, а не shell/Docker команды.
2. Core проверяет запись, source snapshot и доступную версию executor.
3. Queue атомарно исключает дубликаты и выдаёт одну активную аренду для recorded compute; сохраняет fencing/generation и границу live K1.
4. Worker проверяет exact identities и claim, получает bounded source streams.
5. Generic launcher разрешает только установленные images/assets/argv, идёт по dependency order, запускает шаги последовательно и удаляет принадлежащие запуску временные контейнеры.
6. Результат проверяется и публикуется на Core. Core outbox умеет повторять публикацию уже принятого пакета без inference.
7. Saved viewer читает запись и сохранённые артефакты с Core.
Телеметрия оборудования — отдельный путь:
Windows Telegraf → MQTT → normalizer → Timescale → Core System API.
Job progress передаётся собственным Observatory HTTP-протоколом и не должен зависеть от доступности MQTT.
## 5. Существенные разрывы между текущим кодом и composer
### 5.1 DDRNet не независим от EoMT
run_portable_lab_v1_ddrnet_component.py:139 вызывает _validate_eomt_input.
lab_v1_installed_package_steps.py:202 формирует для DDRNet eomt_result_root и source-frames из EoMT step. Installed manifest объявляет depends_on=[eomt,prepare].
Нужен самостоятельный output подготовки камеры: decoded-frame index, verified frames/chunks, source timestamps, valid-FOV/preprocessing metadata и decode-repair accounting. DDRNet и EoMT должны потреблять его независимо. Нельзя снять dependency только в JSON.
### 5.2 Package registry уже поддерживает DAG, но только фиксированный пакет
installed_lab_packages.py:192 связывает package с одним definition_sha256 и runtime_candidate_sha256.
worker_service.py:380 строит ready registry по этим точным парам.
worker_agent.py:428 выбирает только заранее установленную executor identity.
Следовательно, простое добавление React Select не создаёт динамические композиции. Нужны server-owned composition registry и проверка плана на Worker по локальному реестру модулей. Новая комбинация не должна требовать image build, ручного installer или нового agent.
### 5.3 Нет общего результата произвольного набора слоёв
PortableResultReplay.tsx:18 распознаёт конкретные M49 и EoMT+DDRNet schemas.
portable_semantic_replay.py:67 ожидает одновременно city_masks и vegetation_masks, обе component identities и их artifacts.
lab_v1_installed_package_steps.py:158 собирает именно два component result.
Нужен versioned result с inventory фактически вычисленных capabilities, общим source clock, coordinate frame, taxonomy и artifact references. Пример: detector-only публикует boxes/classes/scores; segmentation-only — masks/taxonomy; range появляется только при наличии соответствующего вычисления.
### 5.4 Source admission шире потребностей отдельных алгоритмов
Нынешние два профиля требуют camera + point-cloud + trajectory, точную camera/calibration identity и одну media epoch. RecordedSourceRequirements в portable_run_definitions.py требует video даже в общем типе.
Для частичных композиций требования должны выводиться из выбранного графа. Segmentation и detector не должны автоматически требовать LiDAR. Для LiDAR-only режима нужно отдельно определить timestamp anchor и поддерживаемую аттестацию источника; нельзя просто убрать video из проверки текущего camera-anchored M49.
| Запись, API-срез | Текущее состояние |
|---|---|
| RAVNOVES004TREE, 808.779 s | video + cloud + trajectory; оба старых профиля source-compatible, M49 уже сохранён |
| RAVNOVES00, 535.718 s | video + cloud + trajectory; оба старых профиля source-compatible |
| RAVNOVES01, 517.468 s | cloud + trajectory; нет video; оба профиля сейчас блокируются уже по capture-attestation-missing |
RAVNOVES01 — отрицательный тест текущего admission, а не уже допущенный LiDAR-only источник. Новый режим требует отдельной проверки фактической аттестации, временных и пространственных данных.
### 5.5 Полный прототип нельзя переносить как готовый универсальный модуль
pilot_graph.py использует настоящие detector/geometry/motion/TGS алгоритмы, но также:
- жёстко заданные RAVNOVES00/session IDs;
- camera 800×600, конкретную KB4 calibration и valid-FOV;
- DDRNet crop/resize 600→512 и конкретный GOOSE mapping;
- связывает TGS rasterization, material projection, препятствия и policy в одном costmap method;
- удерживает state surface/association/temporal/rolling/history.
Нужны adapters из общего SourceEnvelope, явные image transforms и taxonomy maps. EoMT нельзя подставить вместо DDRNet в этот method без mapping/geometry contract.
### 5.6 Source CAS и финальный result cache уже есть; per-node cache отсутствует
worker_source_cache.py повторно использует точные исходные bytes.
portable_result_cache.py проверяет уже опубликованный полный LAB.
Промежуточные steps сейчас принадлежат попытке конкретной job. Нет независимой идентичности node-result, reusable across compositions. На cold path сначала завершается materialize всего входа, затем запускается runner. Бounded передача файлов уже есть, но это ещё не progressive compute.
### 5.7 Cancellation/lease loss нужно довести до самого executor
worker_agent.py:524 запускает adapter.execute синхронно и проверяет heartbeat.failed после возврата.
installed_lab_package_runner.py:326 ждёт Docker not-running; отдельного cancellation token между heartbeat и launcher нет.
Cleanup после выхода/ошибки существует. Однако быстрое освобождение ресурсов при потере аренды или operator cancel этим не доказано. Новому runtime нужны общий cancellation context, прекращение выдачи новых chunks, остановка точных child containers/processes, bounded join и подтверждение освобождения перед следующей GPU-job. Это вывод из проверенного кода, не проведённый здесь аварийный эксперимент.
### 5.8 Packaging и установленная resource policy ещё расходятся с целью
EoMT использует host-mounted Python/environment/transformers/model cache/runner/FFmpeg. DDRNet использует mounted checkpoint/mapping/runner и старый vegetation adapter. Это явные текущие зависимости, но ещё не переносимый модуль без developer layout.
В checkout EoMT DISK_FLOOR_BYTES=250 GiB. По последнему handoff установленный step image содержит прежние 350 GiB; точный installed image в этом проходе совпал с тем handoff. Внутренний файл stopped compute image заново не извлекался. Изменение policy требует новой immutable версии, а не редактирования прежнего digest.
### 5.9 Системная видимость Docker сейчас задана старым списком
system_telemetry_api.py:34 и :1163 строит runtime cards по CONTAINER_GROUPS: Triton, perception, Frigate, Ollama. Само появление новых module containers не даст им полноценного представления в этой проекции.
Нужны versioned module/job events и связь по labels: module version, composition, job, attempt, node. Существующий transport телеметрии можно переиспользовать; дополнительный telemetry-agent на каждую модель не нужен.
## 6. Предлагаемое разбиение
Это проектирование будущих контрактов. Приведённые ndc-имена не являются уже собранными releases.
| Узел / группа | Кандидат | Вход → результат | Независимость |
|---|---|---|---|
| Внутренняя подготовка, без выбора модели | Source adapter / decoder | raw source → verified bounded camera/LiDAR/pose chunks и индексы | Подготавливает только нужные графу каналы; не запускает ML |
| Сегментация | ndc-k1-segmentation-ddrnet39 | Camera + preprocessing → mask + GOOSE taxonomy + transforms | Без EoMT, detector и LiDAR |
| Сегментация, альтернатива | ndc-k1-segmentation-eomt-cityscapes | Camera + preprocessing → mask + versioned taxonomy | Без DDRNet; output adapter фиксируется отдельно от raw labels модели |
| Детекция | ndc-k1-detection-rfdetr | Camera/FOV → bbox, class, score | Без segmentation; текущий RF-DETR-L native KB4 wrapper сохраняется как точная версия |
| LiDAR / TGS / geometry costmap | ndc-k1-lidar-tgs | Cloud + необходимая pose/history → ground/occupied/rejected/unobserved | Без semantic detector и segmenter; camera нужен лишь если выбран camera-anchored режим |
| Объектная геометрия / расстояния | ndc-k1-object-geometry | Objects + cloud + pose/calibration/time binding → metric association/range | Не требует segmentation; geometry-only output не выдаётся за semantic detection |
| Temporal / motion | ndc-k1-object-motion | Geometry observations + bounded history → tracks/motion/retention | Явный state/history/reset contract |
| Semantic fusion / policy-shadow | ndc-k1-policy-shadow | TGS, material projection и объявленные obstacle/temporal outputs → наблюдаемые policy outputs | Зависимости задаются конкретным policy provider |
Тесно связанные temporal/motion/rolling функции допустимо держать в одном модуле. Аналогично TGS и его геометрическую rasterization/costmap. Логическая dependency не требует отдельного процесса для каждого математического шага.
Разделять TGS и semantic fusion нужно хотя бы в контракте: TGS-only не должен скрыто запускать segmentation. В полном pilot graph они сейчас соединены кодом.
Текущий detector использует RF-DETR-L с COCO-derived классами и ограниченным risk-class subset: человек, ряд транспорта и животных. Фраза «детекция всех объектов» не соответствует этому контракту. Дальность named object требует association; сегментация сама по себе расстояние не создаёт.
## 7. Контракты и идентичность
Предлагаемые новые исполнимые сущности:
- ModuleSpec: stable ID/version, image digest, code/weights/assets digests, capabilities, input/output schema, taxonomy, preprocessing, resource profile, state model.
- CompositionSpec: canonical nodes + module versions + parameters + typed edges + requested outputs + cadence/precision/history/reset rules.
- CompositionRun: composition digest + source snapshot + выбранный временной диапазон + execution attempt/ownership + node outcomes + publication.
- NodeResultManifest: exact input/output identities, actual coverage/gaps, computed/reused status, artifacts и timings.
- CapabilityResult: единый сохранённый LAB с перечислением доступных слоёв, renderer-neutral artifact refs и provenance.
Ключевые правила:
1. CompositionSpec не содержит конкретную запись, labels UI, Docker host paths, argv или credentials. Он переиспользуем.
2. Core выдаёт data-only manifest. Worker разрешает module IDs только через собственные установленные ModuleSpecs.
3. Worker подтверждает capability snapshot и exact module versions. Текущего списка готовых полных executor identities недостаточно для произвольного composer. Рекомендуется versioned extension capability/claim contract с сохранением чтения v3 для старых jobs; конкретная версия фиксируется в этапе 1.
4. Composition digest не зависит от порядка кликов; зависит от значимых modules/parameters/edges/outputs/time rules.
5. Node cache key включает module identity, relevant source/preparation inputs, hashes upstream outputs, effective parameters, calibration/transforms/taxonomy, cadence/precision и state/history.
6. В node cache key нельзя включать job ID или digest всей композиции: это уничтожит reuse при изменении независимой ветки. Job/attempt/composition сохраняются в provenance отдельно.
7. Для stateful узлов совпадения frame ID недостаточно: нужны initial state или checkpoint identity, input prefix/history, reset/epoch и time range.
8. Смена detector сохраняет независимую segmentation; пересчитывает association и всё, что от него зависит. Смена segmentation сохраняет detector, но меняет semantic fusion.
9. Массивы передаются локально на Worker: immutable chunks/files/mmap refs с размером, dtype, shape, digest, clock и coordinate frame. В API идут bounded metadata. Промежуточные tensors не ходят Worker→Core→Worker.
10. Final publication связывает node artifacts с новой job независимо от происхождения computed/reused. Наличие частичного node cache не делает LAB завершённой.
11. Нужны atomic cache publication, validation перед reuse, quarantine damaged entries, retention pins для активных jobs/готовых LAB/retry/rollback.
12. Одна композиция владеет Worker 006; тяжёлые GPU стадии исполняются последовательно. Процесс модели живёт на протяжении её обработки записи, а не создаётся на каждый кадр.
## 8. Поведение интерфейса
В существующей Обсерватории рядом с выбранной записью постоянно доступна кнопка «Сконфигурировать AI-слой». Наличие уже рассчитанных LAB или активной job не должно убирать вход в настройки. Если источника вообще нет, нужен обычный empty state.
Модальное Window:
- Сегментация: «Не использовать» / DDRNet / EoMT.
- Детекция: «Не использовать» / RF-DETR.
- LiDAR/TGS: допустимый provider либо отключено.
- Расстояния, motion, policy-shadow — по availability и объявленным зависимостям.
- По одному provider на группу; один module с несколькими capabilities не запускается несколько раз.
- Модели остаются в списках после расчёта. Готовность относится к целой композиции.
- Недоступные сочетания объясняются внутри формы. Зависимости нельзя молча исправлять включением другой ML-модели.
- Пустой состав без вычисляемого output не создаёт LAB.
- Оператору показываются имена моделей/возможностей; технические digests и Docker paths остаются в engineering details.
Состояния точного source × composition:
| Состояние | Действие |
|---|---|
| Допустим, ещё не рассчитан | Рассчитать |
| Уже принят / queued / running | Показать существующую job и реальный progress |
| Полностью опубликован и проверен | Открыть сохранённую LAB |
| Расчёт завершён, публикация требует повтора | Повторить публикацию без inference |
| Недопустим или нет installed module | Причина несовместимости; настройки остаются открываемыми |
| Расчёт failed/cancelled | Честный terminal state и допустимый повтор; partial node cache не выдаётся за готовую LAB |
Никаких отдельных страниц/микроприложений на модель или новую LAB. Компоненты формы — отдельные bounded feature modules, чтобы не расширять бесконечно ObservatoryWorkspace.tsx/App.tsx.
Escape сначала закрывает открытый Select, затем окно; проверяются focus restore, normal/expanded viewer, close/reopen и release ресурсов. Отображаются только реально рассчитанные capabilities; старые Legacy overlays не используются для заполнения отсутствующих слоёв.
## 9. План реализации
### Этап 1 — executable contracts и граница миграции
1. Зафиксировать ModuleSpec / CompositionSpec / NodeResult / CapabilityResult и source requirements по графу.
2. Построить server-side dependency admission: один segmenter; detector-only и segmentation-only допустимы; distance без нужных входов отклоняется.
3. Спроектировать dynamic composition registration и Worker capability negotiation поверх существующей очереди. Новая комбинация не требует image build/reinstall агента.
4. Реализовать canonical identities и правила reuse/invalidation, включая stateful nodes.
5. Зафиксировать coexistence новых schemas со старым installed V1/M49 и Legacy.
6. Составить retention closure существующих images/assets/packages/results/rollback. Очистку выполнять только отдельным последующим действием по проверенной достижимости; она не нужна для завершения текущего планирования.
Выход: контрактные fixtures и тесты, точная модель admission, migration table. Новых GPU-прогонов для этого этапа не требуется.
### Этап 2 — modules и Worker; первым сквозным результатом DDRNet-only
2A. Вынести подготовку камеры из EoMT, создать независимый DDRNet module и общий capability result writer.
Прогнать на настоящем источнике: source → prepare → DDRNet → sealed LAB → Core viewer. Это минимальный полезный вертикальный срез.
2B. Добавить RF-DETR detector-only и альтернативный EoMT. Доказать, что отключённые модели не загружаются. Упаковка включает закреплённый runtime и weights либо явно поставляемые immutable assets, без зависимости от случайного checkout/conda на host.
2C. Перенести TRAVEL TGS в общий package runtime. Отделить geometry-only от semantic fusion, подключить object association, motion и policy-shadow по реальным зависимостям полного prototype graph. Убрать hardcoded source IDs; сохранить точные calibration/FOV/taxonomy contracts.
2D. Добавить node cache, composition progress, cancellation/lease fencing, module/job labels, cleanup и retry. Обобщить capabilities системной телеметрии; перед measurement вернуть рабочий telemetry path без изменения Legacy.
2E. Довести progressive input: bounded chunks, early-start и accounting gaps; первичная полная материализация может быть промежуточным ограничением первого вертикального среза, но не критерием завершения всего этапа. Измерять disk I/O и memory вместе с inference.
Новый EoMT release отдельно активирует согласованную resource policy. Images старых releases не меняются на месте.
### Этап 3 — composer и полная продуктовая приёмка
- Подключить grouped Window к server admission и immutable compositions.
- Перенести readiness и dedup с одного фиксированного setup dropdown на source × composition.
- Добавить generic replay по capabilities: camera/mask/boxes/range/TGS/motion. Проверить отсутствие неназначенных слоёв.
- Выполнить последовательную матрицу на RAVNOVES00 и RAVNOVES004TREE; допустимость RAVNOVES01 проверять отдельно, не обходя отсутствие attestation.
- Проверить recovery, exact cache reuse, большие каталоги, закрытие/повторное открытие и освобождение RAM/GPU viewer.
- Сохранённые записи и LAB должны открываться без работающего Worker.
- Прогресс показывает фактически выполненные/переиспользованные/ошибочные узлы, source frames и coverage. Percent без измеренного total не выдумывается.
Этапы 2 и 3 разумно выполнять вертикальными инкрементами: сначала реальная DDRNet-only LAB и её минимальная форма, затем остальные группы через те же контракты.
### Этап 4 — будущий CUDA-борт
Перенос тех же логических модулей на конкретное совместимое железо, долгоживущие процессы в пределах миссии, общий benchmark memory/latency/I/O. Этот этап не является условием готовности записанных лабораторий и сейчас не исполняется.
## 10. Приёмочные сценарии
| Сценарий | Проверяемый результат |
|---|---|
| DDRNet-only | Нет EoMT/detector процесса; есть masks и saved review |
| EoMT-only | Нет DDRNet; собственная taxonomy и корректный source transform |
| Detector-only | Есть bbox/class/score; segmentation отсутствует |
| TGS-only | Геометрические состояния без скрытой ML; clock выбран явно |
| Distance без detector/cloud/calibration | Server admission отклоняет named-object distance |
| Geometry-only без detector | Нет выдуманных semantic labels; только заявленный geometric output |
| Два segmenter / пустой граф / cycle | Отклонение на сервере, до enqueue |
| Повтор одной композиции | Существующая job или проверенная LAB, без нового inference |
| Изменён detector | Segmentation reuse; зависимые association/motion пересчитаны |
| Изменена calibration/cadence/history | Нужные cache entries инвалидированы |
| Повреждён node cache | Не принимается как hit; нет ложной готовой LAB |
| Restart Core/Worker, потеря сети | History и ownership сохранены; нет конкурентной GPU-job |
| Cancel / lease loss внутри inference | Bounded stop, освобождение exact resources до следующего владельца |
| Upload обрывается / Core publication падает | Сохранённый sealed output используется для recovery; inference не повторяется ради публикации |
| Viewer с Worker offline | Полный сохранённый просмотр с Core |
| Close/reopen, normal/expanded/Escape | Один clock/receiver, отсутствие накопления временных ресурсов |
| Две записи × две композиции | Никакой привязки результата к чужой записи или старому overlay |
| Вычисление медленнее записи | Честный wall time и полное заявленное coverage, без ложного realtime PASS |
Existing tests для расширения: test_observatory_installed_lab_packages.py, test_observatory_installed_lab_package_runner.py, test_observatory_installed_lab_worker_service.py, test_observatory_recorded_jobs.py, test_observatory_portable_worker_runtime.py, test_worker_source_cache*.py, test_observatory_heartbeat_recovery.py, test_observatory_portable_result_publisher.py и Observatory frontend contract tests. Новый прогон тестов не выполнялся, поскольку этот проход не менял реализацию.
## 11. Конкретные точки следующего изменения
Предлагаемые новые bounded backend modules:
module_contracts.py, composition_contracts.py, composition_admission.py, composition_registry.py, node_result_cache.py, capability_result.py.
Окончательные имена — implementation detail; не нужно разносить каждую dataclass по отдельному файлу.
Изменяемые существующие seams:
- portable_run_definitions / source_admission / portable_queue_binding: переход от fixed profile к graph-derived требованиям;
- recorded_jobs / worker_agent / worker_service / worker_http_transport: composition identity, capability negotiation и cancellation;
- installed_lab_packages / installed_lab_package_runner: compilation разрешённого graph и module execution;
- отдельные adapters в experiments/perception/worker/observatory_portable;
- portable_result_* / portable_replay: generic capabilities и exact publication/review;
- ObservatoryWorkspace + отдельный AI-layer configuration feature в core/observatory и components;
- system_telemetry_api / pipeline_telemetry: динамическая module/job correlation.
Первое реализационное действие: согласованный executable контракт независимого source preparation и DDRNet module, затем настоящий DDRNet-only вертикальный срез. Повторный полный dual-segment LAB V1 и массовая чистка Docker не закрывают этот разрыв.
## 12. Evidence и пределы сверки
Приватные файлы:
/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/.runtime/observatory-context-audit-20260903
Содержат allowlisted inventory, hashes installed manifests, сравнение пяти исходников агента, source catalog, portable setup projections, queue summary и health/telemetry snapshot. Credentials, auth headers и содержимое записей не извлекались.
Основной Worker inventory SHA-256:
1a960a8ec05572dbd69409dcff1030076fc785fd91e3b2c729aad19143b7e195.
Сверка доказывает текущее устройство и перечисленные разрывы. Она не доказывает cold-start новых modules, скорость нового graph, визуальное качество, полноту покрытия всех записей или memory-lifecycle приёмку. Эти критерии включены в план, а не отмечены выполненными.
## 13. Ссылки на проверенные участки кода
- [Скрытая зависимость DDRNet от EoMT](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/experiments/perception/worker/observatory_portable/run_portable_lab_v1_ddrnet_component.py:139)
- [Формирование связанных component inputs](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/src/k1link/observatory/lab_v1_installed_package_steps.py:202)
- [Package привязан к конкретной definition](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/src/k1link/observatory/installed_lab_packages.py:192)
- [Реестр готовых установленных executor](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/src/k1link/observatory/worker_service.py:380)
- [Синхронный вызов executor и heartbeat](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/src/k1link/observatory/worker_agent.py:524)
- [Ожидание завершения Docker step](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/src/k1link/observatory/installed_lab_package_runner.py:326)
- [Текущая граница общего source contract](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/src/k1link/observatory/portable_run_definitions.py:127)
- [Viewer выбирает фиксированные result schemas](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/apps/control-station/src/components/laboratory/PortableResultReplay.tsx:18)
- [Обязательные обе segmentation ветки](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/src/k1link/observatory/portable_semantic_replay.py:67)
- [Жёсткие source IDs полного прототипа](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/experiments/perception/worker/streaming_profile_stage1/pilot_graph.py:302)
- [Текущий profile selector в Обсерватории](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/apps/control-station/src/workspaces/observatory/ObservatoryWorkspace.tsx:439)
- [Статический список системной телеметрии](/Users/dcconstructions/Downloads/mnt/NODEDC/NODEDC_MISSION_CORE_m5_observatory/src/k1link/web/system_telemetry_api.py:34)
## 10. Реализация после сверки — 3 сентября 2026, финальный локальный срез
Этот раздел заменяет формулировки выше о том, что модульный runtime и интерфейс ещё не реализованы. Указания исходного status-документа использовались как контекст; выполнен запрос владельца из диалога. Legacy лабораторный контур и исторический combined LAB V1 не изменялись. Канон Synology/DCPLATFORM-21 не применялся.
### Интерфейс
- Удалены фиксированный selector готового LAB-профиля и кнопки «Обновить»/«Рассчитать» рядом с ним.
- На их месте постоянно доступна кнопка «Сконфигурировать AI-слой» для выбранной записи.
- Каноническое модальное окно содержит отдельные функциональные блоки, статус в header, одиночный Select и нижнюю кнопку «Рассчитать».
- DDRNet и EoMT представлены как независимые альтернативы группы «Сегментация»; ни одна из моделей не выбирает и не запускает вторую.
- После отправки durable job сразу появляется в «Лабораторных доказательствах» с записью, составом, фазой, прогрессом и оценкой оставшегося времени. После публикации результат использует существующие действия просмотра, переименования и удаления.
- По последнему уточнению владельца из модального окна удалены внешняя обводка, рамки блоков, разделители header и контурные тени полей. Группировка держится на фоне, отступах и типографике.
### Модули и Worker 006
Модельно-нейтральная подготовка камеры вынесена в самостоятельный шаг. DDRNet и EoMT зависят только от `camera.frames` и не читают результаты друг друга.
| Модуль | Docker image | Image SHA-256 |
| --- | --- | --- |
| Camera source | `ndc/mission-core-ai-module-camera-source:61d1cd0adbac` | `da926459aee0a841bbdfaf80a0eb5fbead354c56794d1f3384eeba66d0a49e00` |
| DDRNet | `ndc/mission-core-ai-module-ddrnet:61d1cd0adbac` | `489fc7d1157fd0f1cd1d82e06a15737b7b2aaaf72b2ddb2aca2992b91a97488e` |
| EoMT | `ndc/mission-core-ai-module-eomt:61d1cd0adbac` | `5b770178e4a5c8fbe8f8ddab3b83a598973dbe103b669851110b11a0918ab846` |
Общий агент `ndc-mission-core-observatory-ai-agent` запущен на Worker 006 из image SHA-256 `b7ce60a851703375e77234d9ae37dfc6221b74c9dff8de719d2a1f2772c6b089`. Он использует release `20260903-v2`, SHA-256 `a5017e73216b566d3dc61d62df1ba7bbaf1fb348dde26e42d818a121e7a4aef5`. На финальном срезе контейнер `running`, `RestartCount=0`; Core получает его claim-запросы с HTTP 204.
| Setup | Definition SHA-256 | Package SHA-256 |
| --- | --- | --- |
| `ai-segmentation-ddrnet-v1` | `3adeba6595e31503a21f731f4b1427b09c64705c4a506659854c7c366b2d144f` | `958aa340819b42880cb79001efed946f369272937bd166e1844ee57784c6fd78` |
| `ai-segmentation-eomt-v1` | `499105c06a50b046ef1c5cd2148254e916156528ad21a824a66b787915a7f96b` | `019205fd5f0e6253759f4e7cf7aa1daa6d132163d36d4be5f8d07cca3ad1598d` |
Для записи `20260828T130511Z_viewer_live` оба setup прошли три независимые живые проверки: `source_compatible=true`, `executor_ready=true`, `submission_allowed=true`. Во время QA пользовательская запись не отправлялась на реальный GPU-прогон.
### Проверка
- Backend: 98 целевых pytest-проверок модульной композиции, setup/admission, Worker integration, adapters, release и replay — успешно.
- Frontend: 749 unit-тестов — успешно; TypeScript typecheck и production build — успешно.
- Ruff и mypy по новому backend/Worker контуру — успешно.
- Release-файлы сверены по SHA-256 между локальной копией и Worker 006.
- В браузере проверены отсутствие старых controls, независимый выбор DDRNet/EoMT, закрытие модалки и итоговый вариант без обводок.
@@ -0,0 +1,16 @@
{
"archived_at": "2026-09-05",
"role": "historical_desktop_reports_not_current_instructions",
"files": [
{
"filename": "_MISSING_CORE_MODULAR_AUDIT_AND_PLAN_2026-09-03.md",
"sha256": "d6c201d083fbec4b1db031379b515ff821a09ccfa0cea62443e211a9d76cb1c2",
"bytes": 53637
},
{
"filename": "_MISSING_CORE_OBSERVATORY_DOCKER_LABS_FINAL_STATUS_2026-09-01.md",
"sha256": "45e870700baddab8f31a2f0f0bfe1f9e99e8e73a490195c1e6a3beb5265e49ee",
"bytes": 330260
}
]
}
+1 -1
View File
@@ -148,7 +148,7 @@ class LaboratorySetup:
]
if compatible and ready_result_ids:
action = "open-existing"
action_reason = "Точный запечатанный результат уже опубликован в Обсерватории."
action_reason = "Точный запечатанный результат уже опубликован в AI Inference."
elif compatible and any(
result.access == "legacy-lab" for result in self.preserved_results
):
+3 -3
View File
@@ -174,7 +174,7 @@ def build_modular_observatory_router(
try:
source = store.get_session(request.source_session_id).summary
except SessionNotFoundError as exc:
raise HTTPException(status_code=404, detail="Запись Обсерватории не найдена.") from exc
raise HTTPException(status_code=404, detail="Запись AI Inference не найдена.") from exc
if source.lab is not None:
raise HTTPException(
status_code=409,
@@ -412,7 +412,7 @@ def build_modular_observatory_router(
try:
display_name = composition_runs.rename_projection(run_id, request.display_name)
except CompositionRunError as exc:
raise HTTPException(404, "Результат AI inference не найден.") from exc
raise HTTPException(404, "Результат AI Inference не найден.") from exc
return {
"schema_version": "missioncore.observatory-ai-composition-run-projection/v1",
"run_id": run_id,
@@ -429,7 +429,7 @@ def build_modular_observatory_router(
try:
composition_runs.delete_projection(run_id)
except CompositionRunError as exc:
raise HTTPException(404, "Результат AI inference не найден.") from exc
raise HTTPException(404, "Результат AI Inference не найден.") from exc
return Response(status_code=204)
@router.get("/api/v1/observatory/ai-runs")
+22 -22
View File
@@ -456,7 +456,7 @@ def build_observatory_router(
if setup_registry is None:
raise HTTPException(
status_code=503,
detail="Каталог legacy-сетапов Обсерватории недоступен.",
detail="Каталог legacy-сетапов AI Inference недоступен.",
)
source = source_summary(source_session_id)
return setup_registry.catalog(
@@ -623,7 +623,7 @@ def build_observatory_router(
del source_session_id
raise HTTPException(
status_code=503,
detail="Каталог сетапов Обсерватории не прошёл проверку целостности.",
detail="Каталог сетапов AI Inference не прошёл проверку целостности.",
)
@router.post("/api/v1/observatory/run-preflights")
@@ -633,7 +633,7 @@ def build_observatory_router(
del request
raise HTTPException(
status_code=503,
detail="Каталог сетапов Обсерватории не прошёл проверку целостности.",
detail="Каталог сетапов AI Inference не прошёл проверку целостности.",
)
if setup_registry is not None and run_preparation_ledger is not None:
@@ -688,7 +688,7 @@ def build_observatory_router(
if not isinstance(setups, list):
raise HTTPException(
status_code=503,
detail="Каталог сетапов Обсерватории нарушил контракт.",
detail="Каталог сетапов AI Inference нарушил контракт.",
)
projected = next(
(
@@ -701,7 +701,7 @@ def build_observatory_router(
if projected is None:
raise HTTPException(
status_code=503,
detail="Каталог сетапов Обсерватории нарушил контракт.",
detail="Каталог сетапов AI Inference нарушил контракт.",
)
definition = projected.get("run_definition")
if not isinstance(definition, dict):
@@ -725,7 +725,7 @@ def build_observatory_router(
):
raise HTTPException(
status_code=503,
detail="Каталог сетапов Обсерватории нарушил контракт.",
detail="Каталог сетапов AI Inference нарушил контракт.",
)
if compatibility.get("compatible") is not True:
raise HTTPException(
@@ -743,7 +743,7 @@ def build_observatory_router(
):
raise HTTPException(
status_code=503,
detail="Dispatch-контракт Обсерватории не установлен.",
detail="Dispatch-контракт AI Inference не установлен.",
)
definition_id = definition.get("definition_id")
definition_version = definition.get("version")
@@ -759,7 +759,7 @@ def build_observatory_router(
):
raise HTTPException(
status_code=503,
detail="Каталог сетапов Обсерватории нарушил контракт.",
detail="Каталог сетапов AI Inference нарушил контракт.",
)
try:
intent = ObservatoryRunPreparationIntent(
@@ -826,7 +826,7 @@ def build_observatory_router(
del request
raise HTTPException(
status_code=503,
detail="Подготовка расчётов Обсерватории недоступна.",
detail="Подготовка расчётов AI Inference недоступна.",
)
@router.get("/api/v1/observatory/run-preparations/{preparation_id}")
@@ -840,7 +840,7 @@ def build_observatory_router(
del preparation_id
raise HTTPException(
status_code=503,
detail="Подготовка расчётов Обсерватории недоступна.",
detail="Подготовка расчётов AI Inference недоступна.",
)
if recorded_job_queue is not None and (
@@ -1022,7 +1022,7 @@ def build_observatory_router(
if not isinstance(setups, list):
raise HTTPException(
status_code=503,
detail="Каталог сетапов Обсерватории нарушил контракт.",
detail="Каталог сетапов AI Inference нарушил контракт.",
)
projected = next(
(
@@ -1035,7 +1035,7 @@ def build_observatory_router(
if projected is None:
raise HTTPException(
status_code=503,
detail="Каталог сетапов Обсерватории нарушил контракт.",
detail="Каталог сетапов AI Inference нарушил контракт.",
)
compatibility = projected.get("compatibility")
preflight = projected.get("preflight")
@@ -1043,7 +1043,7 @@ def build_observatory_router(
if not isinstance(compatibility, dict) or not isinstance(preflight, dict):
raise HTTPException(
status_code=503,
detail="Каталог сетапов Обсерватории нарушил контракт.",
detail="Каталог сетапов AI Inference нарушил контракт.",
)
if compatibility.get("compatible") is not True:
raise HTTPException(
@@ -1064,7 +1064,7 @@ def build_observatory_router(
if not isinstance(definition_sha256, str):
raise HTTPException(
status_code=503,
detail="Каталог сетапов Обсерватории нарушил контракт.",
detail="Каталог сетапов AI Inference нарушил контракт.",
)
try:
admission = recorded_binding_service.admit(
@@ -1175,7 +1175,7 @@ def build_observatory_router(
except ObservatoryRecordedQueueNotFoundError as exc:
raise HTTPException(
status_code=404,
detail="Расчёт Обсерватории не найден.",
detail="Расчёт AI Inference не найден.",
) from exc
except (ObservatoryRecordedQueueError, ValueError) as exc:
raise HTTPException(
@@ -1206,7 +1206,7 @@ def build_observatory_router(
except ObservatoryRecordedQueueNotFoundError as exc:
raise HTTPException(
status_code=404,
detail="Расчёт Обсерватории не найден.",
detail="Расчёт AI Inference не найден.",
) from exc
except (ObservatoryRecordedQueueError, ValueError) as exc:
raise HTTPException(
@@ -1305,17 +1305,17 @@ def build_observatory_router(
except SessionNotFoundError as exc:
raise HTTPException(
status_code=404,
detail="Проекция Обсерватории не найдена.",
detail="Проекция AI Inference не найдена.",
) from exc
except SessionIntegrityError as exc:
raise HTTPException(
status_code=409,
detail="Запись не является управляемой проекцией Обсерватории.",
detail="Запись не является управляемой проекцией AI Inference.",
) from exc
except ValueError as exc:
raise HTTPException(
status_code=422,
detail="Некорректные параметры проекции Обсерватории.",
detail="Некорректные параметры проекции AI Inference.",
) from exc
return ObservatoryProjectionDocument(
schema_version=OBSERVATORY_PROJECTION_SCHEMA,
@@ -1333,17 +1333,17 @@ def build_observatory_router(
except SessionNotFoundError as exc:
raise HTTPException(
status_code=404,
detail="Проекция Обсерватории не найдена.",
detail="Проекция AI Inference не найдена.",
) from exc
except SessionIntegrityError as exc:
raise HTTPException(
status_code=409,
detail="Запись не является управляемой проекцией Обсерватории.",
detail="Запись не является управляемой проекцией AI Inference.",
) from exc
except ValueError as exc:
raise HTTPException(
status_code=422,
detail="Некорректный идентификатор проекции Обсерватории.",
detail="Некорректный идентификатор проекции AI Inference.",
) from exc
return Response(status_code=204)