Уточнить DSH, плагины, roadmap и контракты исполнения

This commit is contained in:
admin committed 2026-11-11 05:24:36 +00:00
1 parent 2af6dd78ba
commit 41a4397ed2
25 files changed
+742 -36

No files matched your search

+1 -1
View File
@@ -28,4 +28,4 @@ UpgradePreview: fromVersionId, toVersionId, changes:[{path, kind}], validation,
## Подключения ## Подключения
GET /v1/connections возвращает доступные ConnectionSummary (id, provider, label, grantedScopes, expiresAt), не credentials. POST /v1/connections создаёт подключение через provider authorization flow или защищённую передачу ключа; конкретные provider payload задаются отдельными адаптерами и не входят в универсальную config schema. DELETE /v1/connections/{id} отзывает платформенный доступ и при возможности выполняет revoke у провайдера. Повторное использование в новом Run после отзыва запрещено. GET /v1/connections возвращает Page<ConnectionSummary> с cursor и limit, без credentials. Подключения создаются через provider authorization flow; единый контракт и защищённая передача API key описаны в [Provider API](provider-api.md). DELETE /v1/connections/{id} отзывает платформенный доступ и при возможности выполняет revoke у провайдера. Повторное использование в новом Run после отзыва запрещено.
+1 -1
View File
@@ -28,6 +28,6 @@ PATCH/PUT изменяемых ресурсов требуют If-Match, отв
## События и файлы ## События и файлы
SSE endpoint принимает Last-Event-ID; event id монотонен в пределах Run. После retention слишком старый cursor возвращает 410 с указанием получить snapshot. Повторные события дедуплицируются по eventId. SSE не является источником истины о состоянии: GET Run возвращает канонический snapshot. SSE endpoint принимает Last-Event-ID; SSE cursor монотонен в пределах Run и назначается сервером, отдельно от runner eventId. После retention слишком старый cursor возвращает 410 с указанием получить snapshot. Повторные runner events дедуплицируются по attemptId + eventId. SSE data содержит RunEvent, а transport id — серверный cursor; клиент хранит cursor для reconnect. SSE не является источником истины о состоянии: GET Run возвращает канонический snapshot.
Binary upload выполняется по scoped grant. Он содержит uploadId, url, expiresAt, maxBytes, requiredHeaders; постоянные записи хранят artifactId, не подписанный URL. Grant не считается подтверждением загрузки: finalize проверяет размер, digest и объект. По умолчанию ошибки не повторяются автоматически, кроме явных transient ошибок с ограниченным backoff и jitter. Binary upload выполняется по scoped grant. Он содержит uploadId, url, expiresAt, maxBytes, requiredHeaders; постоянные записи хранят artifactId, не подписанный URL. Grant не считается подтверждением загрузки: finalize проверяет размер, digest и объект. По умолчанию ошибки не повторяются автоматически, кроме явных transient ошибок с ограниченным backoff и jitter.
+15 -5
View File
@@ -12,19 +12,19 @@ Capabilities: os, architecture, executionKinds:["oci"], features:["cancel-v1"],
| Метод и путь | Запрос | Ответ | | Метод и путь | Запрос | Ответ |
|---|---|---| |---|---|---|
| POST /v1/runner-jobs/claim | runnerId, availableSlots, capabilitiesRevision | 200 Assignment или 204 | | POST /v1/runner-jobs/claim | runnerId, claimRequestId, availableSlots, capabilitiesRevision | 200 Assignment или 204 |
| POST /v1/attempts/{id}/heartbeat | leaseEpoch, sequence, progress? | 200 {leaseUntil, cancelRequested} | | POST /v1/attempts/{id}/heartbeat | leaseEpoch, sequence, progress? | 200 {leaseUntil, executionToken, tokenExpiresAt, cancelRequested} |
| POST /v1/attempts/{id}/started | leaseEpoch, sequence | 200 Attempt | | POST /v1/attempts/{id}/started | leaseEpoch, sequence | 200 Attempt |
| POST /v1/attempts/{id}/events | leaseEpoch, events:[RunEvent] | 200 {acceptedThrough} | | POST /v1/attempts/{id}/events | leaseEpoch, events:[RunEvent] | 200 {acceptedThrough} |
| POST /v1/attempts/{id}/uploads | leaseEpoch, purpose, mediaType, sizeBytes, digest | 201 UploadGrant | | POST /v1/attempts/{id}/uploads | leaseEpoch, purpose, mediaType, sizeBytes, digest | 201 UploadGrant |
| POST /v1/attempts/{id}/complete | leaseEpoch, completionId, outcome, resultManifest?, error? | 200 Attempt | | POST /v1/attempts/{id}/complete | leaseEpoch, completionId, outcome, resultManifest?, error? | 200 Attempt |
| POST /v1/attempts/{id}/suspend | leaseEpoch, checkpointArtifactId, inputRequest | 200 Run | | POST /v1/attempts/{id}/suspend | leaseEpoch, checkpointArtifactId, inputRequest | 200 Run |
Assignment: attemptId, runId, leaseEpoch, leaseUntil, executionSpec, executionToken. Execution token scoped к Attempt. Запрос claim authenticated идентичностью Runner; последующие операции — execution token. Назначение создаётся сервером атомарно; один claim выдаёт максимум один Attempt, availableSlots не разрешает превысить maxConcurrency пула. Assignment: attemptId, runId, leaseEpoch, leaseUntil, executionSpec, attemptContext, executionToken, tokenExpiresAt. См. [схему](../contracts/runner-assignment.schema.json). Execution token scoped к Attempt. Запрос claim authenticated идентичностью Runner; последующие операции — execution token. Назначение создаётся сервером атомарно; один claim выдаёт максимум один Attempt, availableSlots не разрешает превысить maxConcurrency пула.
Outcome: succeeded/failed/cancelled. Success требует ResultManifest и сохранённых объектов, даже если artifacts пуст. Error: code, message, retryableHint; решение о retry принимает платформа. Complete повторяется с тем же completionId и телом; другой payload после terminal state → 409. Поздние heartbeat, события и complete с прежним epoch → 409 LEASE_EXPIRED. События могут доставляться повторно; уникальны по attemptId + eventId. Outcome: succeeded/failed/cancelled. Success требует ResultManifest и сохранённых объектов, даже если artifacts пуст. Error: code, message, retryableHint; решение о retry принимает платформа. Complete повторяется с тем же completionId и телом; другой payload после terminal state → 409. Поздние heartbeat и события с прежним epoch → 409 LEASE_EXPIRED. Повтор уже принятого complete с тем же completionId и телом возвращает сохранённый ответ даже после истечения lease, но никогда не меняет состояние. Для этого replay допускается с действующей идентичностью назначенного Runner; новый terminal report с устаревшим epoch запрещён. События могут доставляться повторно; уникальны по attemptId + eventId.
Suspend допустим только для checkpoint-v1 + input-v1. InputRequest: id, schema, prompt, expiresAt. Платформа принимает checkpoint, переводит Run в waiting_input, отзывает lease; новый Attempt получает checkpointRef и проверенный ответ. Без checkpoint протокол не обещает сохранение памяти процесса. Suspend допустим только для checkpoint-v1 + input-v1. InputRequest: id, schema, prompt, expiresAt. Платформа принимает checkpoint, переводит Run в waiting_input, отзывает lease; новый Attempt получает checkpointRef и проверенный ответ в AttemptContext, отдельно от ExecutionSpec. Без checkpoint протокол не обещает сохранение памяти процесса.
## Локальный процесс ## Локальный процесс
@@ -35,3 +35,13 @@ Suspend допустим только для checkpoint-v1 + input-v1. InputRequ
## Минимальная проверка совместимости ## Минимальная проверка совместимости
Runner обязан показать: корректный success; failure; отказ при несовместимом spec; отмену; тайм-аут; повтор complete без дублей; отказ с просроченным lease; изоляцию файлов между задачами; корректный upload digest; отсутствие secrets в событиях. Resume проверяется только при соответствующей capability. Managed и customer-managed пулы отображаются раздельно. Runner обязан показать: корректный success; failure; отказ при несовместимом spec; отмену; тайм-аут; повтор complete без дублей; отказ с просроченным lease; изоляцию файлов между задачами; корректный upload digest; отсутствие secrets в событиях. Resume проверяется только при соответствующей capability. Managed и customer-managed пулы отображаются раздельно.
## Восстановление потерянного ответа
claimRequestId уникален в пределах runnerId. Повтор claim с тем же ID и телом возвращает то же назначение (или исходный 204), не занимает новый слот. Дедупликация хранится 24 часа; перед повторным получением работы после reconnect Runner вызывает GET /v1/runners/{id}/assignments (200 {items:[Assignment]}) со своей идентичностью. Endpoint возвращает только активные назначения этого Runner и перевыпускает их короткие токены. Если lease уже утрачен, старую работу прекращают; восстановление не продлевает истёкший lease.
Heartbeat продлевает lease и executionToken не дальше deadlineAt. Complete ID и хеш тела сохраняются до удаления Run. Sequence монотонен внутри потока событий; heartbeat/started имеют отдельный счётчик controlSequence (поле sequence в этих запросах), чтобы доставка логов не блокировала lease. Повтор с тем же номером и другим телом — 409. Конфликт события по eventId либо sequence также даёт 409. Клиент сериализует control-запросы.
ResultManifest валидируется по [схеме](../contracts/result-manifest.schema.json), а output — дополнительно по outputSchemaRef шаблона. InputRequest schema использует тот же ограниченный профиль, что формы настроек. Событие input_requested информационное; только успешный suspend меняет состояние.
Повтор claim не возобновляет утраченную аренду: если сохранённое назначение уже неактивно, сервер возвращает 409 ASSIGNMENT_EXPIRED. Перед запуском из повторного ответа Runner проверяет leaseUntil по серверному времени. ClaimRequestId с иным телом возвращает 409. Поля runId в Assignment и вложенном ExecutionSpec должны совпадать; server validator проверяет это отдельно от JSON Schema.
+35
View File
@@ -0,0 +1,35 @@
# Provider API v1
Platform identity и provider identity независимы. Все операции требуют текущего actor и tenant; запрос к provider mode допускается только если матрица разрешает local/on_prem/managed_remote. Provider broker — модуль Platform API для управляемых credentials, локальный аналог — sidecar; provider plugin вызывается в изолированном host, а не внутри API-процесса.
| Метод и путь | Запрос | Ответ |
|---|---|---|
| GET /v1/providers | deploymentMode | 200 {items:[ProviderDescriptor]} |
| POST /v1/provider-auth-flows | providerId, methodId, placement, returnRoute | 201 AuthFlow |
| GET /v1/provider-auth-flows/{id} | — | 200 AuthFlow с текущим status |
| DELETE /v1/provider-auth-flows/{id} | — | 204, flow cancelled |
| GET /v1/provider-auth/callback/{providerId} | state, code или error | 303 на allowlisted внутренний returnRoute |
| GET /v1/connections/{id} | — | 200 ConnectionSummary |
| POST /v1/connections/{id}/verify | — | 200 {status, capabilities, checkedAt} |
| GET /v1/connections/{id}/models | cursor, limit | 200 Page<ModelDescriptor> |
| DELETE /v1/connections/{id} | — | 204 после платформенного revoke; remote revoke best effort с аудитом |
ProviderDescriptor: id, pluginVersionId, methods:[{id, kind:api_key/oauth_pkce/device_code/official_client, allowedPlacements, status:enabled/gated/unsupported, reason?}], capabilitiesRevision. methodId определяется provider adapter; браузер не выбирает произвольный OAuth endpoint.
AuthFlow: id, providerId, methodId, status:pending/connected/failed/expired/cancelled, expiresAt, action:{type:open_url/device_code/local_client, url?, userCode?, intervalSeconds?}, connectionId?. PKCE verifier, refresh token и client secret не возвращаются клиенту. returnRoute — относительный allowlisted путь. API-key создаётся через защищённый POST /v1/connections, описанный ниже, не через GET callback.
ConnectionSummary: id, tenantId, ownerId, providerId, pluginVersionId, authMode, placement, bindingId?, status:active/reauth_required/revoked/error, scopes, accountLabel, expiresAt?, capabilitiesRevision. bindingId для runner_private_store привязывает к одному разрешённому пулу/пользовательскому окружению. Verify не выполняет платный inference без отдельного opt-in; model list не гарантирует entitlement.
POST auth flow и verify принимают Idempotency-Key. OAuth callback одноразовый, проверяет state, expiry, actor binding и exact redirect URI; при потере пользовательской сессии завершение требует reauth владельца. Device polling выполняет broker по interval, не каждая открытая вкладка. Authentication errors возвращаются нормализованно без raw provider token response.
## Инференс как внутренний контракт
ProviderInvocation: invocationId, runId, attemptId, connectionId, modelId, request, deadlineAt, capabilityRequirements. Доступ проверяется по executionToken и активному lease. Обёртка DSH нормализует stream events, usageStatus и terminal outcome. Credentials доступны только разрешённому adapter/официальному клиенту; shared глобального аккаунта нет. Внешний provider request id сохраняется для диагностики и дедупликации, если API поддерживает её.
## Передача API key
POST /v1/connections принимает {providerId, methodId, placement, label, credentialInput?, bindingId?}; ответ 201 ConnectionSummary. Для server_vault credentialInput={apiKey:string} передаётся только в TLS body, исключается из access/error logs, tracing и сохранения idempotency payload; сервер хранит только хеш запроса и зашифрованный ключ. Для local_keychain/runner_private_store ключ принимает локальный broker, облачный API получает только подтверждённый bindingId. Переданный клиентом bindingId проверяется на владельца и proof-of-possession от доверенного broker. API не принимает локальный путь к чужому файлу или произвольный vault URI.
GET /v1/connections принимает cursor/limit и возвращает Page<ConnectionSummary>. ModelDescriptor: id, providerId, displayName, capabilities, contextWindow?, availability:unknown/available/unavailable, checkedAt?. Поля capabilities — набор поддержанных операций (text, tools, image_input, structured_output), а не гарантия доступа к модели по подписке.
AuthFlow создаётся только для oauth_pkce/device_code/official_client. Callback OAuth использует GET только для провайдеров с query response mode; иной response mode требует отдельного адаптера и conformance. По истечении expiresAt flow больше не может создавать connection. Внешний callback без пользовательской cookie проверяет flow binding, а выдача connection пользователю требует исходную сессию либо повторный вход владельца.
+13 -3
View File
@@ -13,14 +13,14 @@
| POST /v1/runs/{id}/cancel | reason? | 202 Run | Идемпотентная команда; terminal run → 409 | | POST /v1/runs/{id}/cancel | reason? | 202 Run | Идемпотентная команда; terminal run → 409 |
| POST /v1/runs/{id}/retry | acknowledgedExternalEffects:boolean | 202 новый Run | parentRunId, новый ключ, проверка policy | | POST /v1/runs/{id}/retry | acknowledgedExternalEffects:boolean | 202 новый Run | parentRunId, новый ключ, проверка policy |
| POST /v1/runs/{id}/responses | responseId, inputRequestId, value | 202 Run | Только waiting_input; схема ответа и права | | POST /v1/runs/{id}/responses | responseId, inputRequestId, value | 202 Run | Только waiting_input; схема ответа и права |
| POST /v1/schedules | agentId, cron, timezone, overlapPolicy | 201 Schedule | operator; cron и timezone валидируются | | POST /v1/schedules | agentId, agentRevision, cron, timezone, overlapPolicy, misfirePolicy? | 201 Schedule | operator; cron и timezone валидируются |
| PATCH /v1/schedules/{id} | cron?, timezone?, enabled?, overlapPolicy?; If-Match | 200 Schedule | 412 conflict | | PATCH /v1/schedules/{id} | agentRevision?, cron?, timezone?, enabled?, overlapPolicy?, misfirePolicy?; If-Match | 200 Schedule | 412 conflict |
| GET /v1/schedules | cursor, limit | 200 Page<Schedule> | Tenant-scoped | | GET /v1/schedules | cursor, limit | 200 Page<Schedule> | Tenant-scoped |
| DELETE /v1/schedules/{id} | If-Match | 204 | Останавливает будущие, не текущие Run | | DELETE /v1/schedules/{id} | If-Match | 204 | Останавливает будущие, не текущие Run |
Run: id, tenantId, agentId, agentRevisionId, status, specDigest, createdAt, startedAt?, finishedAt?, attemptCount, parentRunId?, error?, resultManifest?, inputRequest?. Полный spec доступен только субъектам с run:read-config; обычный status не содержит конфигурацию. Run: id, tenantId, agentId, agentRevisionId, status, specDigest, createdAt, startedAt?, finishedAt?, attemptCount, parentRunId?, error?, resultManifest?, inputRequest?. Полный spec доступен только субъектам с run:read-config; обычный status не содержит конфигурацию.
Schedule: id, tenantId, agentId, cron, timezone, overlapPolicy (skip/queue), enabled, nextRunAt, revision. Каждое срабатывание фиксирует текущую ревизию агента; уже созданный Run не меняется при обновлении агента. Cron интерпретируется как пять полей (минута, час, день месяца, месяц, день недели); шаг менее минуты не поддерживается. Schedule: id, tenantId, agentId, agentRevisionId, cron, timezone, overlapPolicy (skip/queue), misfirePolicy (skip/coalesce), enabled, nextRunAt, revision. Расписание закрепляет agentRevisionId при создании. Новая ревизия применяется только явным PATCH расписания; уже созданные Run не меняются. Cron интерпретируется как пять полей (минута, час, день месяца, месяц, день недели); шаг менее минуты не поддерживается.
Limits: cpuMillis, memoryBytes, timeoutSeconds, outputBytes. Пользователь может запросить меньше предела policy; превышение даёт 422, а не скрытое повышение прав. Input — JSON по input schema template. PoolId не даёт доступ к чужому пулу. Limits: cpuMillis, memoryBytes, timeoutSeconds, outputBytes. Пользователь может запросить меньше предела policy; превышение даёт 422, а не скрытое повышение прав. Input — JSON по input schema template. PoolId не даёт доступ к чужому пулу.
@@ -31,3 +31,13 @@ Limits: cpuMillis, memoryBytes, timeoutSeconds, outputBytes. Пользоват
``` ```
Отмена не гарантирует отмену уже совершённого внешнего действия. Reconcile технического статуса выполняет сервис исполнения; пользовательский запрос не переписывает состояние Runner произвольно. Отмена не гарантирует отмену уже совершённого внешнего действия. Reconcile технического статуса выполняет сервис исполнения; пользовательский запрос не переписывает состояние Runner произвольно.
## Семантика расписаний
GET /v1/schedules/{id} возвращает Schedule. POST /v1/schedules/preview принимает cron, timezone, from, count (1–10) и возвращает {occurrences:[UTC timestamp], warnings:[]}; сохранения не выполняет. Pause — PATCH enabled=false, resume — PATCH enabled=true; оба требуют If-Match. Возобновление не догоняет периоды явной паузы.
Cron: пять полей; день недели 0–6 (0 — воскресенье); если day-of-month и day-of-week ограничены одновременно, применяется OR. DST: несуществующее локальное время пропускается, двойное — первое вхождение. Обновление tzdata пересчитывает только будущие occurrences; версия tzdata записывается в аудит. Первый релиз не поддерживает jitter и интервалы меньше минуты.
Skip отбрасывает occurrence, если у расписания есть нетерминальный Run. Queue допускает один активный и максимум один ожидающий Run; лишние occurrences объединяются с ожидающим. При простое misfirePolicy=coalesce (default) выбирает последний пропущенный occurrence, skip не создаёт Run. Уникальность (scheduleId, scheduledAt) гарантируется БД. Проверка overlap и создание Run выполняются под блокировкой строки Schedule в одной транзакции. Ручные Run не учитываются в overlap, но учитываются в квотах tenant.
Отзыв доступа к агенту/connection, блокировка пакета и архивирование агента останавливают расписание с reason, не создавая бесконечную череду failed Run. Любой запуск повторно проверяет права владельца расписания. Локальное расписание требует работающего daemon; перенос в облако отключает прежнего владельца до включения нового.
+6
View File
@@ -27,3 +27,9 @@ Resolver принимает templateVersionId и профиль среды. Он
Deprecated версия доступна закреплённым агентам, но скрыта из стандартного выбора. Удаление referenced-версии возвращает 409. Физическая очистка допускается после retention запусков, проверки ссылок и grace period. Immutable артефакты адресуются по digest; signed URL не сохраняется в постоянном lock. Deprecated версия доступна закреплённым агентам, но скрыта из стандартного выбора. Удаление referenced-версии возвращает 409. Физическая очистка допускается после retention запусков, проверки ссылок и grace period. Immutable артефакты адресуются по digest; signed URL не сохраняется в постоянном lock.
API: [catalog-api.md](api/catalog-api.md). Все диаграммы: [design.md](design.md). API: [catalog-api.md](api/catalog-api.md). Все диаграммы: [design.md](design.md).
## DSH и схемы ввода/вывода
Каталог хранит оригинальный DSH plugin artifact вместе с платформенным manifest envelope. Поля dshCompatibility фиксируют диапазон DSH, runtime, entry module и поддержанный профиль; tested versions и digest находятся в отчёте проверки каталога. Декларация автора не даёт badge совместимости. Плагины с зависимостью от API платформы явно объявляют endpoint и scopes; offline режим может не поддерживаться.
Template публикует inputSchemaRef и outputSchemaRef в том же архиве. Resolver включает архив по digest в lock, а API валидирует input до создания Run и output до success. UI схемы относятся к настройкам; дополнительные права не могут выдаваться значениями формы. См. [DSH foundation](dsh-foundation.md) и [плагины](plugins.md).
+2
View File
@@ -36,3 +36,5 @@ PUT конфигурации требует If-Match. При конфликте
- [Пример схемы](contracts/examples/config.schema.json) - [Пример схемы](contracts/examples/config.schema.json)
- [Начальные значения](contracts/examples/config.defaults.json) - [Начальные значения](contracts/examples/config.defaults.json)
- [Представление формы](contracts/examples/ui.schema.json) - [Представление формы](contracts/examples/ui.schema.json)
Ограниченный набор JSON Schema keywords относится к пользовательским формам config/input. Служебные схемы протокола могут использовать allOf/if/then и не передаются renderer. Версия профиля валидатора закрепляется вместе с шаблоном; несовместимая схема отвергается при публикации.
+13 -5
View File
@@ -11,13 +11,13 @@
| VersionPolicy | versionId, status, reason, revision | Catalog | | VersionPolicy | versionId, status, reason, revision | Catalog |
| Agent | id, tenantId, ownerId, name, currentRevision | Platform API | | Agent | id, tenantId, ownerId, name, currentRevision | Platform API |
| AgentRevision | id, agentId, revision, templateVersionId, config, connections, schemaDigest | Platform API | | AgentRevision | id, agentId, revision, templateVersionId, config, connections, schemaDigest | Platform API |
| Connection | id, tenantId, provider, scopes, encryptedSecretRef | Secrets / Platform API | | Connection | id, tenantId, ownerId, providerId, authMode, placement, status, secretBindingRef | Secrets / Platform API |
| Run | id, tenantId, agentRevisionId, status, specDigest, parentRunId | Platform API | | Run | id, tenantId, agentRevisionId, status, specDigest, parentRunId | Platform API |
| Attempt | id, runId, runnerId, leaseEpoch, leaseUntil, status | Dispatcher | | Attempt | id, runId, runnerId, leaseEpoch, leaseUntil, status | Dispatcher / Platform DB |
| RunnerPool | id, tenantId, trustPolicy, quotas | Dispatcher | | RunnerPool | id, tenantId, trustPolicy, quotas | Dispatcher / Platform DB |
| Runner | id, poolId, capabilities, credentialStatus, lastSeenAt | Dispatcher | | Runner | id, poolId, capabilities, credentialStatus, lastSeenAt | Dispatcher / Platform DB |
| Artifact | id, runId, attemptId, objectKey, digest, sizeBytes, mediaType | Platform API | | Artifact | id, runId, attemptId, objectKey, digest, sizeBytes, mediaType | Platform API |
| Schedule | id, agentId, cron, timezone, nextRunAt, overlapPolicy | Dispatcher | | Schedule | id, agentId, agentRevisionId, cron, timezone, nextRunAt, overlapPolicy, misfirePolicy | Dispatcher / Platform DB |
| Outbox | id, aggregateId, eventType, payload, deliveredAt | Пишущий сервис | | Outbox | id, aggregateId, eventType, payload, deliveredAt | Пишущий сервис |
## Инварианты ## Инварианты
@@ -42,3 +42,11 @@
Id — opaque string. Version — SemVer строка; разрешение диапазонов выполняет resolver до фиксации ExecutionSpec. Digest — SHA-256. Timestamps — RFC3339 UTC. UUID не навязывается публичным контрактом. Id — opaque string. Version — SemVer строка; разрешение диапазонов выполняет resolver до фиксации ExecutionSpec. Digest — SHA-256. Timestamps — RFC3339 UTC. UUID не навязывается публичным контрактом.
Package manifest с kind=template обязан указать harnessVersionId, configSchemaRef и зависимости. Harness обязан указать entrypoint и executionKind. Plugin и skill указывают совместимость supportedHarnesses. Отсутствующая optional capability означает, что возможность недоступна; поле не может быть выведено из названия пакета. Package manifest с kind=template обязан указать harnessVersionId, configSchemaRef и зависимости. Harness обязан указать entrypoint и executionKind. Plugin и skill указывают совместимость supportedHarnesses. Отсутствующая optional capability означает, что возможность недоступна; поле не может быть выведено из названия пакета.
Run, Attempt, Schedule и reservations составляют одну транзакционную область Platform DB. Внешние Execution DB и Catalog DB не принимают бизнес-переходы Run. Подробнее: [исполнение](../execution.md).
- [Assignment и AttemptContext](runner-assignment.schema.json): контекст попытки отдельно от неизменяемого spec.
- [ResultManifest](result-manifest.schema.json): результат и проверяемые артефакты.
- [Provider API](../api/provider-api.md): канонический ConnectionSummary; secretBindingRef остаётся серверным полем.
inputSchemaRef и outputSchemaRef обязательны для template. Все schemaRef — пути внутри проверенного архива версии; произвольные сетевые $ref запрещены. DSH-плагин указывает dshCompatibility; статус совместимости выставляется каталогом по отдельному отчёту, а не самим автором.
@@ -0,0 +1,15 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Company input",
"type": "object",
"additionalProperties": false,
"required": [
"company"
],
"properties": {
"company": {
"type": "string",
"minLength": 1
}
}
}
@@ -0,0 +1,15 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Research output",
"type": "object",
"additionalProperties": false,
"required": [
"summary"
],
"properties": {
"summary": {
"type": "string",
"minLength": 1
}
}
}
@@ -23,5 +23,7 @@
"cancel-v1" "cancel-v1"
], ],
"requiredPermissions": [], "requiredPermissions": [],
"retrySafe": false "retrySafe": false,
"inputSchemaRef": "input.schema.json",
"outputSchemaRef": "output.schema.json"
} }
@@ -132,12 +132,6 @@
"type": "string", "type": "string",
"minLength": 1 "minLength": 1
} }
}, }
"checkpointRef": {
"type": "string",
"minLength": 1,
"maxLength": 128
},
"resumeInput": {}
} }
} }
@@ -134,6 +134,45 @@
}, },
"retrySafe": { "retrySafe": {
"type": "boolean" "type": "boolean"
},
"inputSchemaRef": {
"type": "string",
"minLength": 1
},
"outputSchemaRef": {
"type": "string",
"minLength": 1
},
"dshCompatibility": {
"type": "object",
"additionalProperties": false,
"required": [
"dshVersionRange",
"nodeVersionRange",
"entryModule",
"profile"
],
"properties": {
"dshVersionRange": {
"type": "string",
"minLength": 1
},
"nodeVersionRange": {
"type": "string",
"minLength": 1
},
"entryModule": {
"type": "string",
"minLength": 1
},
"profile": {
"enum": [
"headless",
"web",
"both"
]
}
}
} }
}, },
"allOf": [ "allOf": [
@@ -148,7 +187,9 @@
"then": { "then": {
"required": [ "required": [
"harnessVersionId", "harnessVersionId",
"configSchemaRef" "configSchemaRef",
"inputSchemaRef",
"outputSchemaRef"
] ]
} }
}, },
@@ -0,0 +1,44 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "ResultManifest v1",
"type": "object",
"additionalProperties": false,
"required": [
"output",
"artifacts"
],
"properties": {
"output": {},
"artifacts": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"artifactId",
"digest",
"sizeBytes",
"mediaType"
],
"properties": {
"artifactId": {
"type": "string",
"minLength": 1
},
"digest": {
"type": "string",
"pattern": "^sha256:[a-f0-9]{64}$"
},
"sizeBytes": {
"type": "integer",
"minimum": 0
},
"mediaType": {
"type": "string",
"minLength": 1
}
}
}
}
}
}
@@ -42,5 +42,156 @@
"payload": { "payload": {
"type": "object" "type": "object"
} }
},
"allOf": [
{
"if": {
"properties": {
"type": {
"const": "progress"
} }
}
},
"then": {
"properties": {
"payload": {
"type": "object",
"additionalProperties": false,
"required": [
"message"
],
"properties": {
"message": {
"type": "string",
"minLength": 1
},
"fraction": {
"type": "number",
"minimum": 0,
"maximum": 1
}
}
}
}
}
},
{
"if": {
"properties": {
"type": {
"const": "log"
}
}
},
"then": {
"properties": {
"payload": {
"type": "object",
"additionalProperties": false,
"required": [
"level",
"message"
],
"properties": {
"level": {
"enum": [
"debug",
"info",
"warn",
"error"
]
},
"message": {
"type": "string",
"minLength": 1
}
}
}
}
}
},
{
"if": {
"properties": {
"type": {
"const": "artifact_ready"
}
}
},
"then": {
"properties": {
"payload": {
"type": "object",
"additionalProperties": false,
"required": [
"artifactId"
],
"properties": {
"artifactId": {
"type": "string",
"minLength": 1
}
}
}
}
}
},
{
"if": {
"properties": {
"type": {
"const": "input_requested"
}
}
},
"then": {
"properties": {
"payload": {
"type": "object",
"additionalProperties": false,
"required": [
"inputRequestId"
],
"properties": {
"inputRequestId": {
"type": "string",
"minLength": 1
}
}
}
}
}
},
{
"if": {
"properties": {
"type": {
"const": "diagnostic"
}
}
},
"then": {
"properties": {
"payload": {
"type": "object",
"additionalProperties": false,
"required": [
"code",
"message"
],
"properties": {
"code": {
"type": "string",
"minLength": 1
},
"message": {
"type": "string",
"minLength": 1
}
}
}
}
}
}
]
} }
@@ -0,0 +1,83 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Runner Assignment v1",
"type": "object",
"additionalProperties": false,
"required": [
"attemptId",
"runId",
"leaseEpoch",
"leaseUntil",
"executionSpec",
"attemptContext",
"executionToken",
"tokenExpiresAt"
],
"properties": {
"attemptId": {
"type": "string",
"minLength": 1
},
"runId": {
"type": "string",
"minLength": 1
},
"leaseEpoch": {
"type": "integer",
"minimum": 1
},
"leaseUntil": {
"type": "string",
"format": "date-time"
},
"executionSpec": {
"$ref": "execution-spec.schema.json"
},
"attemptContext": {
"type": "object",
"additionalProperties": false,
"required": [
"deadlineAt"
],
"properties": {
"deadlineAt": {
"type": "string",
"format": "date-time"
},
"continuation": {
"type": "object",
"additionalProperties": false,
"required": [
"checkpointRef",
"inputRequestId",
"responseId",
"resumeInput"
],
"properties": {
"checkpointRef": {
"type": "string",
"minLength": 1
},
"inputRequestId": {
"type": "string",
"minLength": 1
},
"responseId": {
"type": "string",
"minLength": 1
},
"resumeInput": {}
}
}
}
},
"executionToken": {
"type": "string",
"minLength": 1
},
"tokenExpiresAt": {
"type": "string",
"format": "date-time"
}
}
}
+102 -5
View File
@@ -5,6 +5,9 @@
| Термин | Значение | | Термин | Значение |
|---|---| |---|---|
| Harness | Движок и обвязка агента: цикл выполнения, управление контекстом, состоянием и вызовами инструментов | | Harness | Движок и обвязка агента: цикл выполнения, управление контекстом, состоянием и вызовами инструментов |
| DSH | DeepSeek Harness — исходная база стандартного agent runtime Invest Harness |
| Connection | Подключение к провайдеру: способ входа, права, место хранения credentials и их состояние |
| AttemptContext | Deadline и данные продолжения конкретной попытки, отдельно от ExecutionSpec |
| Runtime | Среда выполнения программы: например, Node.js или Python; определяется пакетом harness’а | | Runtime | Среда выполнения программы: например, Node.js или Python; определяется пакетом harness’а |
| Plugin | Программное расширение, добавляющее инструменты, интеграции или возможности | | Plugin | Программное расширение, добавляющее инструменты, интеграции или возможности |
| Skill | Инструкции и вспомогательные материалы для конкретной задачи; может содержать скрипты, но сам по себе не предоставляет доступы | | Skill | Инструкции и вспомогательные материалы для конкретной задачи; может содержать скрипты, но сам по себе не предоставляет доступы |
@@ -22,7 +25,7 @@
## Концепция и статус ## Концепция и статус
Invest Harness — платформа агентов для инвестиций. Автор публикует шаблон и его зависимости, пользователь выбирает шаблон, настраивает его через автоматически построенную форму и запускает локально или удалённо. Оба режима используют один формат пакетов и ExecutionSpec. Invest Harness — платформа агентов для инвестиций. Автор публикует шаблон и его зависимости, пользователь выбирает шаблон, настраивает его через автоматически построенную форму и запускает локально или удалённо. Оба режима используют один формат пакетов и ExecutionSpec. Стандартный агент строится на DSH с собственным интерфейсом и исправленным разделением ядра, конфигурации, credentials и исполнения. Плагины сохраняют совместимость с публичным API DSH в проверенном профиле; другие harness также допускаются.
Документ задаёт целевую архитектуру и контракты первой версии. Реализация сервисов пока не входит в этот репозиторий. Выбранные технологии — проектные решения; численные показатели масштабирования — гипотезы до измерений. Документ задаёт целевую архитектуру и контракты первой версии. Реализация сервисов пока не входит в этот репозиторий. Выбранные технологии — проектные решения; численные показатели масштабирования — гипотезы до измерений.
@@ -69,13 +72,13 @@ flowchart TB
W["Web UI / Container / React, TypeScript, JSON Forms"] W["Web UI / Container / React, TypeScript, JSON Forms"]
I["Identity / Logical component of platform API / Sessions, OIDC"] I["Identity / Logical component of platform API / Sessions, OIDC"]
B["Platform API / Container / Go, REST"] B["Platform API / Container / Go, REST"]
DB[("Platform DB / PostgreSQL / роли, агенты, запуски, аудит")] DB[("Platform DB / PostgreSQL / роли, агенты, Run, Attempt, расписания, аудит")]
C["Каталог / Container / Go, REST"] C["Каталог / Container / Go, REST"]
CD[("Catalog DB / PostgreSQL / пакеты и версии")] CD[("Catalog DB / PostgreSQL / пакеты и версии")]
PS[("Package Storage / S3 / архивы плагинов, скиллов, шаблонов")] PS[("Package Storage / S3 / архивы плагинов, скиллов, шаблонов")]
D["Диспетчер / Container / Go"] D["Диспетчер / Container / Go"]
E["Сервис исполнения / Container / Go / workflow, jobs, адаптер"] E["Сервис исполнения / Container / Go / workflow, jobs, адаптер"]
ED[("Execution DB / PostgreSQL / назначения и статусы движка")] ED[("Execution DB / PostgreSQL / executionId mapping и технические статусы")]
R["Registry API / Component of execution service / Go, OCI"] R["Registry API / Component of execution service / Go, OCI"]
RS[("Registry Storage / S3 / манифесты и слои образов")] RS[("Registry Storage / S3 / манифесты и слои образов")]
ES[("Execution Storage / S3 / логи и технические артефакты")] ES[("Execution Storage / S3 / логи и технические артефакты")]
@@ -116,7 +119,7 @@ flowchart TB
T --> S T --> S
T --> M T --> M
B --> F B --> F
D --> S B --> S
B -.-> O B -.-> O
C -.-> O C -.-> O
E -.-> O E -.-> O
@@ -195,6 +198,9 @@ flowchart TB
| Система | Стек | Как создаётся | | Система | Стек | Как создаётся |
|---|---|---| |---|---|---|
| DSH adapter / plugin host | TypeScript, Node.js, DSH / Cordis | Переработанные границы ядра; публичный plugin API сохраняется |
| Standalone app | TypeScript, React; Electron / Capacitor | Общие формы, desktop sidecar; mobile управляет Runner |
| Provider broker | Go API + изолированные TypeScript provider plugins | Вход, хранение bindings, обновление и отзыв credentials |
| Web UI | TypeScript, React, JSON Forms | Новый интерфейс | | Web UI | TypeScript, React, JSON Forms | Новый интерфейс |
| Platform API и identity | Go, REST, OpenAPI, сессии, OIDC | Продуктовый API с адаптацией существующих механизмов аккаунтов | | Platform API и identity | Go, REST, OpenAPI, сессии, OIDC | Продуктовый API с адаптацией существующих механизмов аккаунтов |
| Каталог | Go, PostgreSQL, S3 API | Новый отдельный сервис | | Каталог | Go, PostgreSQL, S3 API | Новый отдельный сервис |
@@ -329,6 +335,9 @@ stateDiagram-v2
preparing --> running: окружение готово preparing --> running: окружение готово
running --> waiting_input: checkpoint и запрос ввода running --> waiting_input: checkpoint и запрос ввода
waiting_input --> queued: подтверждённое продолжение waiting_input --> queued: подтверждённое продолжение
waiting_input --> failed: INPUT_EXPIRED или deadline
preparing --> failed: deadline и остановка подтверждена
running --> failed: deadline и остановка подтверждена
running --> succeeded: результат принят running --> succeeded: результат принят
preparing --> failed: ошибка подготовки preparing --> failed: ошибка подготовки
running --> failed: ошибка running --> failed: ошибка
@@ -389,10 +398,91 @@ flowchart LR
MVP: четыре типа пакетов; immutable versions; конфигурация через формы; экземпляры агентов; ручной и регулярный запуск; стандартный и локальный Runner; документированный протокол своей реализации; отмена, события и результаты; tenant isolation; registry и buckets; аудит. MVP: четыре типа пакетов; immutable versions; конфигурация через формы; экземпляры агентов; ручной и регулярный запуск; стандартный и локальный Runner; документированный протокол своей реализации; отмена, события и результаты; tenant isolation; registry и buckets; аудит.
Следующий этап: возобновление через checkpoint, пользовательский ввод, автоматическая миграция конфигураций, Kubernetes Runner, автоматическое масштабирование и коммерческий биллинг. Протокол заранее резервирует эти возможности, но UI не предлагает их без подтверждённой capability. Полный MVP достигается поэтапно (P0–P5 ниже), а не одним релизом. Следующий этап: возобновление через checkpoint, пользовательский ввод, автоматическая миграция конфигураций, Kubernetes Runner, автоматическое масштабирование и коммерческий биллинг. Протокол заранее резервирует эти возможности, но UI не предлагает их без подтверждённой capability.
Открытые решения: провайдер KMS и S3, конкретные версии зависимостей, политика модерации публичных пакетов, целевые SLO после нагрузочных измерений, перечень лицензий распространяемых runtime и пакетов. Публичный доступ к этому проекту сам по себе не задаёт лицензию его дальнейшего использования. Открытые решения: провайдер KMS и S3, конкретные версии зависимостей, политика модерации публичных пакетов, целевые SLO после нагрузочных измерений, перечень лицензий распространяемых runtime и пакетов. Публичный доступ к этому проекту сам по себе не задаёт лицензию его дальнейшего использования.
## DSH: интерфейс и внутренняя архитектура
Свой UI показывает шаблоны, настройки, подключения, расписания и результаты. Внутри DSH сохраняются публичные точки подключения плагинов; platform adapter изолирует конфигурацию, credentials, запуск и состояния сессий. Runner остаётся заменяемым, а внутренний agent loop — чёрным ящиком для диспетчера.
```mermaid
flowchart LR
UI["UI / React + JSON Forms"] --> API["Platform API / Go"]
API --> SPEC["Immutable ExecutionSpec + AttemptContext"]
SPEC --> RUN["Runner / Go adapter или своя реализация"]
subgraph JOB["Job / изолированное окружение"]
AD["Invest Harness adapter / TypeScript"]
CORE["DSH core / Node.js, Cordis"]
PL["DSH-compatible plugins / TypeScript"]
SK["Skills / инструкции и ресурсы"]
AD --> CORE
CORE --> PL
CORE --> SK
end
RUN --> AD
PL --> BROKER["Provider broker / изолированный plugin host"]
BROKER --> STORE["KMS vault или локальное secret storage"]
BROKER --> EXT["LLM / официальный клиент / API"]
```
Совместимость подтверждается для конкретных версий DSH, runtime и плагина. Непроверенные пакеты не получают отметку совместимости; зависимость от платформенного API объявляется явно. Детали и исходные источники: [DSH foundation](dsh-foundation.md).
## Плагины и авторизация провайдеров
Первая линейка: provider-claude, provider-codex, provider-xai, provider-generic, recurring-tasks и package-discovery. Provider plugins поддерживают API keys и отдельно разрешённые способы входа в аккаунт. Наличие подписки само по себе не делает её доступной стороннему приложению; неподтверждённые режимы не включаются. Плагин расписаний обращается к единому Scheduler, а discovery ищет пакеты и показывает зависимости/разрешения до установки.
```mermaid
sequenceDiagram
participant U as Пользователь
participant UI as Web / Desktop / Mobile
participant B as Provider broker / сервер или sidecar
participant P as Провайдер / официальный клиент
participant S as Разрешённое secret storage
U->>UI: Выбрать провайдера и способ входа
UI->>B: Создать AuthFlow
B->>B: Проверить deployment mode и права
B-->>UI: URL / device code / official client action
U->>P: Подтвердить вход
P-->>B: Результат поддержанного auth flow
B->>S: Сохранить credentials или локальный binding
B-->>UI: ConnectionSummary без секретов
```
Для official_client авторизация завершается внутри неизменённого клиента; broker получает только статус/binding, не извлекает его tokens. Для API key используется отдельная защищённая передача. Полная матрица и правила: [плагины](plugins.md), [Provider API](api/provider-api.md), [API edge cases](provider-edge-cases.md).
## Режимы приложения и развёртывания
```mermaid
flowchart TB
WEB["Web / PWA / React"] --> CLOUD["Облачный control plane / Go, PostgreSQL, S3"]
MOBILE["Mobile / Capacitor + React"] --> CLOUD
MOBILE --> ONPREM["On-prem control plane / тот же стек"]
DESKTOP["Desktop / Electron + React"] --> SIDE["Локальный sidecar / Go"]
DESKTOP --> CLOUD
SIDE --> LOCAL["Local Runner / DSH Node.js или OCI"]
CLOUD --> MANAGED["Managed Runner"]
CLOUD --> OWN["Свой Runner"]
ONPREM --> PRIVATE["Runner внутри инфраструктуры клиента"]
```
Desktop выполняет локально через sidecar; mobile/PWA управляют Runner. On-prem означает размещение всей платформы у клиента; свой Runner при облачном API — отдельный режим. Local CLI остаётся самостоятельным способом запуска без обязательной облачной учётки.
## Roadmap и готовность
| Этап | Результат |
|---|---|
| P0 | DSH spike, фиксация версий, plugin compatibility и контракты |
| P1 | JSON Schema Driven компоненты и редактор конфигураций |
| P2 | Реестры harness/plugin/skill/template и discovery |
| P3 | Локальный и on-premise запуск |
| P4 | Managed и собственные Runner, регулярные задачи |
| P5 | Provider plugins и допущенные account modes |
| P6 | Standalone JS: desktop, mobile, PWA |
| P7 | Расширение API edge cases, нагрузка и эксплуатация |
Проверки ошибок и изоляции входят в каждый этап, а не откладываются до P7. [Roadmap с критериями выхода](roadmap.md). Начинать можно с P0–P2; [результат проверки дизайна](review.md) разделяет принятые решения и оставшиеся проверки реализации.
## Подробные спецификации ## Подробные спецификации
- [Каталог и версии](catalog.md) - [Каталог и версии](catalog.md)
@@ -406,3 +496,10 @@ MVP: четыре типа пакетов; immutable versions; конфигур
- [API запусков](api/runs-api.md) - [API запусков](api/runs-api.md)
- [Runner Protocol](api/executor-api.md) - [Runner Protocol](api/executor-api.md)
- [Модель данных и JSON Schema](contracts/domain-model.md) - [Модель данных и JSON Schema](contracts/domain-model.md)
- [База DSH](dsh-foundation.md)
- [Плагины](plugins.md)
- [Provider API](api/provider-api.md)
- [API edge cases](provider-edge-cases.md)
- [Roadmap](roadmap.md)
- [Проверка готовности](review.md)
+39
View File
@@ -0,0 +1,39 @@
# DSH как базовый harness
## Решение
Invest Harness использует DeepSeek Harness (DSH) как базовый движок агентов. Изменяем интерфейс и внутренние границы, сохраняя публичные контракты плагинов. Это целевой дизайн нашей сборки, а не утверждение, что все необходимые возможности уже реализованы в upstream.
Исходный ориентир spike — @deepseek-ai/dsh 0.2.2-rc.1, указанный в проверенном манифесте на 11.11.2026. Перед первым runtime-релизом фиксируются исходный commit, версии всех DSH-пакетов, lock зависимостей и digest сборки. Плавающий master не используется в опубликованных harness’ах. Сама версия пакета без проверки целостности недостаточна.
## Исправления интерфейса
Собственный JS-интерфейс строится вокруг пользователя: каталог → шаблон → настройки → подключения → запуск → результаты. Пользователь не редактирует внутреннюю конфигурацию движка. JSON Schema Driven UI обслуживает настройки harness, plugins и template с одинаковыми сообщениями об ошибках. Экран подключения явно различает API key, вход через аккаунт и локальный официальный клиент. История показывает состояние запуска и попыток, запросы ввода и источник расхода.
## Исправления архитектуры
| Граница | Решение Invest Harness | Критерий |
|---|---|---|
| Ядро и интерфейс | DSH session/agent/tools через runtime adapter; UI работает по продуктовым API | Замена UI не меняет ExecutionSpec |
| Конфигурация | Валидируемый config → детерминированная композиция DSH | Один lock даёт одинаковый состав пакетов |
| Credentials | Provider broker и хранилище отдельно от config | Секреты отсутствуют в snapshot и событиях |
| Планирование | DSH plugin обращается к сервису расписаний | Нет второго cloud cron внутри каждого job |
| Исполнение | Runner adapter отделён от agent loop | Один и тот же harness запускается локально и удалённо |
| Контекст | Отдельный workspace и DSH state directory для каждого Agent/Run с явной политикой сохранения | Нет смешения tenant-сессий |
| Обновления | Собственная версия сборки + upstream baseline + compatibility report | Плагин не ломается после незаметного обновления |
В DSH уже есть профили запуска и отдельный headless-режим. Платформенный адаптер нормализует поток событий и результат; он не считает произвольный stderr машинным протоколом. Продолжение сохранённой DSH-сессии требует исходных state files и совместимого workspace; оно не равно переносимому checkpoint без проверенного адаптера.
## Совместимость с DSH
Плагины реализуют публичные DSH/Cordis interfaces, объявляют peer dependencies и требования к сервисам. Каталог добавляет envelope публикации, не заменяя формат самого DSH-пакета. Наши стандартные плагины должны загружаться в проверенном upstream DSH с теми же public interfaces; платформенные операции требуют настроенного endpoint Invest Harness. При отсутствии endpoint плагин сообщает capability unavailable, не ломая запуск DSH.
Входящая совместимость не означает запуск любого стороннего плагина. Матрица фиксирует DSH version, plugin version, Node version, OS/architecture, permissions и surfaces: headless/web/local. Проверки: load/dispose, регистрация tools, config validation, streaming, cancellation, credential refresh, отсутствие зависимостей от private APIs. Плагин, требующий внутренний UI DSH, получает ui-specific статус и адаптер; он не объявляется автоматически совместимым с новым UI.
Несовместимая смена API меняет compatibility profile; resolver отказывает до запуска. Lifecycle адаптации и возможности безопасности остаются частью сборки, а не требуют silent monkey patch каждого плагина.
## Основа и ограничения лицензирования
DSH опубликован под MIT; сохраняем copyright и license notices в сборках. Состав сторонних пакетов проверяется для каждого распространяемого образа. Это не определяет лицензию всего Invest Harness и не заменяет условия моделей и провайдеров.
Источники: [CLI manifest](https://raw.githubusercontent.com/deepseek-ai/deepseek-harness/master/apps/cli/package.json), [Headless](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/headless/README.md), [Authorization service](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/credentials/authorization/README.md), [MIT](https://github.com/deepseek-ai/deepseek-harness/blob/master/LICENSE).
+12 -4
View File
@@ -6,15 +6,15 @@ Harness получает ExecutionSpec и разрешённые ресурсы.
## Планирование ## Планирование
API в одной транзакции записывает Run, reservation квоты и outbox. Диспетчер обрабатывает outbox идемпотентно по runId. Resolve выполняется до создания снимка; назначение повторно проверяет block policy и права. Попытка захватывается атомарно с leaseEpoch. Стандартный execution adapter использует runId/attemptId как ключ дедупликации, хранит соответствие с executionId движка и сверяет состояние при неоднозначном ответе. API в одной транзакции записывает Run, reservation бюджета/места в очереди и outbox. Слот активного исполнения резервируется только при claim. Диспетчер обрабатывает outbox идемпотентно по runId. Resolve выполняется до создания снимка; назначение повторно проверяет block policy и права. Попытка захватывается атомарно с leaseEpoch. Стандартный execution adapter использует runId/attemptId как ключ дедупликации, хранит соответствие с executionId движка и сверяет состояние при неоднозначном ответе.
Расписания хранят IANA timezone, cron expression, nextRunAt и overlapPolicy: skip или queue. В MVP catch-up после простоя создаёт не более одного пропущенного запуска. Уникальный ключ scheduleId + scheduledAt предотвращает дубли. При переходах DST пропущенное локальное время пропускается, повторённое выполняется один раз; scheduledAt фиксируется как UTC instant. Ручной запуск имеет отдельный ключ. Расписания закрепляют agentRevisionId, IANA timezone, cron expression, nextRunAt и overlapPolicy: skip или queue. Политика misfire: skip либо coalesce (по умолчанию), создающая не более одного запуска за простой. Queue удерживает максимум одно ожидающее срабатывание; следующие объединяются с ним. Уникальный ключ scheduleId + scheduledAt предотвращает дубли. При переходах DST пропущенное локальное время пропускается, повторённое выполняется один раз; scheduledAt фиксируется как UTC instant. Ручной запуск имеет отдельный ключ.
## Lease и повторы ## Lease и повторы
Начальные настройки: lease 90 секунд, heartbeat каждые 20 секунд, maxAttempts 3 только для явно retry-safe задач. Важна серверная шкала времени. Каждый heartbeat и terminal report содержит attemptId, leaseEpoch и sequence. Устаревший epoch возвращает 409 и не может изменить состояние Run. Начальные настройки: lease 90 секунд, heartbeat каждые 20 секунд, maxAttempts 3 только для явно retry-safe задач. Важна серверная шкала времени. Каждый heartbeat и terminal report содержит attemptId, leaseEpoch и sequence. Устаревший epoch возвращает 409 и не может изменить состояние Run.
Потеря lease переводит Run в interrupted. Автоповтор разрешён, только если template объявил retrySafe и policy организации позволяет; иначе нужен явный retry пользователя после предупреждения о возможном повторе внешних действий. Checkpoint continuation создаёт новый Attempt того же Run. Retry terminal Run создаёт новый Run с parentRunId и тем же снимком, но с актуальной проверкой прав. Потеря lease переводит Run в interrupted. Автоповтор разрешён, только если template объявил retrySafe и policy организации позволяет; иначе нужен явный retry пользователя после предупреждения о возможном повторе внешних действий. Checkpoint continuation создаёт новый Attempt того же Run. Retry terminal Run создаёт новый Run с parentRunId и копией настроек и зависимостей, новым runId и specDigest и актуальной проверкой прав.
Fencing защищает записи платформы, но не останавливает старый процесс на недоступной машине и не обеспечивает exactly-once сторонних API. Повторные внешние действия должен защищать сам harness или поддерживающий idempotency key шлюз. Fencing защищает записи платформы, но не останавливает старый процесс на недоступной машине и не обеспечивает exactly-once сторонних API. Повторные внешние действия должен защищать сам harness или поддерживающий idempotency key шлюз.
@@ -30,6 +30,14 @@ Waiting_input поддерживается только с capability checkpoint
## Артефакты ## Артефакты
Runner запрашивает upload grant для конкретного Attempt и назначения файла. Grant ограничен размером, сроком и префиксом. ResultManifest содержит artifactId, digest, size и mediaType, без произвольных URL. Сервис проверяет существование объектов до terminal success. Логи доставляются отдельно и не являются единственным источником состояния. Runner запрашивает upload grant для конкретного Attempt и назначения файла. Grant ограничен размером, сроком и префиксом. ResultManifest содержит artifactId, digest, sizeBytes и mediaType, без произвольных URL. Сервис проверяет существование объектов до terminal success. Логи доставляются отдельно и не являются единственным источником состояния.
[Runner Protocol](api/executor-api.md) · [Состояния и диаграммы](design.md). [Runner Protocol](api/executor-api.md) · [Состояния и диаграммы](design.md).
## Владение состоянием и продолжение
Run, Attempt, Schedule, reservations и их outbox находятся в Platform DB. API и диспетчер используют общий модуль переходов состояния и транзакций. Execution DB хранит только техническое соответствие attemptId → executionId и состояние движка, а не второй источник истины Run. Финализация Attempt, Run, освобождение активного слота и outbox атомарны в Platform DB; события движка проходят тот же путь.
ExecutionSpec неизменяем на протяжении Run. Checkpoint и ответ пользователя передаются отдельно в AttemptContext внутри Assignment. Deadline фиксируется при первом назначении: timeoutSeconds ограничивает время Run с первого назначения, включая ожидание ввода и последующие очереди; продолжение не обнуляет deadline. Подтверждённая остановка по deadline завершает Run как failed с DEADLINE_EXCEEDED; неподтверждённая — interrupted без автоматического повтора. Истечение inputRequest.expiresAt завершает waiting_input как failed с INPUT_EXPIRED. Ошибка подготовки без внешних эффектов допускает bounded retry внутри preparing до maxAttempts; после исчерпания — failed.
После принятой отмены автоматический retry запрещён даже при interrupted. Reconciler проверяет deadline, протухшие lease и outbox; изменение статуса выполняется условно по текущему состоянию и epoch.
+49
View File
@@ -0,0 +1,49 @@
# Плагины Invest Harness
Плагины совместимы с публичным DSH plugin API в проверенной матрице версий. Harness — движок, template — состав агента, skill — инструкции, plugin — исполняемое расширение. Подключение аккаунта провайдера не является входом в Invest Harness.
## Первая линейка
| Плагин | Назначение | Результат |
|---|---|---|
| provider-claude | Claude API и поддерживаемая работа с аккаунтом через официальный клиент | ConnectionSummary, model capability profile |
| provider-codex | OpenAI API и согласованные account-based способы через Codex/Sign in with ChatGPT | ConnectionSummary с mode и execution placement |
| provider-xai | xAI API и исследуемый account flow официального клиента | Доступные способы входа, проверенные capabilities |
| provider-generic | Другие провайдеры через отдельные адаптеры; OpenAI-compatible не означает полную эквивалентность | Нормализованный адаптер моделей |
| recurring-tasks | Планирование регулярных задач из агента и формы | Сохранённое Schedule, preview ближайших запусков |
| package-discovery | Поиск плагинов, harness’ов, скиллов и шаблонов | Доступные пакеты, совместимость, preview установки |
Это план разработки, а не список уже установленных расширений. Account-based режим включается отдельно для каждой комбинации provider, deploymentMode, integrationPath. Если путь недоступен, UI показывает причину и API-вариант без скрытого переключения способа оплаты.
## Авторизация провайдеров
Методы провайдера перечисляет adapter discovery; браузер не получает client secret или refresh token. OAuth flow хранит state, PKCE, nonce где применимо, redirect allowlist, срок и tenant/actor binding. Device flow соблюдает polling interval и slow_down. Отмена и expiry завершают flow. Refresh выполняется single-flight на connectionId с атомарной заменой refresh token. invalid_grant переводит Connection в reauth_required; повторные login попытки не создаются автоматически.
Credential placement: local_keychain, runner_private_store или server_vault. Переход между ними требует нового разрешённого связывания; локальная подписка не переносится на hosted Runner неявно. Для official-client-mode provider broker хранит статус и binding, а не извлекает закрытые токены клиента.
| Провайдер | Подтверждённая основа | Решение для Invest Harness |
|---|---|---|
| Claude | Официальные условия различают API и подписку, запрещают стороннему приложению собирать Claude.ai session tokens; допускают собственный вход пользователя в неизменённый официальный клиент | API — базовый путь. Account plugin интегрирует официальный клиент в отдельном окружении после проверки условий; не подменяет его DSH OAuth-прокси |
| Codex / OpenAI | Официально описаны app-server и отдельный Sign in with ChatGPT для планового использования | Локальный/open-source app-server путь проверяется отдельно. Коммерческий hosted режим использует одобренную интеграцию Sign in with ChatGPT либо API; старый app-server login не считается разрешением на hosted сервис |
| xAI | Официальный Grok Build описывает browser/device login и API key | Наличие login у клиента не доказывает доступность произвольного DSH subscription adapter. Remote account mode gated до проверки; API доступен как отдельный режим |
| Другие | Условия и протокол определяет провайдер | Новый адаптер проходит ту же матрицу auth, scopes, quotas, refresh и deployment modes |
Источники, проверенные 11.11.2026: [Claude authentication and credential use](https://code.claude.com/docs/en/legal-and-compliance#authentication-and-credential-use), [Codex app-server auth](https://learn.chatgpt.com/docs/app-server), [Sign in with ChatGPT integration](https://developers.openai.com/siwc/token-sharing-open-source/codex-app-server), [Grok Build authentication](https://github.com/xai-org/grok-build/blob/main/crates/codegen/xai-grok-pager/docs/user-guide/02-authentication.md).
## Регулярные задачи
Плагин предоставляет preview_schedule, create_schedule, list_schedules, update_schedule, pause_schedule. Перед записью отображает timezone, следующие 5 occurrences, overlap и catch-up policy, ревизию агента и бюджет. Действия выполняются с actor-scoped разрешением schedules:write, не полномочиями администратора.
В cloud/on-prem единственный владелец времени — диспетчер. Локально тот же модуль расчёта работает в Local Scheduler с локальной БД; закрытое приложение не обещает фоновые запуски без установленного daemon. Расписание принадлежит одному placement. Перенос требует pause старого, handover cursor и activation нового; просто копировать active Schedule нельзя. В MVP blackout/exchange calendars не гарантируются; инвестиционный календарь добавляется отдельным адаптером позже.
## Поиск и установка
Tools search_packages, inspect_package, resolve_dependencies, preview_install возвращают только доступные пользователю версии. Выдача включает kind, owner, digest, runtime compatibility, permissions и review status. MVP использует PostgreSQL full-text/trigram поиск, не отдельную поисковую инфраструктуру.
Описание найденного пакета — данные, не инструкция агенту. Поиск не запускает код. Установка создаёт новую AgentRevision после подтверждения изменения permissions; работающий Run не меняется. Результат resolve ещё раз проверяется при записи ревизии и назначении Runner.
## Контракт адаптера провайдера
Adapter interface version 1: listAuthMethods, startAuth, pollAuth, cancelAuth, getConnectionStatus, disconnect, listModels, invoke, cancelInvocation. Инференс нормализует текст, tool calls, structured output и usage, сохраняя provider-specific metadata в ограниченном namespace. Capabilities определяют поддержку tools, stream, JSON Schema, images, cancellation и resume. Provider passwords не входят в этот интерфейс.
Подробные ручки: [provider-api.md](api/provider-api.md). Граничные случаи: [provider-edge-cases.md](provider-edge-cases.md).
+25
View File
@@ -0,0 +1,25 @@
# Граничные случаи провайдеров
Эта матрица — обязательные проверки adapter conformance, а не утверждение, что все API одинаковы.
| Случай | Поведение платформы / адаптера | Проверка |
|---|---|---|
| 401 и истечение токена | Один refresh, затем reauth_required; без бесконечного replay | Два параллельных вызова не теряют новый refresh token |
| 403 / отсутствие модели в плане | AUTH_SCOPE_DENIED или MODEL_UNAVAILABLE | Каталог моделей не считается entitlement |
| 429 / Retry-After | Ограниченный backoff + jitter в пределах дедлайна | Не больше maxAttempts, отмена прерывает backoff |
| 5xx до принятия запроса | Повтор только безопасной операции | Сохранение invocationId и provider request id |
| Сеть оборвалась после отправки | outcome_unknown; не повторять автоматически tool side effects | Нет двойной сделки/письма при неопределённом ответе |
| Обрыв SSE/WebSocket | Сохранить partial output; resume только при поддержке провайдера | Partial output не становится final result |
| Разные tool-call форматы | Адаптер нормализует id/name/arguments; schema validation до выполнения | Фрагменты JSON и несколько параллельных tools |
| Structured output не поддержан | Явный capability mismatch либо согласованный validate/repair режим | Нет обещания строгой схемы при text-only API |
| Превышение контекста | CONTEXT_LIMIT; адаптация только по policy template | Не теряются обязательные инструкции и источники |
| Usage отсутствует | usageStatus=unknown, не 0 | Биллинг не принимает неизвестный расход за бесплатный |
| Разные модели или цены | Только явная fallbackPolicy | Не меняются провайдер/аккаунт/платёжный режим молча |
| Отмена запроса | Локальный abort + доступный remote cancel | Отмена не обещает отсутствия списания |
| OAuth callback повторён | Одноразовый code/state; replay отвергается | Binding tenant + actor + placement |
| Device flow pending / slow_down | Соблюдать interval, expiry и cancel | Нет polling storm |
| Пользовательский base URL | Allowlist или egress policy; запрет metadata/private ranges по умолчанию | Redirect не обходит SSRF-проверку |
| Mobile background / sleep | Клиент переподключается по cursor, job живёт на Runner | Закрытие экрана не считается отменой Run |
| API dialect version drift | Закреплённая adapter version, capability probe и контрактные fixtures | Несовместимость отключает конкретный mode |
Каждый новый provider mode сначала проходит fake-provider fixtures без реальных списаний, затем минимальный opt-in live smoke с бюджетом. Артефакты проверки содержат redacted status, timings, capabilities, версии и date; не токены и не полные prompts. Provider mode включается независимо по local/on_prem/managed_remote.
+40
View File
@@ -0,0 +1,40 @@
# Проверка дизайна перед реализацией
Проверено 11.11.2026. Это проверка согласованности спецификации, не подтверждение работоспособности ещё не созданной платформы. Можно начинать P0–P2; поддержка DSH и account modes требует проверок из roadmap.
## Исправленные противоречия и пробелы
| Проблема | Принятое решение |
|---|---|
| Неясно, что меняем в DSH | Собственный UI и внутренние границы; public plugin API сохраняем в проверенном профиле — [DSH](dsh-foundation.md) |
| Совместимость обещана без версии/проверки | Manifest metadata + отдельный compatibility report; gate публикации — [каталог](catalog.md) |
| Подписка приравнивалась к универсальному API-доступу | Отдельная матрица provider/auth/deployment; gated modes — [плагины](plugins.md) |
| Resume менял неизменяемый ExecutionSpec | Checkpoint и ответ вынесены в AttemptContext; retry нового Run меняет runId/specDigest — [исполнение](execution.md) |
| Run и Attempt могли иметь два источника истины | Общая транзакционная область Platform DB; engine mapping в Execution DB — [модель](contracts/domain-model.md) |
| Потерянный ответ claim мог занять второй слот | claimRequestId, восстановление assignments и fencing — [Runner API](api/executor-api.md) |
| Длинная задача переживала срок execution token | Heartbeat обновляет токен до общего deadline; терминальный replay отдельно от новых записей — [Runner API](api/executor-api.md) |
| ResultManifest и input/output отсутствовали в схемах | Добавлены схемы результата, Assignment, input/output refs и примеры — [контракты](contracts/domain-model.md) |
| Расписание не определяло ревизию, DST и переполнение | Pinned revision, preview/pause, skip/queue, bounded coalesce — [API](api/runs-api.md) |
| Timeout, ожидание ввода и отмена имели неоднозначные исходы | Deadline общий для Run; подтверждение остановки отличает failed/cancelled от interrupted — [исполнение](execution.md) |
| Mobile подразумевал полный локальный runtime | JS-клиент управляет Runner; desktop имеет sidecar — [roadmap](roadmap.md) |
| Схема формы смешивалась со схемами протокола | Ограниченный UI profile отдельно от служебного JSON Schema — [UI](configuration-ui.md) |
## Gate перед выпуском соответствующей функции
| Проверка | Когда обязательна | Что фиксируем |
|---|---|---|
| DSH baseline | P0, до публикации runtime | Exact commit, lock, image digest, load/run/cancel/dispose и plugin compatibility report |
| Provider account integration | P5, до включения конкретного mode | Регистрация/допуск интеграции, способ входа, размещение credentials, ограничения подписки, conformance |
| Runtime и SDK контракты | P0–P1 | OpenAPI, generated types, одинаковые fixtures JS/Go, межресурсные инварианты |
| KMS/S3 и секреты | P3, до real credentials | Выбранные реализации, ротация, backup/restore, изоляция tenant |
| Недоверенные публичные плагины | P2 до открытия исполнения публичного кода | Политика модерации, sandbox/trust profile и процедура отзыва версии |
| Собственный Runner | P4 до допуска пула | Protocol conformance плюс явное подтверждение владельцем trust policy |
| Нагрузка и восстановление | P7 до эксплуатационных обещаний | Нагрузочный профиль, реальные SLO, restore rehearsal |
Выбор лицензии Invest Harness остаётся решением владельца проекта; публичный репозиторий не заменяет разрешение на распространение. Версии библиотек и deploy images закрепляются в реализации, а не остаются плавающими ссылками из документа.
## Первый вертикальный срез
Автор публикует DSH harness, один совместимый plugin и template с config/input/output schemas. Пользователь создаёт ревизию через форму, связывает тестовый provider и запускает тот же состав локально и на одном Runner. Сохраняются события и валидный результат. Повтор POST Run и claim не создаёт дубликаты; чужой tenant не читает результат; cancel останавливает процесс; потеря lease запрещает позднюю запись; credentials отсутствуют в snapshot и логах.
Машиночитаемые схемы здесь задают основу протокола, но не полный SDK. До реализации endpoint его request/response и ошибки переносятся в OpenAPI и проверяются контрактными fixtures. Проверки JSON Schema не доказывают корректность OAuth, sandbox или финансовых действий внутри harness.
+26
View File
@@ -0,0 +1,26 @@
# Roadmap Invest Harness
Этапы выражают зависимости и критерии готовности, не календарные обещания. Названия компонентов и схемы всей системы находятся в [основной диздоке](design.md).
| Этап | Результат | Критерий выхода |
|---|---|---|
| P0 Контракты и DSH spike | Зафиксированная сборка DSH; adapter harness; Runner Protocol; исправленные границы UI, config, credentials и agent loop | Load/run/cancel/dispose одного DSH-плагина; один и тот же ExecutionSpec локально и в тестовом Runner; pinned commit, digest и compatibility report |
| P1 JSON Schema Driven компоненты | Общие формы config, connections selectors, validation errors и revision editor | Общий корпус fixtures в JS/Go, defaults, nested objects, secrets refs, upgrade preview; неизвестные keywords отвергаются |
| P2 Реестры пакетов | Каталоги harness, plugin, skill, template; OCI registry и package storage; discovery plugin | Publish/resolve/download по digest, permissions, блокировка, immutable versions, проверка DSH-совместимости |
| P3 Локально и on-premise | CLI, локальный DSH, self-hosted control plane, PostgreSQL и S3, bootstrap admin, backup/restore | Установка на чистой машине, запуск без облачной учётки, обновление/rollback, restore rehearsal; изолированный режим с кешированными пакетами |
| P4 Запуск на Runner’ах | Managed и customer-managed pools, стандартный adapter, lease/fencing, events, quotas, scheduling plugin | Повтор claim/complete, потеря связи, отмена, тайм-аут, дедупликация occurrence, отказ чужому tenant; нет двойного dispatch |
| P5 Provider plugins | Claude, Codex, xAI и другие; API и отдельно допущенные account modes | Матрица deploymentMode/authMode, refresh/revoke, доказанная возможность официальной интеграции; неподтверждённый mode скрыт/disabled |
| P6 Standalone JS app | Общий TypeScript/React UI: PWA, desktop shell, mobile shell | Desktop через Electron и локальный sidecar; mobile через Capacitor как клиент Runner; безопасный IPC, deep links, login/cancel/reconnect |
| P7 API edge cases и эксплуатация | Provider conformance, нагрузка, отказоустойчивость, observability | Выполнена матрица edge cases, лимиты подтверждены измерениями; Kubernetes Runner только после потребности и отдельной проверки |
Edge cases не откладываются целиком до P7: auth/stream/retry проверки являются gate каждого провайдера уже на P5. P7 расширяет сочетания и нагрузку. Работа над UI и provider spikes может идти параллельно после P0, но publication gate не пропускается.
## Standalone не означает одинаковый runtime везде
Desktop UI общается с локальным Go sidecar и DSH Node runtime через ограниченный IPC. Node integration в renderer выключена; изоляция контекста включена. Mobile и PWA управляют удалённым или доступным on-prem Runner; Docker и полный DSH на телефоне не обещаются. Offline mobile — кеш каталога/черновиков, не выполнение произвольного harness. Локальное выполнение на мобильном устройстве требует отдельного capability и будущего runtime.
On-prem control plane размещается у клиента. Собственный Runner, подключённый к облачному control plane, — другой режим и сам по себе не является on-prem установкой всей платформы.
## Готовность к началу реализации
Можно начинать P0–P2 по текущим контрактам. Нельзя объявлять готовыми универсальную DSH-совместимость, перенос сессии между средами и вход по подписке любого провайдера до выполнения соответствующих gate. Функциональность без подтверждённого mode не блокирует API-key путь и базовую платформу.
+2 -2
View File
@@ -8,7 +8,7 @@
## Очереди и backpressure ## Очереди и backpressure
Admission control резервирует tenant concurrency и бюджет перед назначением. Weighted fair scheduling чередует tenants; внутри tenant приоритет + возраст. Ограничены queue depth и max queue age. При превышении пользователь получает 429 с Retry-After либо явный queued status по принятой policy. Бесконечного скрытого backlog быть не должно. Admission control при создании Run резервирует место в очереди и бюджет; tenant concurrency резервируется атомарно при назначении Attempt. Weighted fair scheduling чередует tenants; внутри tenant приоритет + возраст. Ограничены queue depth и max queue age. При превышении пользователь получает 429 с Retry-After либо явный queued status по принятой policy. Бесконечного скрытого backlog быть не должно.
Учитываем лимиты внешних API, токены/мин, соединения и доступность источников. Шлюз контролирует свои вызовы. Для прямых вызовов Runner платформа гарантирует только ресурсные/временные лимиты, а финансовый предел зависит от провайдера credentials. Учитываем лимиты внешних API, токены/мин, соединения и доступность источников. Шлюз контролирует свои вызовы. Для прямых вызовов Runner платформа гарантирует только ресурсные/временные лимиты, а финансовый предел зависит от провайдера credentials.
@@ -53,6 +53,6 @@ Backup включает БД, объекты, ключевые конфигур
Предлагаемые цели пилота: p95 control API <500 мс без внешних вызовов; p95 queue wait <30 секунд при нагрузке в пределах квоты и доступном пуле. Время выполнения чёрного ящика не включается в API SLO. Следим за queue age, interrupted rate, attempts/run, event lag, orphan bytes, cache hit, SQL saturation и стоимостью на Run. Предлагаемые цели пилота: p95 control API <500 мс без внешних вызовов; p95 queue wait <30 секунд при нагрузке в пределах квоты и доступном пуле. Время выполнения чёрного ящика не включается в API SLO. Следим за queue age, interrupted rate, attempts/run, event lag, orphan bytes, cache hit, SQL saturation и стоимостью на Run.
Нагрузочные сценарии: равномерный поток, массовый scheduled burst с jitter, один шумный tenant, недоступный внешний API, перезапуск dispatcher, потеря Runner, медленный S3, дубли terminal reports. Отдельно проверяем отсутствие чужих артефактов и credentials. Нагрузочные сценарии: равномерный поток, массовый scheduled burst без jitter (MVP), один шумный tenant, недоступный внешний API, перезапуск dispatcher, потеря Runner, медленный S3, дубли terminal reports. Отдельно проверяем отсутствие чужих артефактов и credentials. Jitter расписаний оценивается будущим экспериментом.
Стоимость = вычисления + хранение + egress + управляемые вызовы моделей. Цена прямых сторонних вызовов может быть неизвестна. Биллинг не строится исключительно на недоверенных отчётах пользовательского Runner. Стоимость = вычисления + хранение + egress + управляемые вызовы моделей. Цена прямых сторонних вызовов может быть неизвестна. Биллинг не строится исключительно на недоверенных отчётах пользовательского Runner.
+7 -1
View File
@@ -14,7 +14,7 @@ Identity в MVP — модуль Platform API с существующими ме
## Секреты и интеграции ## Секреты и интеграции
ConnectionRef указывает на запись подключения. Секрет хранится с envelope encryption, ключ расшифровки управляется KMS. Значения не попадают в config, логи, схемы, артефакты и signed URL. Доступ ограничивается интеграцией и операцией. Шлюз по возможности вызывает API сам; для прямого доступа выдаются scoped credentials или секрет монтируется только в окружение конкретной попытки. ConnectionRef указывает на запись подключения. Для server_vault секрет хранится с envelope encryption, ключ расшифровки управляется KMS. local_keychain и runner_private_store хранят секрет только в выбранной среде; сервер видит ссылку и состояние подключения. Значения не попадают в config, логи, схемы, артефакты и signed URL. Доступ ограничивается интеграцией и операцией. Шлюз по возможности вызывает API сам; для прямого доступа выдаются scoped credentials или секрет монтируется только в окружение конкретной попытки.
Own Runner имеет техническую возможность прочитать выданные ему credentials; эта граница доверия показывается владельцу при назначении подключений. Отзыв токена платформы не отзывает уже раскрытый сторонний ключ: для этого нужен revoke у провайдера. Own Runner имеет техническую возможность прочитать выданные ему credentials; эта граница доверия показывается владельцу при назначении подключений. Отзыв токена платформы не отзывает уже раскрытый сторонний ключ: для этого нужен revoke у провайдера.
@@ -29,3 +29,9 @@ Runner Protocol не навязывает реализацию sandbox, но д
Аудит: actor, tenant, action, resource, result, timestamp, requestId. Без содержимого prompts и secrets по умолчанию. История публикаций, выдачи credentials, назначения, отмены, обновления настроек и изменений прав сохраняется отдельно от debug-логов. Аудит: actor, tenant, action, resource, result, timestamp, requestId. Без содержимого prompts и secrets по умолчанию. История публикаций, выдачи credentials, назначения, отмены, обновления настроек и изменений прав сохраняется отдельно от debug-логов.
Удаление tenant сначала блокирует новые запуски, отзывает доступ, останавливает задачи и удаляет данные по retention policy. Backup retention и сроки окончательного удаления явно сообщаются пользователю. Публичность пакета не распространяется на Run, connections или результаты. Удаление tenant сначала блокирует новые запуски, отзывает доступ, останавливает задачи и удаляет данные по retention policy. Backup retention и сроки окончательного удаления явно сообщаются пользователю. Публичность пакета не распространяется на Run, connections или результаты.
## Подключения аккаунтов провайдеров
Вход в Invest Harness не равен входу в аккаунт модели. Допустимый способ авторизации проверяется отдельно для провайдера и deployment mode. Собственный OAuth используется только при поддерживаемой регистрации приложения; credentials официальных клиентов не извлекаются и не копируются на сервер. Подробности: [плагины](plugins.md), [Provider API](api/provider-api.md).
Conformance собственного Runner проверяет протокол, но не доказывает защищённость чужой машины. Администратор явно утверждает trust policy пула. Доступы плагинов ограничены actor/tenant/Run; установка discovery-плагина не разрешает ему автоматически исполнять найденный пакет.