Уточнить DSH, плагины, roadmap и контракты исполнения
This commit is contained in:
1 parent
2af6dd78ba
commit
41a4397ed2
25 files changed
+743
-37
No files matched your search
@@ -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 после отзыва запрещено.
|
||||
@@ -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.
|
||||
@@ -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/attempts/{id}/heartbeat | leaseEpoch, sequence, progress? | 200 {leaseUntil, cancelRequested} |
|
||||
| POST /v1/runner-jobs/claim | runnerId, claimRequestId, availableSlots, capabilitiesRevision | 200 Assignment или 204 |
|
||||
| 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}/events | leaseEpoch, events:[RunEvent] | 200 {acceptedThrough} |
|
||||
| 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}/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 пулы отображаются раздельно.
|
||||
|
||||
## Восстановление потерянного ответа
|
||||
|
||||
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.
|
||||
@@ -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,14 +13,14 @@
|
||||
| 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}/responses | responseId, inputRequestId, value | 202 Run | Только waiting_input; схема ответа и права |
|
||||
| POST /v1/schedules | agentId, cron, timezone, overlapPolicy | 201 Schedule | operator; cron и timezone валидируются |
|
||||
| PATCH /v1/schedules/{id} | cron?, timezone?, enabled?, overlapPolicy?; If-Match | 200 Schedule | 412 conflict |
|
||||
| POST /v1/schedules | agentId, agentRevision, cron, timezone, overlapPolicy, misfirePolicy? | 201 Schedule | operator; cron и timezone валидируются |
|
||||
| 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 |
|
||||
| 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 не содержит конфигурацию.
|
||||
|
||||
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 не даёт доступ к чужому пулу.
|
||||
|
||||
@@ -31,3 +31,13 @@ Limits: cpuMillis, memoryBytes, timeoutSeconds, outputBytes. Пользоват
|
||||
```
|
||||
|
||||
Отмена не гарантирует отмену уже совершённого внешнего действия. 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; перенос в облако отключает прежнего владельца до включения нового.
|
||||
@@ -27,3 +27,9 @@ Resolver принимает templateVersionId и профиль среды. Он
|
||||
Deprecated версия доступна закреплённым агентам, но скрыта из стандартного выбора. Удаление referenced-версии возвращает 409. Физическая очистка допускается после retention запусков, проверки ссылок и grace period. Immutable артефакты адресуются по digest; signed URL не сохраняется в постоянном lock.
|
||||
|
||||
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).
|
||||
@@ -36,3 +36,5 @@ PUT конфигурации требует If-Match. При конфликте
|
||||
- [Пример схемы](contracts/examples/config.schema.json)
|
||||
- [Начальные значения](contracts/examples/config.defaults.json)
|
||||
- [Представление формы](contracts/examples/ui.schema.json)
|
||||
|
||||
Ограниченный набор JSON Schema keywords относится к пользовательским формам config/input. Служебные схемы протокола могут использовать allOf/if/then и не передаются renderer. Версия профиля валидатора закрепляется вместе с шаблоном; несовместимая схема отвергается при публикации.
|
||||
@@ -11,13 +11,13 @@
|
||||
| VersionPolicy | versionId, status, reason, revision | Catalog |
|
||||
| Agent | id, tenantId, ownerId, name, currentRevision | 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 |
|
||||
| Attempt | id, runId, runnerId, leaseEpoch, leaseUntil, status | Dispatcher |
|
||||
| RunnerPool | id, tenantId, trustPolicy, quotas | Dispatcher |
|
||||
| Runner | id, poolId, capabilities, credentialStatus, lastSeenAt | Dispatcher |
|
||||
| Attempt | id, runId, runnerId, leaseEpoch, leaseUntil, status | Dispatcher / Platform DB |
|
||||
| RunnerPool | id, tenantId, trustPolicy, quotas | Dispatcher / Platform DB |
|
||||
| Runner | id, poolId, capabilities, credentialStatus, lastSeenAt | Dispatcher / Platform DB |
|
||||
| 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 | Пишущий сервис |
|
||||
|
||||
## Инварианты
|
||||
@@ -42,3 +42,11 @@
|
||||
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 означает, что возможность недоступна; поле не может быть выведено из названия пакета.
|
||||
|
||||
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"
|
||||
],
|
||||
"requiredPermissions": [],
|
||||
"retrySafe": false
|
||||
"retrySafe": false,
|
||||
"inputSchemaRef": "input.schema.json",
|
||||
"outputSchemaRef": "output.schema.json"
|
||||
}
|
||||
@@ -132,12 +132,6 @@
|
||||
"type": "string",
|
||||
"minLength": 1
|
||||
}
|
||||
},
|
||||
"checkpointRef": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
"maxLength": 128
|
||||
},
|
||||
"resumeInput": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,6 +134,45 @@
|
||||
},
|
||||
"retrySafe": {
|
||||
"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": [
|
||||
@@ -148,7 +187,9 @@
|
||||
"then": {
|
||||
"required": [
|
||||
"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": {
|
||||
"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
@@ -5,6 +5,9 @@
|
||||
| Термин | Значение |
|
||||
|---|---|
|
||||
| Harness | Движок и обвязка агента: цикл выполнения, управление контекстом, состоянием и вызовами инструментов |
|
||||
| DSH | DeepSeek Harness — исходная база стандартного agent runtime Invest Harness |
|
||||
| Connection | Подключение к провайдеру: способ входа, права, место хранения credentials и их состояние |
|
||||
| AttemptContext | Deadline и данные продолжения конкретной попытки, отдельно от ExecutionSpec |
|
||||
| Runtime | Среда выполнения программы: например, Node.js или Python; определяется пакетом harness’а |
|
||||
| Plugin | Программное расширение, добавляющее инструменты, интеграции или возможности |
|
||||
| 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"]
|
||||
I["Identity / Logical component of platform API / Sessions, OIDC"]
|
||||
B["Platform API / Container / Go, REST"]
|
||||
DB[("Platform DB / PostgreSQL / роли, агенты, запуски, аудит")]
|
||||
DB[("Platform DB / PostgreSQL / роли, агенты, Run, Attempt, расписания, аудит")]
|
||||
C["Каталог / Container / Go, REST"]
|
||||
CD[("Catalog DB / PostgreSQL / пакеты и версии")]
|
||||
PS[("Package Storage / S3 / архивы плагинов, скиллов, шаблонов")]
|
||||
D["Диспетчер / Container / Go"]
|
||||
E["Сервис исполнения / Container / Go / workflow, jobs, адаптер"]
|
||||
ED[("Execution DB / PostgreSQL / назначения и статусы движка")]
|
||||
ED[("Execution DB / PostgreSQL / executionId mapping и технические статусы")]
|
||||
R["Registry API / Component of execution service / Go, OCI"]
|
||||
RS[("Registry Storage / S3 / манифесты и слои образов")]
|
||||
ES[("Execution Storage / S3 / логи и технические артефакты")]
|
||||
@@ -116,7 +119,7 @@ flowchart TB
|
||||
T --> S
|
||||
T --> M
|
||||
B --> F
|
||||
D --> S
|
||||
B --> S
|
||||
B -.-> O
|
||||
C -.-> 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 | Новый интерфейс |
|
||||
| Platform API и identity | Go, REST, OpenAPI, сессии, OIDC | Продуктовый API с адаптацией существующих механизмов аккаунтов |
|
||||
| Каталог | Go, PostgreSQL, S3 API | Новый отдельный сервис |
|
||||
@@ -329,6 +335,9 @@ stateDiagram-v2
|
||||
preparing --> running: окружение готово
|
||||
running --> waiting_input: checkpoint и запрос ввода
|
||||
waiting_input --> queued: подтверждённое продолжение
|
||||
waiting_input --> failed: INPUT_EXPIRED или deadline
|
||||
preparing --> failed: deadline и остановка подтверждена
|
||||
running --> failed: deadline и остановка подтверждена
|
||||
running --> succeeded: результат принят
|
||||
preparing --> failed: ошибка подготовки
|
||||
running --> failed: ошибка
|
||||
@@ -389,10 +398,91 @@ flowchart LR
|
||||
|
||||
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 и пакетов. Публичный доступ к этому проекту сам по себе не задаёт лицензию его дальнейшего использования.
|
||||
|
||||
## 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)
|
||||
@@ -406,3 +496,10 @@ MVP: четыре типа пакетов; immutable versions; конфигур
|
||||
- [API запусков](api/runs-api.md)
|
||||
- [Runner Protocol](api/executor-api.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)
|
||||
@@ -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).
|
||||
@@ -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 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 шлюз.
|
||||
|
||||
@@ -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).
|
||||
|
||||
## Владение состоянием и продолжение
|
||||
|
||||
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.
|
||||
@@ -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).
|
||||
@@ -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.
|
||||
@@ -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.
|
||||
@@ -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 путь и базовую платформу.
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
## Очереди и 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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Нагрузочные сценарии: равномерный поток, массовый 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.
|
||||
@@ -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 у провайдера.
|
||||
|
||||
@@ -29,3 +29,9 @@ Runner Protocol не навязывает реализацию sandbox, но д
|
||||
Аудит: actor, tenant, action, resource, result, timestamp, requestId. Без содержимого prompts и secrets по умолчанию. История публикаций, выдачи credentials, назначения, отмены, обновления настроек и изменений прав сохраняется отдельно от debug-логов.
|
||||
|
||||
Удаление 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-плагина не разрешает ему автоматически исполнять найденный пакет.
|
||||
Reference in new issue
Block a user