From d78c3016584f9abf6a799ed61a4784b0e946bbf4 Mon Sep 17 00:00:00 2001 From: Rogee Date: Wed, 23 Sep 2026 00:17:09 +0800 Subject: [PATCH] refactor: remove obsolete business paths --- AGENTS.md | 2 +- contracts/archive/README.md | 5 - .../2026-09-17-snapshot/SNAPSHOT.json | 70 - .../ai-config.openapi.yaml | 145 --- .../2026-09-17-snapshot/ai-config.schema.json | 101 -- .../cell-agent.openapi.yaml | 232 ---- .../2026-09-17-snapshot/examples/README.md | 5 - .../examples/agent-version.json | 49 - .../examples/call.execute.json | 23 - .../2026-09-17-snapshot/executor.openapi.yaml | 303 ----- .../integration-manifest.json | 32 - .../2026-09-17-snapshot/mock-profile.json | 64 - .../2026-09-17-snapshot/mq-topology.md | 40 - .../2026-09-17-snapshot/mq.schema.json | 40 - .../2026-09-17-snapshot/saas.openapi.yaml | 169 --- .../sip-management.openapi.yaml | 1125 ----------------- .../upstream/2026-09-18-p1-baseline/README.md | 27 - .../2026-09-18-p1-baseline/SNAPSHOT.json | 17 - .../ai-authorization.schema.json | 40 - .../ai-config.openapi.yaml | 145 --- .../ai-config.schema.json | 122 -- .../cell-agent.openapi.yaml | 232 ---- .../event-payloads.schema.json | 170 --- .../2026-09-18-p1-baseline/examples/README.md | 5 - .../examples/agent-version-asr-only.json | 21 - .../examples/agent-version-full-explicit.json | 41 - .../examples/agent-version.json | 49 - .../examples/ai-authorization.json | 14 - .../examples/call.execute.json | 23 - .../examples/event-call-finished.json | 26 - .../examples/event-call-status.json | 28 - .../examples/event-command-result.json | 19 - .../examples/event-contact-opt-out.json | 20 - .../examples/event-recording-failed.json | 20 - .../examples/event-recording-ready.json | 23 - .../examples/event-transcript-failed.json | 19 - .../examples/event-transcript-updated.json | 24 - .../invalid-ai-authorization-revoked.json | 12 - .../examples/invalid-asr-only-with-llm.json | 19 - .../examples/invalid-event-unknown-type.json | 13 - .../examples/invalid-oss-upload-http.json | 10 - .../examples/oss-upload-grant.json | 10 - .../examples/static-cell-artifact.json | 14 - .../executor.openapi.yaml | 303 ----- .../2026-09-18-p1-baseline/mock-profile.json | 64 - .../2026-09-18-p1-baseline/mq-topology.md | 40 - .../2026-09-18-p1-baseline/mq.schema.json | 40 - .../oss-upload.schema.json | 64 - .../p1-development-profile.json | 23 - .../p1-development-profile.schema.json | 43 - .../release-manifest.json | 193 --- .../2026-09-18-p1-baseline/saas.openapi.yaml | 169 --- .../sip-management.openapi.yaml | 1125 ----------------- .../static-cell-artifact.schema.json | 37 - .../2026-09-19-p1-v1-legacy/README.md | 31 - .../2026-09-19-p1-v1-legacy/SNAPSHOT.json | 17 - .../ai-authorization.schema.json | 40 - .../ai-config.openapi.yaml | 145 --- .../ai-config.schema.json | 122 -- .../cell-agent.openapi.yaml | 232 ---- .../event-payloads.schema.json | 170 --- .../examples/README.md | 5 - .../examples/agent-version-asr-only.json | 21 - .../examples/agent-version-full-explicit.json | 41 - .../agent-version-full-production-v1.json | 54 - .../examples/agent-version.json | 49 - .../examples/ai-authorization.json | 14 - .../examples/call.execute.json | 23 - .../examples/event-call-finished.json | 26 - .../examples/event-call-status.json | 28 - .../examples/event-command-result.json | 19 - .../examples/event-contact-opt-out.json | 20 - .../examples/event-recording-failed.json | 20 - .../examples/event-recording-ready.json | 23 - .../examples/event-transcript-failed.json | 19 - .../examples/event-transcript-updated.json | 24 - .../invalid-ai-authorization-revoked.json | 12 - .../examples/invalid-asr-only-with-llm.json | 19 - .../examples/invalid-event-unknown-type.json | 13 - .../examples/invalid-oss-upload-http.json | 10 - .../examples/oss-upload-grant.json | 10 - .../static-cell-artifact-real-v1.json | 95 -- .../examples/static-cell-artifact.json | 45 - .../executor.openapi.yaml | 303 ----- .../2026-09-19-p1-v1-legacy/mock-profile.json | 64 - .../2026-09-19-p1-v1-legacy/mq-topology.md | 40 - .../2026-09-19-p1-v1-legacy/mq.schema.json | 40 - .../oss-upload.schema.json | 64 - .../p1-development-profile.json | 23 - .../p1-development-profile.schema.json | 43 - .../release-manifest.json | 205 --- .../2026-09-19-p1-v1-legacy/saas.openapi.yaml | 169 --- .../sip-management.openapi.yaml | 1125 ----------------- .../static-cell-artifact.schema.json | 102 -- .../upstream/2026-09-21-p1-v2/README.md | 11 - .../ai-authorization.schema.json | 119 -- .../2026-09-21-p1-v2/ai-config.schema.json | 323 ----- .../dispatcher-config.schema.json | 62 - .../event-payloads.schema.json | 646 ---------- .../examples/ai-config-request.json | 14 - .../examples/ai-config-result.json | 90 -- .../examples/call-execute.json | 24 - .../examples/call-query-result.json | 157 --- .../2026-09-21-p1-v2/examples/call-query.json | 14 - .../examples/call-replay.json | 15 - .../examples/command-query-result.json | 21 - .../examples/command-query.json | 14 - .../examples/command-replay.json | 15 - .../examples/dispatcher-config.json | 12 - .../examples/event-call-finished.json | 34 - .../examples/event-call-status.json | 29 - .../examples/event-command-result.json | 20 - .../examples/event-contact-opt-out.json | 21 - .../examples/event-recording-failed.json | 21 - .../examples/event-recording-uploaded.json | 26 - .../examples/event-transcript-failed.json | 22 - .../examples/event-transcript-updated.json | 25 - .../examples/invalid-call-query-extra.json | 158 --- .../examples/invalid-correlation.json | 20 - .../examples/invalid-dispatcher.json | 24 - .../2026-09-21-p1-v2/examples/invalid-v1.json | 24 - .../examples/invalid-wildcard.json | 24 - .../examples/query-pending.json | 14 - .../examples/query-rejected.json | 17 - .../examples/task-control.json | 18 - .../upstream/2026-09-21-p1-v2/fixtures.json | 132 -- .../upstream/2026-09-21-p1-v2/manifest.json | 86 -- .../2026-09-21-p1-v2/mq-topology.json | 32 - .../upstream/2026-09-21-p1-v2/mq.schema.json | 956 -------------- .../2026-09-21-p1-v2/oss-upload.schema.json | 205 --- .../p1-development-profile.schema.json | 156 --- .../static-cell-artifact.schema.json | 369 ------ .../2026-09-21-p1-v3-unused-ai-digest.json | 15 - .../ai-config.openapi.yaml | 145 --- .../ai-config.schema.json | 101 -- .../cell-agent.openapi.yaml | 225 ---- .../examples/README.md | 5 - .../examples/agent-version.json | 49 - .../examples/call.execute.json | 23 - .../executor.openapi.yaml | 303 ----- .../mock-profile.json | 64 - .../mq-topology.md | 40 - .../mq.schema.json | 40 - .../saas.openapi.yaml | 169 --- .../sip-management.openapi.yaml | 1125 ----------------- contracts/upstream/manifest.txt | 6 +- contracts/upstream/v1/manifest.json | 6 +- contracts/upstream/v1/oss-upload.schema.json | 241 +--- .../upstream/v1/p1-development-profile.json | 1 - .../v1/p1-development-profile.schema.json | 24 - docs/contracts/dispatcher-agent.md | 4 +- docs/contracts/saas-dispatcher.md | 6 +- docs/evidence/20260918-acceptance-matrix.md | 2 +- .../20260918-contract-input-blocker.md | 2 +- docs/evidence/20260918-g0-status.md | 2 +- docs/evidence/20260918-local-development.json | 2 +- docs/plan-0918.md | 4 +- gen/agent/v1/agent.pb.go | 39 +- internal/store/migrations/003_uploads.sql | 1 - internal/store/upload_notification_test.go | 2 +- internal/store/uploads.go | 25 - proto/ERRORS.md | 4 +- proto/agent/v1/agent.proto | 7 +- proto/manifest.json | 12 +- scripts/archive/publish-mq-v2.py | 278 ---- scripts/archive/publish-mq-v3.py | 111 -- 166 files changed, 88 insertions(+), 16159 deletions(-) delete mode 100644 contracts/archive/README.md delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/SNAPSHOT.json delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/ai-config.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/ai-config.schema.json delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/cell-agent.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/examples/README.md delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/examples/agent-version.json delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/examples/call.execute.json delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/executor.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/integration-manifest.json delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/mock-profile.json delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/mq-topology.md delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/mq.schema.json delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/saas.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-17-snapshot/sip-management.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/README.md delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/SNAPSHOT.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/ai-authorization.schema.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/ai-config.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/ai-config.schema.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/cell-agent.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/event-payloads.schema.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/README.md delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version-asr-only.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version-full-explicit.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/ai-authorization.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/call.execute.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-call-finished.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-call-status.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-command-result.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-contact-opt-out.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-recording-failed.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-recording-ready.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-transcript-failed.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-transcript-updated.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-ai-authorization-revoked.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-asr-only-with-llm.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-event-unknown-type.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-oss-upload-http.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/oss-upload-grant.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/examples/static-cell-artifact.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/executor.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/mock-profile.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/mq-topology.md delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/mq.schema.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/oss-upload.schema.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/p1-development-profile.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/p1-development-profile.schema.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/release-manifest.json delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/saas.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/sip-management.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-18-p1-baseline/static-cell-artifact.schema.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/README.md delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/SNAPSHOT.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-authorization.schema.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-config.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-config.schema.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/cell-agent.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/event-payloads.schema.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/README.md delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-asr-only.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-full-explicit.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-full-production-v1.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/ai-authorization.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/call.execute.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-call-finished.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-call-status.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-command-result.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-contact-opt-out.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-recording-failed.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-recording-ready.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-transcript-failed.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-transcript-updated.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-ai-authorization-revoked.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-asr-only-with-llm.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-event-unknown-type.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-oss-upload-http.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/oss-upload-grant.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/static-cell-artifact-real-v1.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/static-cell-artifact.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/executor.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/mock-profile.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/mq-topology.md delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/mq.schema.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/oss-upload.schema.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/p1-development-profile.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/p1-development-profile.schema.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/release-manifest.json delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/saas.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/sip-management.openapi.yaml delete mode 100644 contracts/archive/upstream/2026-09-19-p1-v1-legacy/static-cell-artifact.schema.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/README.md delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/ai-authorization.schema.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/ai-config.schema.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/dispatcher-config.schema.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/event-payloads.schema.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/ai-config-request.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/ai-config-result.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/call-execute.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/call-query-result.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/call-query.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/call-replay.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/command-query-result.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/command-query.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/command-replay.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/dispatcher-config.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/event-call-finished.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/event-call-status.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/event-command-result.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/event-contact-opt-out.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/event-recording-failed.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/event-recording-uploaded.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/event-transcript-failed.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/event-transcript-updated.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-call-query-extra.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-correlation.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-dispatcher.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-v1.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-wildcard.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/query-pending.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/query-rejected.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/examples/task-control.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/fixtures.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/manifest.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/mq-topology.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/mq.schema.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/oss-upload.schema.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/p1-development-profile.schema.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v2/static-cell-artifact.schema.json delete mode 100644 contracts/archive/upstream/2026-09-21-p1-v3-unused-ai-digest.json delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/ai-config.openapi.yaml delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/ai-config.schema.json delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/cell-agent.openapi.yaml delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/README.md delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/agent-version.json delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/call.execute.json delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/executor.openapi.yaml delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mock-profile.json delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mq-topology.md delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mq.schema.json delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/saas.openapi.yaml delete mode 100644 contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/sip-management.openapi.yaml delete mode 100644 scripts/archive/publish-mq-v2.py delete mode 100644 scripts/archive/publish-mq-v3.py diff --git a/AGENTS.md b/AGENTS.md index f29c9a6..144a3da 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -166,7 +166,7 @@ - **OSS相关配置存于Dispatcher配置文件,Agent向Dispatcher领取临时上传TOKEN后直传OSS,不保存长期凭据;SaaS不再下发OSS配置/TOKEN。** D复用官方SDK提供受限TOKEN/目标信息,配置缺失/无效明确失败;不在样例、源码、日志或证据中保存实际密钥/完整TOKEN。过期只允许A显式向D重新申请,不自动续期或向SaaS申请TOKEN;精确配置格式/TOKEN形态/UploadGrant映射另行核验,不猜字段。 - **用户已修订目标:上传仅负责Agent直传及D可靠通知MQ,SaaS后续处理不属本项目职责。** D保留签发能力、不转发文件;R13持久保存事实与recording.uploaded outbox,消息为persistent、进入指定durable队列/绑定、mandatory无return且publisher confirm成功后才记交付完成。只写本地outbox不算入队;不申请SaaS会话、不等待verified/OSS ID、不新增VERIFYING、不伪造SaaS结果。 - 新版recording.uploaded取代本项目recording.ready,字段为call_id/recording_id/upload_id/bucket/object_key/format/channels/sample_rate_hz/duration_ms/size_bytes/checksum_sha256;不含TOKEN/密钥/签名URL。MQ失败/确认丢失/重启只恢复原消息身份的交付,不重新PUT或新建资产。AI/控制等必要请求响应不受此收缩影响。 -- 前一轮MQ-only文档纠正已结束;当前目标已获批准修改本项目契约/代码/配置/测试。精确方案见已确认的 `docs/contracts/mq-only-v1-freeze-proposal.md`:纯Topic精确绑定、拒绝独立通配词段、tenant_key预算196 UTF-8字节、稳定UUID v4、严格JSON配置及15分钟SDK预签名PUT;不得重开已批准方向。当前仅保留现有代码需要的契约包;未发生契约迁移前不新增契约,未使用的旧快照移至 `contracts/archive/`。新版须完成Schema/正反例/哈希验证后发布,不把方案确认当实现完成。受影响W01/W02/W04/W05/W07/W08/W11/W12/W13/W14按plan§8.2重新验证。全局唯一D身份/专用Topic及本地D1/D2隔离fixture为当前合同要求,不授权双D业务运行、HA或共享额度。 +- 前一轮MQ-only文档纠正已结束;当前目标已获批准修改本项目契约/代码/配置/测试。精确方案见已确认的 `docs/contracts/mq-only-v1-freeze-proposal.md`:纯Topic精确绑定、拒绝独立通配词段、tenant_key预算196 UTF-8字节、稳定UUID v4、严格JSON配置及15分钟SDK预签名PUT;不得重开已批准方向。当前仅保留现有代码需要的契约包;未发生契约迁移前不新增契约,旧快照不作为当前工作树输入。新版须完成Schema/正反例/哈希验证后发布,不把方案确认当实现完成。受影响W01/W02/W04/W05/W07/W08/W11/W12/W13/W14按plan§8.2重新验证。全局唯一D身份/专用Topic及本地D1/D2隔离fixture为当前合同要求,不授权双D业务运行、HA或共享额度。 - 文本实时事件准确名为transcript.updated,不新增call.transcript别名;OSS文本归档不能替代实时文字/opt-out,缺少专用资产授权接口时明确未启用,不能伪装recording.ready。 - 现有MQ信封command_type/command_id、event_type/aggregate_*与正文已对齐;事件payload专属约束尚需补齐,不把通用object校验当完整验收。字段索引只读生成,不手改成第二套Schema。 - `tenant_key` 原值一对一绑定,不清洗、编码或截断;旧布局224个UTF-8字节预算不能在加入D身份后直接照搬,W01须冻结并验证完整routing key/queue预算及分隔符/通配符边界;超限停止发布并保留源任务。 diff --git a/contracts/archive/README.md b/contracts/archive/README.md deleted file mode 100644 index 6fbef32..0000000 --- a/contracts/archive/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Archived contract inputs - -These bundles are no longer embedded or read by the current code. They are kept outside `contracts/upstream/` only to avoid mixing inactive inputs with the contracts currently required by the test/development tree. - -Do not create or update a contract here. Create a new contract only as part of an explicit contract migration. diff --git a/contracts/archive/upstream/2026-09-17-snapshot/SNAPSHOT.json b/contracts/archive/upstream/2026-09-17-snapshot/SNAPSHOT.json deleted file mode 100644 index 180e4c9..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/SNAPSHOT.json +++ /dev/null @@ -1,70 +0,0 @@ -{ - "snapshot_version": "2026-09-17", - "source_repository": "ai-call", - "source_head": "fa6925010ba47976d2e99893eac92140b3cb0d09", - "source_worktree": "dirty", - "dirty_patch_sha256": "be7a3a66cc5fb3d800aa38092b8ab70c17118e8bf9aba5b54b183ac357076a5d", - "runtime_dependency": "none (files are a versioned snapshot; parent paths are never read at runtime)", - "files": [ - { - "path": "ai-config.openapi.yaml", - "sha256": "d2f75d8fd2bf76ceb4eef869a838f08dca156938e1f3025d126ce81e436f624a", - "bytes": 4516 - }, - { - "path": "ai-config.schema.json", - "sha256": "62d9090adcca619e2bb3a6c5d6aa249c92601fe47b3278e24df82c640987c5db", - "bytes": 4316 - }, - { - "path": "cell-agent.openapi.yaml", - "sha256": "79dc697d7ce16e2a6aa7e350f30dd006dd847afe2cdc0ea29841f9c6d4310c41", - "bytes": 7633 - }, - { - "path": "examples/README.md", - "sha256": "6fee21522bad463eaa385848431c072ed371cf31dc51eb8c30757952740f157c", - "bytes": 513 - }, - { - "path": "examples/agent-version.json", - "sha256": "d3d4bf2fae07192674e54bf32172a8e95146f11d70609f3cd8f57f0112633c2e", - "bytes": 1079 - }, - { - "path": "examples/call.execute.json", - "sha256": "0164664fd3503d72668b24bdecb623aa0414ce58191960b868abe8454988c742", - "bytes": 656 - }, - { - "path": "executor.openapi.yaml", - "sha256": "b24703783df63e044fc0151c5e215430d2294e13937d2a5ceee3c6fee99b0329", - "bytes": 10244 - }, - { - "path": "mock-profile.json", - "sha256": "4d43097602fed9a68821e765117580706896ac82d4bce361a80a4cea544ab638", - "bytes": 2549 - }, - { - "path": "mq-topology.md", - "sha256": "a85b26596e1b1db7405dcabc967df56d5eb6713cc9908bc05ecaa2075ff1092f", - "bytes": 2211 - }, - { - "path": "mq.schema.json", - "sha256": "4fbfc39d46fb55ca48b71bc11cafce60e0814182ba4f898973c7c4d7657f912a", - "bytes": 2953 - }, - { - "path": "saas.openapi.yaml", - "sha256": "368c3a7d75ecc74771b88f9bd9fb7131697c69ce695475fc5aaae6099ff889eb", - "bytes": 5750 - }, - { - "path": "sip-management.openapi.yaml", - "sha256": "5006bbb1fb69f7b4a05cbaa5a43f8944e8522172910a41aba61897c9d5e00281", - "bytes": 38240 - } - ] -} diff --git a/contracts/archive/upstream/2026-09-17-snapshot/ai-config.openapi.yaml b/contracts/archive/upstream/2026-09-17-snapshot/ai-config.openapi.yaml deleted file mode 100644 index e310606..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/ai-config.openapi.yaml +++ /dev/null @@ -1,145 +0,0 @@ -openapi: 3.1.0 -info: - title: agent-call immutable AI configuration API - version: 1.0.0 - description: >- - Internal configuration publication/read surface. The call.execute business - command remains RabbitMQ-only; secrets, URLs, and provider credentials are - resolved by the execution environment and never enter MQ messages. -servers: - - url: / -paths: - /internal/v1/ai/agent-versions: - post: - operationId: publishAgentVersion - security: - - aiConfigPublish: [] - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionPublishRequest' - responses: - '200': - description: Identical immutable content already exists - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionReceipt' - '201': - description: Immutable version published - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionReceipt' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '409': - description: Existing version has different content - /internal/v1/ai/agent-versions/{agent_version_id}: - get: - operationId: getAgentVersion - security: - - aiConfigRead: [] - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - name: agent_version_id - in: path - required: true - schema: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$' - responses: - '200': - description: Trusted immutable snapshot - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersion' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '404': - description: Agent version not found -components: - parameters: - TenantId: - name: X-Tenant-Id - in: header - required: true - schema: {type: string, minLength: 1} - RequestId: - name: X-Request-Id - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - securitySchemes: - aiConfigPublish: - type: http - scheme: bearer - bearerFormat: JWT - description: >- - Requires scope ai.config.publish and the AI-config issuer/audience. - aiConfigRead: - type: http - scheme: bearer - bearerFormat: JWT - description: >- - Requires scope ai.config.read and the AI-config issuer/audience. - schemas: - AgentVersionPublishRequest: - type: object - additionalProperties: false - required: [agent_version_id, config] - properties: - agent_version_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$' - config: - $ref: 'ai-config.schema.json' - AgentVersionReceipt: - type: object - required: [tenant_id, agent_version_id, status, immutable, content_sha256] - properties: - tenant_id: {type: string} - agent_version_id: {type: string} - status: {enum: [published, reused]} - immutable: {const: true} - content_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - AgentVersion: - allOf: - - $ref: '#/components/schemas/AgentVersionReceipt' - - type: object - required: [config] - properties: - config: - $ref: 'ai-config.schema.json' - created_at: {type: string, format: date-time} - published_at: {type: string, format: date-time} - created_by: {type: string} - Error: - type: object - required: [error] - properties: - error: {type: string} - message: {type: string} - responses: - BadRequest: - description: Invalid configuration - content: - application/json: - schema: {$ref: '#/components/schemas/Error'} - Unauthorized: - description: Missing or invalid AI-config token - Forbidden: - description: Token lacks the AI-config permission diff --git a/contracts/archive/upstream/2026-09-17-snapshot/ai-config.schema.json b/contracts/archive/upstream/2026-09-17-snapshot/ai-config.schema.json deleted file mode 100644 index e4d2797..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/ai-config.schema.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/ai-config.schema.json", - "title": "Immutable AI agent version", - "type": "object", - "additionalProperties": false, - "required": ["agent_version_id", "immutable", "llm", "prompt", "tts", "asr", "conversation"], - "properties": { - "agent_version_id": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"}, - "immutable": {"const": true}, - "llm": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "model"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "temperature": {"type": "number", "minimum": 0, "maximum": 2}, - "max_tokens": {"type": "integer", "minimum": 1}, - "timeout_ms": {"type": "integer", "minimum": 1} - } - }, - "prompt": { - "type": "object", - "additionalProperties": false, - "required": ["text", "allowed_variables"], - "properties": { - "text": {"type": "string", "minLength": 1, "maxLength": 32768}, - "allowed_variables": { - "type": "array", - "maxItems": 32, - "items": {"type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"} - }, - "max_bytes": {"type": "integer", "minimum": 1, "maximum": 32768} - } - }, - "tts": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "model", "voice", "format"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "voice": {"type": "string", "minLength": 1, "maxLength": 128}, - "speed": {"type": "number", "minimum": 0.25, "maximum": 3}, - "timeout_ms": {"type": "integer", "minimum": 1}, - "format": { - "type": "object", - "additionalProperties": false, - "required": ["encoding", "sample_rate_hz", "channels"], - "properties": { - "encoding": {"enum": ["pcm_s16le", "pcma"]}, - "sample_rate_hz": {"type": "integer", "minimum": 8000, "maximum": 48000}, - "channels": {"const": 1} - } - } - } - }, - "asr": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "language", "input"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "language": {"type": "string", "minLength": 1, "maxLength": 32}, - "interim": {"type": "boolean"}, - "timeout_ms": {"type": "integer", "minimum": 1}, - "input": { - "type": "object", - "additionalProperties": false, - "required": ["encoding", "sample_rate_hz", "channels", "sample_width_bytes"], - "properties": { - "encoding": {"const": "pcm_s16le"}, - "sample_rate_hz": {"type": "integer", "minimum": 8000, "maximum": 48000}, - "channels": {"const": 1}, - "sample_width_bytes": {"const": 2} - } - } - } - }, - "conversation": { - "type": "object", - "additionalProperties": false, - "required": ["opening", "allow_interrupt", "silence_timeout_ms", "max_duration_ms", "max_turns", "sentence_max_chars", "max_pending_audio_chunks"], - "properties": { - "opening": {"type": "string", "maxLength": 32768}, - "allow_interrupt": {"type": "boolean"}, - "silence_timeout_ms": {"type": "integer", "minimum": 1}, - "max_duration_ms": {"type": "integer", "minimum": 1, "maximum": 3600000}, - "max_turns": {"type": "integer", "minimum": 1, "maximum": 1000}, - "sentence_max_chars": {"type": "integer", "minimum": 1}, - "max_pending_audio_chunks": {"type": "integer", "minimum": 1} - } - }, - "metadata": {"type": "object", "additionalProperties": true} - } -} diff --git a/contracts/archive/upstream/2026-09-17-snapshot/cell-agent.openapi.yaml b/contracts/archive/upstream/2026-09-17-snapshot/cell-agent.openapi.yaml deleted file mode 100644 index f37e4c0..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/cell-agent.openapi.yaml +++ /dev/null @@ -1,232 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Cell Agent API - version: 1.0.0 - description: >- - Restricted mTLS API used by the SIP management backend to deliver a - versioned Trunk snapshot to one voice Cell. The Cell validates the SHA-256 - snapshot, applies it with an atomic file replacement, reloads Asterisk, - restores the previous file on reload failure, and returns applied only - after the reload succeeds. A disabled snapshot removes the Cell-local - Trunk fragment and reloads Asterisk. -servers: - - url: https://cell.internal:9443 - description: Cell management network only -tags: - - name: health - - name: trunk-apply -paths: - /healthz/live: - get: - tags: [health] - operationId: live - responses: - '200': - description: Cell Agent is alive - content: - application/json: - schema: {$ref: '#/components/schemas/Health'} - /v1/sip/trunks/{trunk_id}/apply: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [trunk-apply] - operationId: applyTrunk - security: [{CellManagementMtls: []}] - parameters: - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/Publication'} - responses: - '200': - description: Asterisk has loaded the exact snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Acknowledgement'} - '400': {$ref: '#/components/responses/BadRequest'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': - description: >- - Revision or expected local snapshot is stale; the Cell never - guesses over an unknown baseline - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - '502': - description: Asterisk rejected the apply or reload - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - /v1/sip/trunks/{trunk_id}/state: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [trunk-apply] - operationId: getTrunkState - security: [{CellManagementMtls: []}] - responses: - '200': - description: Durable Cell apply state - content: - application/json: - schema: {$ref: '#/components/schemas/State'} - '404': {$ref: '#/components/responses/NotFound'} -components: - securitySchemes: - CellManagementMtls: - type: mutualTLS - description: Management backend client certificate signed by the Cell CA. - parameters: - TrunkId: - name: trunk_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - schemas: - Health: - type: object - additionalProperties: false - required: [status, mode, cell_id] - properties: - status: {type: string, const: ok} - mode: {type: string, const: real} - cell_id: {type: string} - CodecProfile: - type: object - additionalProperties: false - required: [allowed, preferred] - properties: - allowed: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - preferred: {type: string, enum: [PCMA, PCMU]} - SipConfig: - type: object - additionalProperties: false - required: [host, port, transport, auth_mode, register, credential_ref] - properties: - host: {type: string, minLength: 1, maxLength: 253} - port: {type: integer, minimum: 1, maximum: 65535} - transport: {type: string, enum: [udp, tcp, tls]} - auth_mode: {type: string, enum: [ip, digest]} - register: {type: boolean} - credential_ref: - type: [string, 'null'] - description: Secret-store reference only; plaintext is forbidden. - TrunkConfig: - type: object - additionalProperties: false - required: - - provider_id - - display_name - - enabled - - sip - - codec_profile - - caller_ids - - dial_prefix - - egress_pool_id - - max_concurrency - - max_cps - properties: - provider_id: {type: string} - display_name: {type: string, minLength: 1, maxLength: 256} - enabled: {type: boolean} - sip: {$ref: '#/components/schemas/SipConfig'} - codec_profile: {$ref: '#/components/schemas/CodecProfile'} - caller_ids: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, minLength: 1, maxLength: 128} - dial_prefix: {type: string, maxLength: 32} - egress_pool_id: {type: string} - max_concurrency: {type: integer, minimum: 1} - max_cps: {type: integer, minimum: 1} - Publication: - type: object - additionalProperties: false - required: - [mode, cell_id, trunk_id, revision, expected_local_revision, config, - config_sha256] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - expected_local_revision: {type: integer, minimum: 0} - config: {$ref: '#/components/schemas/TrunkConfig'} - config_sha256: - type: string - pattern: '^[0-9a-f]{64}$' - Acknowledgement: - type: object - additionalProperties: false - required: - [mode, cell_id, trunk_id, revision, config_sha256, status, idempotent] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - config_sha256: {type: string, pattern: '^[0-9a-f]{64}$'} - status: {type: string, const: applied} - idempotent: {type: boolean} - State: - type: object - additionalProperties: false - required: - [ - mode, - cell_id, - trunk_id, - desired_revision, - applied_revision, - status, - updated_at, - ] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - desired_revision: {type: integer, minimum: 1} - applied_revision: {type: integer, minimum: 0} - status: {type: string, enum: [applying, applied, failed]} - last_error: {type: [string, 'null']} - updated_at: {type: string, format: date-time} - ErrorResponse: - type: object - required: [error] - properties: - error: - type: object - required: [code, message] - properties: - code: {type: string} - message: {type: string} - responses: - BadRequest: - description: Invalid publication or hash - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Forbidden: - description: Certificate or Cell identity is not authorized - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - NotFound: - description: State does not exist - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} diff --git a/contracts/archive/upstream/2026-09-17-snapshot/examples/README.md b/contracts/archive/upstream/2026-09-17-snapshot/examples/README.md deleted file mode 100644 index 02f9c1a..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/examples/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Contract fixtures - -`call.execute.json` is the canonical valid command fixture. Runtime tests generate the remaining event fixtures from persisted facts so replay assertions compare original bytes and IDs rather than synthesized history. Invalid cases include unknown schema versions, missing required fields, cross-tenant bindings, conflicting idempotency bodies, and tenant routing keys over 224 UTF-8 bytes. - -All fixtures are synthetic. The profile is `mock`; it is never a production provider configuration. diff --git a/contracts/archive/upstream/2026-09-17-snapshot/examples/agent-version.json b/contracts/archive/upstream/2026-09-17-snapshot/examples/agent-version.json deleted file mode 100644 index 61851cd..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/examples/agent-version.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "agent_version_id": "agent_v1", - "immutable": true, - "llm": { - "provider_ref": "mock", - "model": "mock-chat-v1", - "temperature": 0.2, - "max_tokens": 256, - "timeout_ms": 5000 - }, - "prompt": { - "text": "You are a concise telephone assistant. Answer the caller's last statement.", - "allowed_variables": [], - "max_bytes": 32768 - }, - "tts": { - "provider_ref": "mock", - "model": "mock-tts-v1", - "voice": "mock-neutral", - "speed": 1.0, - "format": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1 - }, - "timeout_ms": 5000 - }, - "asr": { - "provider_ref": "mock", - "language": "zh-CN", - "input": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1, - "sample_width_bytes": 2 - }, - "interim": true, - "timeout_ms": 5000 - }, - "conversation": { - "opening": "", - "allow_interrupt": true, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/2026-09-17-snapshot/examples/call.execute.json b/contracts/archive/upstream/2026-09-17-snapshot/examples/call.execute.json deleted file mode 100644 index 23f9fdc..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/examples/call.execute.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "schema_version": "1.0", - "command_type": "call.execute", - "command_id": "cmd_demo_001", - "tenant_id": "tenant-demo", - "tenant_key": "tenant-demo-key", - "trace_id": "trace_demo_001", - "issued_at": "2026-09-11T08:00:00Z", - "not_after": "2099-09-11T08:05:00Z", - "payload": { - "execution_id": "exec_demo_001", - "task_id": "task-demo", - "task_item_id": "item_demo", - "task_revision": 1, - "callee": "18601013734", - "route_policy_id": "route_policy_test", - "caller_profile_id": "caller_profile_test", - "agent_version_id": "agent_v1", - "variables": {}, - "ring_timeout_ms": 30000, - "max_call_duration_ms": 180000 - } -} diff --git a/contracts/archive/upstream/2026-09-17-snapshot/executor.openapi.yaml b/contracts/archive/upstream/2026-09-17-snapshot/executor.openapi.yaml deleted file mode 100644 index a9f02fb..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/executor.openapi.yaml +++ /dev/null @@ -1,303 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Executor Control API - version: 1.0.0 - description: >- - Internal control, query, replay, and recording hand-off API. Call execution - enters through RabbitMQ, not HTTP. -servers: - - url: https://executor.internal -security: - - bearerAuth: [] -paths: - /internal/v1/outbound/tasks/{task_id}/controls: - post: - operationId: controlTask - summary: Persist a pause, resume, or stop barrier - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/TaskId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ControlRequest' - responses: - '202': - description: Reliably persisted, not yet necessarily applied - headers: - Location: - schema: {type: string} - content: - application/json: - schema: {$ref: '#/components/schemas/ControlAccepted'} - '409': {$ref: '#/components/responses/Conflict'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/commands/{command_id}: - get: - operationId: getCommand - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/CommandId' - responses: - '200': - description: Command snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Command'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/calls/{call_id}: - get: - operationId: getCall - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/CallId' - responses: - '200': - description: Call snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Call'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/calls/{call_id}/replays: - post: - operationId: replayCall - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/CallId' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayRequest'} - responses: - '202': - description: Replay persisted for bounded broker delivery - headers: - Location: {schema: {type: string}} - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayAccepted'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - '410': {$ref: '#/components/responses/ReplayExpired'} - /internal/v1/outbound/commands/{source_command_id}/replays: - post: - operationId: replayCommand - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/SourceCommandId' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayRequest'} - responses: - '202': - description: Replay persisted for bounded broker delivery - headers: - Location: {schema: {type: string}} - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayAccepted'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - '410': {$ref: '#/components/responses/ReplayExpired'} -components: - securitySchemes: - bearerAuth: - type: http - scheme: bearer - parameters: - TenantId: - name: X-Tenant-ID - in: header - required: true - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string} - IdempotencyKey: - name: Idempotency-Key - in: header - required: true - schema: {type: string} - TaskId: - name: task_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - CommandId: - name: command_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - SourceCommandId: - name: source_command_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - CallId: - name: call_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - schemas: - Id: - type: string - minLength: 1 - maxLength: 128 - pattern: '^[^\s/\\]+$' - ControlRequest: - type: object - additionalProperties: false - required: [command_id, action, expected_task_revision, reason] - properties: - command_id: {$ref: '#/components/schemas/Id'} - action: {type: string, enum: [pause, resume, stop]} - expected_task_revision: {type: integer, minimum: 1} - active_call_policy: {type: string, enum: [drain, hangup]} - reason: {type: string, minLength: 1, maxLength: 512} - ControlAccepted: - type: object - required: - - command_id - - tenant_id - - tenant_key - - task_id - - status - - requested_task_revision - - accepted_at - properties: - command_id: {$ref: '#/components/schemas/Id'} - tenant_id: {type: string} - tenant_key: {type: string} - task_id: {$ref: '#/components/schemas/Id'} - status: {const: accepted} - requested_task_revision: {type: integer} - accepted_at: {type: string, format: date-time} - ReplayRequest: - type: object - additionalProperties: false - required: [command_id, reason] - properties: - command_id: {$ref: '#/components/schemas/Id'} - reason: {type: string, minLength: 1, maxLength: 512} - ReplayAccepted: - type: object - required: [command_id, status, snapshot_cutoff] - properties: - command_id: {$ref: '#/components/schemas/Id'} - status: {const: accepted} - snapshot_cutoff: {type: string, format: date-time} - Command: - type: object - required: - - command_id - - command_type - - tenant_id - - tenant_key - - status - - aggregate_version - properties: - command_id: {$ref: '#/components/schemas/Id'} - command_type: {type: string} - tenant_id: {type: string} - tenant_key: {type: string} - task_id: {type: [string, 'null']} - execution_id: {type: [string, 'null']} - call_id: {type: [string, 'null']} - status: {type: string} - reason_code: {type: [string, 'null']} - wait_reason_code: {type: [string, 'null']} - accepted_at: {type: [string, 'null'], format: date-time} - waiting_since: {type: [string, 'null'], format: date-time} - admission_deadline: {type: [string, 'null'], format: date-time} - requested_task_revision: {type: [integer, 'null']} - applied_task_revision: {type: [integer, 'null']} - task_state: {type: [string, 'null']} - updated_at: {type: string, format: date-time} - aggregate_version: {type: integer, minimum: 1} - Call: - type: object - required: - - call_id - - execution_id - - call_state - - call_version - - attempts - - transcript - - recordings - - delivery - - snapshot_at - properties: - call_id: {type: string} - execution_id: {type: string} - task_id: {type: string} - task_item_id: {type: string} - call_state: {type: string} - call_version: {type: integer} - reason_code: {type: [string, 'null']} - outcome: {type: [string, 'null']} - started_at: {type: [string, 'null'], format: date-time} - ended_at: {type: [string, 'null'], format: date-time} - duration_ms: {type: [integer, 'null']} - attempts: {type: array, items: {type: object}} - transcript: {type: object} - recordings: {type: array, items: {type: object}} - delivery: {type: object} - snapshot_at: {type: string, format: date-time} - Problem: - type: object - additionalProperties: false - required: [type, title, status, code, detail, request_id, retryable] - properties: - type: {type: string, format: uri-reference} - title: {type: string} - status: {type: integer} - code: {type: string} - detail: {type: string} - request_id: {type: string} - retryable: {type: boolean} - responses: - Unauthorized: - description: Unauthorized - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - Forbidden: - description: Forbidden - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - NotFound: - description: Not found without cross-tenant enumeration - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - Conflict: - description: Idempotency or revision conflict - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - ReplayExpired: - description: Retention window expired - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} diff --git a/contracts/archive/upstream/2026-09-17-snapshot/integration-manifest.json b/contracts/archive/upstream/2026-09-17-snapshot/integration-manifest.json deleted file mode 100644 index fcb5dba..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/integration-manifest.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "schema_version": "1.0", - "snapshot": "SNAPSHOT.json", - "purpose": "Public-contract inputs for the standalone SIP mock; parent source paths are not runtime dependencies.", - "mq": { - "command_schema": "mq.schema.json", - "topology": "mq-topology.md", - "example": "examples/call.execute.json", - "tenant_key_policy": "exact opaque value; no normalization" - }, - "dut": { - "protocols": ["SIP/SDP", "ARI HTTP/WebSocket", "RTP/PCMA", "RabbitMQ", "HTTPS/SSE/WSS"], - "parent_runtime_imports": false, - "runtime_package": {"status": "missing", "required_for": ["AI-01", "MEDIA-01/external-no-inbound"]}, - "worker_rtp_ingress_observer": { - "status": "missing", - "required_for": ["MEDIA-01/external-no-inbound"], - "required_output": "versioned, run-scoped proof of RTP received by the DUT worker before first send" - }, - "worker_ledger_outbox_export": { - "status": "missing", - "required_for": ["AI-01"], - "required_output": "versioned, redacted read-only execution/ledger/outbox/AI stream evidence" - } - }, - "ai_fixture": { - "mode": "mock", - "accepted_transports": ["HTTPS", "SSE", "WSS"], - "audio_gate": "final ASR is emitted only after received audio matches a registered fixture fingerprint" - }, - "status": "snapshot-verified" -} diff --git a/contracts/archive/upstream/2026-09-17-snapshot/mock-profile.json b/contracts/archive/upstream/2026-09-17-snapshot/mock-profile.json deleted file mode 100644 index 4a79b80..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/mock-profile.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "profile_version": "1.0.0", - "mode": "mock", - "provider_modes": { - "saas": "mock", - "database": "sqlite", - "rabbitmq": "memory", - "sip": "mock", - "asterisk": "mock", - "asr": "mock", - "llm": "mock", - "tts": "mock", - "oss": "mock", - "cloud": "fake-cli" - }, - "versions": {"schema": "1.0", "service": "0.1.0", "seed": "mock-2026-09-11"}, - "limits": { - "admission_window_s": 30, - "ring_timeout_ms": 30000, - "max_call_duration_ms": 180000, - "max_mq_bytes": 262144, - "max_queue_messages": 1000, - "max_queue_bytes": 16777216, - "disk_warn_pct": 0.70, - "disk_stop_pct": 0.80, - "max_http_bytes": 65536, - "recording_max_bytes": 16777216, - "max_recording_bytes": 16777216, - "replay_retention_s": 604800, - "upload_ttl_s": 300, - "global_concurrency": 6, - "global_cps": 3, - "tenant_concurrency": 2, - "tenant_cps": 1, - "tenant_publish_rate": 10, - "scheduler_lease_ttl_s": 10, - "pending_window_per_tenant": 16, - "pending_window_global": 64, - "max_unacked_per_tenant": 4, - "max_replay_attempts": 6, - "cell_capacity": 4, - "turns": 2, - "hold_ms": 0 - }, - "random_seed": 7, - "tenants": [ - {"tenant_id": "tenant-demo", "tenant_key": "tenant-demo-key", "enabled": true}, - {"tenant_id": "tenant-b", "tenant_key": "tenant.b", "enabled": true}, - {"tenant_id": "tenant-c", "tenant_key": "tenant#c", "enabled": true} - ], - "tasks": [ - {"task_id": "task-demo", "tenant_id": "tenant-demo", "state": "running", "revision": 1}, - {"task_id": "task-b", "tenant_id": "tenant-b", "state": "running", "revision": 1}, - {"task_id": "task-c", "tenant_id": "tenant-c", "state": "running", "revision": 1} - ], - "routes": [{"route_policy_id": "route_policy_test", "trunk_id": "trunk-mock", "egress_pool_id": "egress-mock", "dial_prefix": "7089", "allowed": true}], - "caller_profiles": [{"caller_profile_id": "caller_profile_test", "display": "BD93205882", "allowed": true}], - "agents": [{"agent_version_id": "agent_v1", "immutable": true, "llm": "mock", "tts": "mock", "asr": "mock"}], - "cells": [ - {"cell_id": "cell-a", "capacity": 4, "media_capacity": 4, "ai_capacity": 4, "egress_pool_id": "egress-mock", "ari_mode": "mock"}, - {"cell_id": "cell-b", "capacity": 4, "media_capacity": 4, "ai_capacity": 4, "egress_pool_id": "egress-mock", "ari_mode": "mock"} - ], - "failure_scenarios": ["success", "busy", "no_answer", "ai_timeout", "customer_silent", "ari_disconnect", "upload_missing", "upload_bad_checksum", "broker_outage", "clock_jump"] -} diff --git a/contracts/archive/upstream/2026-09-17-snapshot/mq-topology.md b/contracts/archive/upstream/2026-09-17-snapshot/mq-topology.md deleted file mode 100644 index 60f8501..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/mq-topology.md +++ /dev/null @@ -1,40 +0,0 @@ -# agent-call MQ topology v1.0 - -This file is an implementation companion to the field authority in -`SaaS交互_OpenAPI与MQ契约规划_v0.1.md`. - -| Element | Value | -| --- | --- | -| Namespace | `agent-call` | -| Command exchange | `agent-call.commands.v1`, durable `direct` | -| Tenant command queue | `agent-call.executor.{tenant_key}.v1`, durable, one exact binding | -| Command routing key | `agent-call.tenant.{tenant_key}.call.execute` | -| Event exchange | `agent-call.events.v1`, durable `topic` | -| SaaS result queue | `agent-call.saas.events.v1`, durable, binding `agent-call.#` | -| Event routing key | `agent-call.{event_type}` | -| Body limit | `262144` UTF-8 bytes in the Mock profile | -| Tenant route budget | Broker limit `255` bytes; fixed prefix/suffix consume `31`, leaving `224` UTF-8 bytes | - -## Delivery rules - -1. SaaS persists the command publication record before publishing. A mandatory - publisher confirmation is required; an unroutable/full queue leaves the - original record retained for bounded retry. -2. The executor consumes only its trusted tenant queue. RabbitMQ messages are - acknowledged after durable SQLite acceptance or durable dead-lettering, not - when they are fetched. -3. Executor business events are written to the same database transaction as - the state transition. The outbox dispatcher publishes them durably and the - SaaS inbox applies each `event_id` once. `saas_applied` may remain unknown - after broker confirmation; it does not trigger unbounded republishing. -4. `tenant_key` is copied byte-for-byte into the body, queue name, binding and - routing key. It is not normalized, encoded, truncated or cleaned. A route - over the byte budget is retained and not sent. -5. Replay publishes the original event body and original `event_id` from a - fixed retention cutoff. It never creates a new business fact and never - includes events written after that cutoff. -6. HTTP has no call execution or redial endpoint. Control, query, replay and - recording metadata paths require bearer scope and tenant scope. - -The in-process broker is only for deterministic tests. Docker Compose uses the -same topology through the `pika` adapter and RabbitMQ durable queues. diff --git a/contracts/archive/upstream/2026-09-17-snapshot/mq.schema.json b/contracts/archive/upstream/2026-09-17-snapshot/mq.schema.json deleted file mode 100644 index b5ab065..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/mq.schema.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.invalid/contracts/mq.schema.json", - "title": "agent-call MQ command and event envelope", - "oneOf": [{"$ref": "#/$defs/executeCommand"}, {"$ref": "#/$defs/event"}], - "$defs": { - "id": {"type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[^\\s/\\\\]+$"}, - "tenantKey": {"type": "string", "minLength": 1}, - "time": {"type": "string", "format": "date-time"}, - "executeCommand": { - "type": "object", "additionalProperties": false, - "required": ["schema_version", "command_type", "command_id", "tenant_id", "tenant_key", "trace_id", "issued_at", "not_after", "payload"], - "properties": { - "schema_version": {"const": "1.0"}, "command_type": {"const": "call.execute"}, "command_id": {"$ref": "#/$defs/id"}, - "tenant_id": {"$ref": "#/$defs/id"}, "tenant_key": {"$ref": "#/$defs/tenantKey"}, "trace_id": {"$ref": "#/$defs/id"}, - "issued_at": {"$ref": "#/$defs/time"}, "not_after": {"$ref": "#/$defs/time"}, "payload": {"$ref": "#/$defs/executePayload"} - } - }, - "executePayload": { - "type": "object", "additionalProperties": false, - "required": ["execution_id", "task_id", "task_item_id", "task_revision", "callee", "route_policy_id", "caller_profile_id", "agent_version_id", "variables", "ring_timeout_ms", "max_call_duration_ms"], - "properties": { - "execution_id": {"$ref": "#/$defs/id"}, "task_id": {"$ref": "#/$defs/id"}, "task_item_id": {"$ref": "#/$defs/id"}, - "task_revision": {"type": "integer", "minimum": 1}, "callee": {"type": "string", "minLength": 1, "maxLength": 256}, - "route_policy_id": {"$ref": "#/$defs/id"}, "caller_profile_id": {"$ref": "#/$defs/id"}, "agent_version_id": {"$ref": "#/$defs/id"}, - "variables": {"type": "object", "additionalProperties": true}, "ring_timeout_ms": {"type": "integer", "minimum": 1}, "max_call_duration_ms": {"type": "integer", "minimum": 1} - } - }, - "event": { - "type": "object", "additionalProperties": false, - "required": ["schema_version", "event_id", "event_type", "tenant_id", "tenant_key", "trace_id", "occurred_at", "aggregate_type", "aggregate_id", "aggregate_version", "payload"], - "properties": { - "schema_version": {"const": "1.0"}, "event_id": {"$ref": "#/$defs/id"}, - "event_type": {"enum": ["command.result", "call.status", "transcript.updated", "call.finished", "recording.ready", "recording.failed", "transcript.failed", "contact.opt_out"]}, - "tenant_id": {"$ref": "#/$defs/id"}, "tenant_key": {"$ref": "#/$defs/tenantKey"}, "trace_id": {"$ref": "#/$defs/id"}, "occurred_at": {"$ref": "#/$defs/time"}, - "aggregate_type": {"enum": ["command", "call", "transcript_segment", "recording"]}, "aggregate_id": {"$ref": "#/$defs/id"}, "aggregate_version": {"type": "integer", "minimum": 1}, "payload": {"type": "object"} - } - } - } -} diff --git a/contracts/archive/upstream/2026-09-17-snapshot/saas.openapi.yaml b/contracts/archive/upstream/2026-09-17-snapshot/saas.openapi.yaml deleted file mode 100644 index e3f47c2..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/saas.openapi.yaml +++ /dev/null @@ -1,169 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call SaaS Recording Handoff API - version: 1.0.0 - description: >- - Internal storage handshake. Business results still return through RabbitMQ. -servers: - - url: https://saas.internal -security: - - bearerAuth: [] -paths: - /internal/v1/outbound/recording-uploads: - post: - operationId: createRecordingUpload - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/UploadRequest'} - responses: - '201': - description: Upload session created or existing session returned - headers: {Cache-Control: {schema: {const: no-store}}} - content: - application/json: - schema: {$ref: '#/components/schemas/UploadSession'} - '200': - description: Existing upload session - content: - application/json: - schema: {$ref: '#/components/schemas/UploadSession'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': {$ref: '#/components/responses/Conflict'} - /internal/v1/outbound/recording-uploads/{upload_id}/complete: - post: - operationId: completeRecordingUpload - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - name: upload_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/CompleteRequest'} - responses: - '200': - description: Object independently verified - content: - application/json: - schema: {$ref: '#/components/schemas/VerifiedUpload'} - '409': {$ref: '#/components/responses/Conflict'} - '410': {$ref: '#/components/responses/Expired'} - '422': {$ref: '#/components/responses/Unprocessable'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} -components: - securitySchemes: - bearerAuth: {type: http, scheme: bearer} - parameters: - TenantId: - name: X-Tenant-ID - in: header - required: true - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string} - IdempotencyKey: - name: Idempotency-Key - in: header - required: true - schema: {type: string} - schemas: - Id: - type: string - minLength: 1 - maxLength: 128 - pattern: '^[^\s/\\]+$' - UploadRequest: - type: object - additionalProperties: false - required: - - recording_id - - call_id - - content_type - - size_bytes - - checksum_algorithm - - checksum - - channels - - sample_rate_hz - - duration_ms - properties: - recording_id: {$ref: '#/components/schemas/Id'} - call_id: {$ref: '#/components/schemas/Id'} - content_type: {type: string, const: audio/wav} - size_bytes: {type: integer, minimum: 1} - checksum_algorithm: {type: string, const: SHA-256} - checksum: {type: string, pattern: '^[0-9a-f]{64}$'} - channels: {type: integer, const: 1} - sample_rate_hz: {type: integer, minimum: 8000} - duration_ms: {type: integer, minimum: 1} - UploadSession: - type: object - required: - - upload_id - - recording_id - - expires_at - - upload_method - - upload_url - - required_headers - - constraints - properties: - upload_id: {$ref: '#/components/schemas/Id'} - recording_id: {$ref: '#/components/schemas/Id'} - expires_at: {type: string, format: date-time} - upload_method: {const: PUT} - upload_url: {type: string, format: uri} - required_headers: {type: object} - constraints: {type: object} - oss_id: {type: [string, 'null']} - CompleteRequest: - type: object - additionalProperties: false - required: [recording_id, size_bytes, checksum_algorithm, checksum] - properties: - recording_id: {$ref: '#/components/schemas/Id'} - size_bytes: {type: integer, minimum: 1} - checksum_algorithm: {const: SHA-256} - checksum: {type: string, pattern: '^[0-9a-f]{64}$'} - etag: {type: [string, 'null']} - VerifiedUpload: - type: object - required: [upload_id, recording_id, status, oss_id, verified_at] - properties: - upload_id: {$ref: '#/components/schemas/Id'} - recording_id: {$ref: '#/components/schemas/Id'} - status: {const: verified} - oss_id: {type: string} - verified_at: {type: string, format: date-time} - Problem: - type: object - required: [type, title, status, code, detail, request_id, retryable] - properties: - type: {type: string} - title: {type: string} - status: {type: integer} - code: {type: string} - detail: {type: string} - request_id: {type: string} - retryable: {type: boolean} - responses: - Unauthorized: {description: Unauthorized} - Forbidden: {description: Forbidden} - Conflict: {description: Idempotency conflict} - Expired: {description: Upload expired} - Unprocessable: {description: Object failed independent verification} diff --git a/contracts/archive/upstream/2026-09-17-snapshot/sip-management.openapi.yaml b/contracts/archive/upstream/2026-09-17-snapshot/sip-management.openapi.yaml deleted file mode 100644 index 28fee2b..0000000 --- a/contracts/archive/upstream/2026-09-17-snapshot/sip-management.openapi.yaml +++ /dev/null @@ -1,1125 +0,0 @@ ---- -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Asterisk/SIP Management API - version: 1.0.0 - description: >- - Independent Asterisk/SIP management backend. Admin write operations are - separate from the SaaS read-only Trunk directory and from ordinary - scheduling APIs. In mock mode publication records are intents only. In - real mode a publication is successful only after every selected Cell Agent - returns a matching mTLS acknowledgement. -servers: - - url: https://sip-admin.internal - description: Restricted operator management network - - url: https://sip-read.internal - description: SaaS read-only service network -tags: - - name: health - - name: admin-providers - - name: admin-trunks - - name: admin-cells - - name: admin-status - - name: admin-statistics - - name: admin-audit - - name: saas-readonly -paths: - /healthz/live: - get: - tags: [health] - operationId: live - responses: - '200': - description: Service is alive - content: - application/json: - schema: - $ref: '#/components/schemas/Health' - /admin/v1/providers: - get: - tags: [admin-providers] - operationId: listProviders - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider directory - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderList'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/providers/{provider_id}: - parameters: - - {$ref: '#/components/parameters/ProviderId'} - get: - tags: [admin-providers] - operationId: getProvider - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-providers] - operationId: upsertProvider - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderInput'} - responses: - '200': - description: Updated provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '201': - description: Created provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '400': {$ref: '#/components/responses/BadRequest'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks: - get: - tags: [admin-trunks] - operationId: listAdminTrunks - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/TrunkStatusFilter'} - responses: - '200': - description: All Trunks, including unpublished revisions - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTrunkList' - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - /admin/v1/trunks/{trunk_id}: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: getAdminTrunk - security: [{SipAdminBearer: []}] - responses: - '200': - description: Trunk configuration and revisions - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTrunk' - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-trunks] - operationId: createTrunkRevision - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TrunkConfig' - responses: - '200': - description: New draft revision for an existing Trunk - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '201': - description: New Trunk with its first draft revision - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '400': {$ref: '#/components/responses/BadRequest'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/validate: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: validateTrunk - security: [{SipAdminBearer: []}] - requestBody: - required: false - content: - application/json: - schema: - type: object - additionalProperties: false - properties: - revision: {type: integer, minimum: 1} - responses: - '200': - description: Validation issues, compatible Cells, and impact preview - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/trunks/{trunk_id}/verifications: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: addTrunkVerification - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/VerificationRequest' - responses: - '200': - description: Versioned verification record - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/publish: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: publishTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - responses: - '200': - description: >- - Published revision after all selected Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/disable: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: disableTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - responses: - '200': - description: Trunk disabled after selected Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/rollback: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: rollbackTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - type: object - additionalProperties: false - required: [target_revision] - properties: - target_revision: {type: integer, minimum: 1} - responses: - '200': - description: >- - New revision copied from the target after Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/publications: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: listTrunkPublications - security: [{SipAdminBearer: []}] - responses: - '200': - description: Per-Cell publication intents - content: - application/json: - schema: - type: object - required: [mode, publications] - properties: - mode: {$ref: '#/components/schemas/Mode'} - publications: - type: array - items: {$ref: '#/components/schemas/Publication'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/trunks/{trunk_id}/audit: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: listTrunkAudit - security: [{SipAdminBearer: []}] - responses: - '200': - description: Immutable management audit entries - content: - application/json: - schema: - type: object - required: [mode, audit] - properties: - mode: {$ref: '#/components/schemas/Mode'} - audit: - type: array - items: {$ref: '#/components/schemas/AuditEntry'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/cells: - get: - tags: [admin-cells] - operationId: listCells - security: [{SipAdminBearer: []}] - responses: - '200': - description: Registered multi-machine voice Cells - content: - application/json: - schema: - type: object - required: [mode, cells] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cells: - type: array - items: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/cells/{cell_id}: - parameters: - - {$ref: '#/components/parameters/CellId'} - get: - tags: [admin-cells] - operationId: getCell - security: [{SipAdminBearer: []}] - responses: - '200': - description: Registered Cell - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-cells] - operationId: registerCell - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/CellConfig'} - responses: - '200': - description: Updated Cell revision - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '201': - description: Registered Cell - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/cells/{cell_id}/observations: - parameters: - - {$ref: '#/components/parameters/CellId'} - post: - tags: [admin-cells] - operationId: ingestCellObservation - security: [{SipAdminBearer: []}] - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ObservationInput'} - responses: - '201': - description: >- - Observation accepted for the current boot and monotonic sequence - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/egress-pools: - get: - tags: [admin-cells] - operationId: listEgressPools - security: [{SipAdminBearer: []}] - responses: - '200': - description: Fixed egress pool directory - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/sip-status: - get: - tags: [admin-status] - operationId: getSipStatus - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/CellIdsFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/ProviderFilter'} - responses: - '200': - description: >- - Cell/trunk status matrix with freshness and missing sources - content: - application/json: - schema: {$ref: '#/components/schemas/StatusResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/cells/{cell_id}/sip-status: - parameters: - - {$ref: '#/components/parameters/CellId'} - get: - tags: [admin-status] - operationId: getCellSipStatus - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/TrunkFilter'} - responses: - '200': - description: One Cell status - content: - application/json: - schema: {$ref: '#/components/schemas/StatusItem'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/providers/{provider_id}/status: - parameters: - - {$ref: '#/components/parameters/ProviderId'} - get: - tags: [admin-status] - operationId: getProviderStatus - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider status matrix - content: - application/json: - schema: {$ref: '#/components/schemas/StatusResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/statistics/outbound/summary: - get: - tags: [admin-statistics] - operationId: getOutboundSummary - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Cohort and interval metrics with completeness metadata - content: - application/json: - schema: {$ref: '#/components/schemas/StatisticsSummary'} - '401': {$ref: '#/components/responses/Unauthorized'} - '422': {$ref: '#/components/responses/BadRequest'} - /admin/v1/statistics/outbound/timeseries: - get: - tags: [admin-statistics] - operationId: getOutboundTimeseries - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/Granularity'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Bounded UTC time series - content: - application/json: - schema: {$ref: '#/components/schemas/TimeseriesResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '422': {$ref: '#/components/responses/BadRequest'} - /admin/v1/call-attempts: - get: - tags: [admin-statistics] - operationId: listCallAttempts - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/Limit'} - - {$ref: '#/components/parameters/Cursor'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Redacted raw attempt facts - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/call-attempts/{attempt_id}: - parameters: - - name: attempt_id - in: path - required: true - schema: {type: string} - get: - tags: [admin-statistics] - operationId: getCallAttempt - security: [{SipAdminBearer: []}] - responses: - '200': - description: One redacted attempt fact - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/audit: - get: - tags: [admin-audit] - operationId: listAudit - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/Limit'} - - {$ref: '#/components/parameters/ResourceFilter'} - - {$ref: '#/components/parameters/RequestFilter'} - - {$ref: '#/components/parameters/ActorFilter'} - responses: - '200': - description: Immutable audit entries - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/operations/{operation_id}: - parameters: - - name: operation_id - in: path - required: true - schema: {type: string} - get: - tags: [admin-audit] - operationId: getOperation - security: [{SipAdminBearer: []}] - responses: - '200': - description: Durable operation state for retry/recovery - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /readonly/v1/sip/trunks: - get: - tags: [saas-readonly] - operationId: listAuthorizedTrunks - security: [{SaasTrunkReadBearer: []}] - responses: - '200': - description: Published Trunks authorized for this SaaS principal - content: - application/json: - schema: - $ref: '#/components/schemas/ReadonlyTrunkList' - '401': {$ref: '#/components/responses/Unauthorized'} - /readonly/v1/sip/trunks/{trunk_id}: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [saas-readonly] - operationId: getAuthorizedTrunk - security: [{SaasTrunkReadBearer: []}] - responses: - '200': - description: Published, sanitized Trunk metadata - content: - application/json: - schema: {$ref: '#/components/schemas/ReadonlyTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} -components: - securitySchemes: - SipAdminBearer: - type: http - scheme: bearer - bearerFormat: opaque - description: >- - Dedicated operator/backend credential for SIP management writes. It is - not accepted by the SaaS read-only API or ordinary scheduling API. - SaasTrunkReadBearer: - type: http - scheme: bearer - bearerFormat: opaque - description: >- - Dedicated SaaS read-only credential. It cannot publish, modify, disable, - rollback, or access Cell management. - parameters: - ProviderId: - name: provider_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - TrunkId: - name: trunk_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - CellId: - name: cell_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - IfMatch: - name: If-Match - in: header - required: true - description: Exact latest revision required for CAS; quotes are accepted. - schema: {type: integer, minimum: 0} - CellIdsFilter: - name: cell_ids - in: query - required: false - schema: {type: string} - CellIdFilter: - name: cell_id - in: query - required: false - schema: {type: string} - ProviderFilter: - name: provider_id - in: query - required: false - schema: {type: string} - TrunkFilter: - name: trunk_id - in: query - required: false - schema: {type: string} - TrunkStatusFilter: - name: status - in: query - required: false - schema: {type: string} - ResourceFilter: - name: resource_id - in: query - required: false - schema: {type: string} - ActorFilter: - name: actor - in: query - required: false - schema: {type: string} - From: - name: from - in: query - required: false - schema: {type: string, format: date-time} - To: - name: to - in: query - required: false - schema: {type: string, format: date-time} - StatsMode: - name: mode - in: query - required: false - schema: {type: string, enum: [mock, mixed, real]} - EgressFilter: - name: egress_pool_id - in: query - required: false - schema: {type: string} - Granularity: - name: granularity - in: query - required: false - schema: {type: string, enum: [minute, hour, day]} - Limit: - name: limit - in: query - required: false - schema: {type: integer, minimum: 1, maximum: 200} - Cursor: - name: cursor - in: query - required: false - schema: {type: string} - RequestFilter: - name: request_id - in: query - required: false - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - responses: - BadRequest: - description: Invalid configuration or request - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Unauthorized: - description: Missing or wrong authentication domain - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Forbidden: - description: Credential lacks the required scope - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Conflict: - description: CAS conflict or no compatible Cell - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - NotFound: - description: Resource is not visible or does not exist - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - schemas: - Mode: - type: string - enum: [mock, real] - StatsMode: - type: string - enum: [mock, mixed, real] - Health: - type: object - additionalProperties: false - required: [status, mode] - properties: - status: {type: string, const: ok} - mode: {$ref: '#/components/schemas/Mode'} - CodecProfile: - type: object - additionalProperties: false - required: [allowed, preferred] - properties: - allowed: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - preferred: {type: string, enum: [PCMA, PCMU]} - SipConfig: - type: object - additionalProperties: false - required: [host, port, transport, auth_mode, register] - properties: - host: {type: string, minLength: 1, maxLength: 253} - port: {type: integer, minimum: 1, maximum: 65535} - transport: {type: string, enum: [udp, tcp, tls]} - auth_mode: {type: string, enum: [ip, digest]} - register: {type: boolean} - credential_ref: - type: string - writeOnly: true - description: >- - Secret-store reference only; plaintext credentials are forbidden. - VerificationRequest: - type: object - additionalProperties: false - required: [revision, check_name, result] - properties: - revision: {type: integer, minimum: 1} - check_name: - type: string - enum: - - transport - - registration_auth - - caller_id_rules - - codec - - capacity - - whitelist - result: - type: string - enum: [confirmed, failed, unknown, not_applicable] - evidence_ref: {type: string, maxLength: 512} - checked_by: {type: string, maxLength: 128} - TrunkConfig: - type: object - additionalProperties: false - required: - - provider_id - - display_name - - enabled - - sip - - codec_profile - - caller_ids - - dial_prefix - - egress_pool_id - - max_concurrency - - max_cps - properties: - provider_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - display_name: {type: string, minLength: 1, maxLength: 256} - enabled: {type: boolean} - sip: {$ref: '#/components/schemas/SipConfig'} - codec_profile: {$ref: '#/components/schemas/CodecProfile'} - caller_ids: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, minLength: 1, maxLength: 128} - dial_prefix: {type: string, maxLength: 32} - egress_pool_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - max_concurrency: {type: integer, minimum: 1} - max_cps: {type: integer, minimum: 1} - CellConfig: - type: object - additionalProperties: false - required: [egress_pool_id, codec_capabilities, status, max_concurrency] - properties: - egress_pool_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - codec_capabilities: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - status: {type: string, enum: [healthy, draining, disabled]} - max_concurrency: {type: integer, minimum: 1} - management_url: - type: string - format: uri - pattern: '^https://' - description: >- - mTLS Cell Agent endpoint. Required when mode=real; credentials and - query strings are not allowed. - RevisionInfo: - type: object - additionalProperties: false - required: [revision, state, created_at, created_by] - properties: - revision: {type: integer, minimum: 1} - state: {type: string, enum: [draft, publishing, published, superseded]} - config_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - created_at: {type: string, format: date-time} - created_by: {type: string} - AdminTrunk: - type: object - required: - - mode - - trunk_id - - provider_id - - latest_revision - - active_revision - - active_status - - status - - compatible_cell_ids - - latest - - active - - versions - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunk_id: {type: string} - provider_id: {type: string} - latest_revision: {type: integer, minimum: 1} - active_revision: {type: integer, minimum: 0} - active_status: {type: string, enum: [draft, published, disabled]} - status: {type: string, enum: [draft, published, disabled]} - updated_at: {type: string, format: date-time} - compatible_cell_ids: {type: array, items: {type: string}} - latest: {$ref: '#/components/schemas/TrunkView'} - active: {$ref: '#/components/schemas/TrunkView'} - versions: - type: array - items: - $ref: '#/components/schemas/RevisionInfo' - TrunkView: - allOf: - - {$ref: '#/components/schemas/TrunkConfig'} - - type: object - properties: - trunk_id: {type: string} - credential_configured: {type: boolean} - asterisk_allow: - type: array - items: {type: string, enum: [alaw, ulaw]} - config_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - ReadonlyTrunk: - type: object - required: - - mode - - trunk_id - - provider_id - - revision - - status - - config - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunk_id: {type: string} - provider_id: {type: string} - revision: {type: integer, minimum: 1} - status: {type: string, const: published} - updated_at: {type: string, format: date-time} - config: {$ref: '#/components/schemas/TrunkView'} - AdminTrunkList: - type: object - required: [mode, trunks] - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunks: {type: array, items: {$ref: '#/components/schemas/AdminTrunk'}} - ReadonlyTrunkList: - type: object - required: [mode, trunks] - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunks: - type: array - items: - $ref: '#/components/schemas/ReadonlyTrunk' - Cell: - type: object - required: [mode, cell_id, revision, config, updated_at, updated_by] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cell_id: {type: string} - revision: {type: integer, minimum: 1} - config: {$ref: '#/components/schemas/CellConfig'} - cloud_instance_id: {type: string} - instance_name: {type: string} - region: {type: string} - boot_id: {type: string} - updated_at: {type: string, format: date-time} - updated_by: {type: string} - Publication: - type: object - required: [trunk_id, revision, cell_id, status, updated_at] - properties: - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - cell_id: {type: string} - status: {type: string, enum: [pending, applied, failed]} - error_code: {type: [string, 'null']} - applied_at: {type: [string, 'null'], format: date-time} - target_digest: {type: string} - local_revision: {type: integer, minimum: 0} - local_digest: {type: string} - operation_id: {type: string} - updated_at: {type: string, format: date-time} - AuditEntry: - type: object - required: - - audit_id - - resource_type - - resource_id - - action - - revision - - actor - - details_json - - created_at - properties: - audit_id: {type: string} - resource_type: {type: string, const: trunk} - resource_id: {type: string} - action: - type: string - enum: - [ - upsert, - publish, - publish_failed, - disable, - disable_failed, - rollback, - rollback_failed, - ] - revision: {type: integer, minimum: 0} - actor: {type: string} - request_id: {type: [string, 'null']} - details_json: {type: string} - created_at: {type: string, format: date-time} - ProviderInput: - type: object - additionalProperties: false - required: [display_name, lifecycle] - properties: - display_name: {type: string, minLength: 1, maxLength: 256} - notes: {type: string, maxLength: 2000} - lifecycle: {type: string, enum: [active, archived]} - Provider: - allOf: - - {$ref: '#/components/schemas/ProviderInput'} - - type: object - required: [provider_id, revision, trunk_count, created_at, updated_at] - properties: - provider_id: {type: string} - revision: {type: integer, minimum: 1} - trunk_count: {type: integer, minimum: 0} - created_at: {type: string, format: date-time} - updated_at: {type: string, format: date-time} - updated_by: {type: string} - ProviderList: - type: object - required: [mode, providers] - properties: - mode: {$ref: '#/components/schemas/Mode'} - providers: {type: array, items: {$ref: '#/components/schemas/Provider'}} - ProviderResponse: - type: object - required: [mode, provider] - properties: - mode: {$ref: '#/components/schemas/Mode'} - provider: {$ref: '#/components/schemas/Provider'} - ObservationInput: - type: object - additionalProperties: false - required: [cell_id, boot_id, sequence, observed_at, source, states] - properties: - observation_id: {type: string} - cell_id: {type: string} - trunk_id: {type: string} - boot_id: {type: string, minLength: 1} - sequence: {type: integer, minimum: 1} - observed_at: {type: string, format: date-time} - source: {type: string} - config_revision: {type: integer, minimum: 0} - states: {type: object} - occupancy: {type: object} - sample_id: {type: string} - StatusItem: - type: object - required: [mode, cell_id, availability, complete, missing_sources] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cell_id: {type: string} - availability: {type: string, enum: [healthy, stale, unknown, disabled]} - complete: {type: boolean} - observed_at: {type: [string, 'null'], format: date-time} - received_at: {type: [string, 'null'], format: date-time} - observation_age_seconds: {type: [integer, 'null'], minimum: 0} - clock_skew: {type: boolean} - reason: {type: string} - boot_id: {type: string} - sequence: {type: integer, minimum: 1} - config_revision: {type: integer, minimum: 1} - config_status: {type: string} - egress_pool_id: {type: string} - eligibility: {type: string} - missing_sources: {type: array, items: {type: string}} - states: {type: object} - occupancy: {type: object} - trunks: {type: array, items: {type: object}} - publication: {type: object} - StatusResponse: - type: object - required: [mode, complete, cells] - properties: - mode: {$ref: '#/components/schemas/Mode'} - complete: {type: boolean} - generated_at: {type: string, format: date-time} - data_as_of: {type: [string, 'null'], format: date-time} - coverage: {type: object} - cells: {type: array, items: {$ref: '#/components/schemas/StatusItem'}} - StatisticsSummary: - type: object - required: [mode, from, to, complete, metrics] - properties: - mode: {$ref: '#/components/schemas/StatsMode'} - from: {type: string, format: date-time} - to: {type: string, format: date-time} - timezone: {type: string} - definition_version: {type: string} - filters: {type: object} - complete: {type: boolean} - missing_sources: {type: array, items: {type: string}} - unresolved_count: {type: integer, minimum: 0} - data_as_of: {type: [string, 'null'], format: date-time} - metrics: {type: object} - failure_reasons: {type: array, items: {type: object}} - realtime: {type: object} - TimeseriesResponse: - type: object - required: [mode, from, to, granularity, complete, series] - properties: - mode: {$ref: '#/components/schemas/StatsMode'} - from: {type: string, format: date-time} - to: {type: string, format: date-time} - timezone: {type: string} - definition_version: {type: string} - filters: {type: object} - granularity: {type: string, enum: [minute, hour, day]} - complete: {type: boolean} - series: {type: array, items: {type: object}} - ErrorResponse: - type: object - required: [error] - properties: - error: - type: object - required: [code, message] - properties: - code: {type: string} - message: {type: string} - fields: {type: object} - request_id: {type: string} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/README.md b/contracts/archive/upstream/2026-09-18-p1-baseline/README.md deleted file mode 100644 index 05ad816..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# 2026-09-18 P1 development contract baseline - -This is the **project-owned** W01 development release. It is self-contained and -embedded by `contracts/contracts.go`; runtime code does not read the parent -project or the source snapshot directory. - -## Scope closed for local development - -- strict envelope plus eight event payload schemas; -- explicit `full_ai` and `asr_only` immutable AI branches, with legacy full-AI - compatibility; -- Dispatcher-to-Agent AI authorization, tenant/original-key binding and digest; -- static Cell/SIP hand-off artifact shape; -- Agent-direct OSS upload request/grant/complete/verified metadata; -- P1 mock two-Cell development profile with real authorization deliberately - blocked; and -- positive and negative fixtures for each boundary. - -`release-manifest.json`, `SNAPSHOT.json`, and the parent `manifest.txt` record -source ancestry and SHA-256 hashes. The source snapshot was dirty when -imported, so this release is **not** an externally authoritative SaaS -publication and does not authorize real SIP, AI, OSS, cloud or paid activity. -The external authority/real-budget gate remains a W04/W14 concern. - -The release must be changed as a whole: update the version, regenerate hashes, -run the contract and AI tests, and update the embedded source pointer only after -reviewing compatibility. diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/SNAPSHOT.json b/contracts/archive/upstream/2026-09-18-p1-baseline/SNAPSHOT.json deleted file mode 100644 index c6b729a..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/SNAPSHOT.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "release_version": "2026-09-18-p1-baseline", - "release_kind": "project-owned-development-baseline", - "contract_status": "locally-locked-not-external-authoritative", - "source_bundle": "2026-09-17-snapshot", - "source_repository": "git.ipao.vip/rogee/ai-call", - "source_snapshot": "2026-09-17", - "source_head": "fa6925010ba47976d2e99893eac92140b3cb0d09", - "source_worktree": "dirty", - "runtime_dependency": "none (bundle is embedded; parent paths are never read at runtime)", - "amendments": [ - "event-payloads.schema.json closes the eight event payload schemas and strict event_type dispatch", - "ai-config.schema.json adds explicit full_ai/asr_only branches with legacy full-AI compatibility", - "examples include positive and negative mode/event fixtures", - "W01 release metadata and hashes are generated from this self-contained directory" - ] -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/ai-authorization.schema.json b/contracts/archive/upstream/2026-09-18-p1-baseline/ai-authorization.schema.json deleted file mode 100644 index ef7ee1c..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/ai-authorization.schema.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/ai-authorization.schema.json", - "title": "Dispatcher to Agent immutable AI authorization", - "type": "object", - "additionalProperties": false, - "required": ["authorization_id", "tenant_id", "tenant_key", "agent_version_id", "config_sha256", "mode", "issued_at", "expires_at", "source", "revoked"], - "properties": { - "authorization_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "tenant_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "tenant_key": {"type": "string", "minLength": 1, "maxLength": 224}, - "agent_version_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "config_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "mode": {"enum": ["full_ai", "asr_only"]}, - "issued_at": {"type": "string", "format": "date-time"}, - "expires_at": {"type": "string", "format": "date-time"}, - "source": {"enum": ["saas", "mock-saas"]}, - "credential_refs": { - "type": "object", - "additionalProperties": false, - "properties": { - "asr": {"type": "string", "minLength": 1, "maxLength": 128}, - "llm": {"type": "string", "minLength": 1, "maxLength": 128}, - "tts": {"type": "string", "minLength": 1, "maxLength": 128} - } - }, - "allowed_egress_pool_ids": { - "type": "array", "minItems": 1, "uniqueItems": true, - "items": {"type": "string", "minLength": 1, "maxLength": 128} - }, - "revoked": {"type": "boolean"}, - "revocation_reason": {"type": "string", "maxLength": 256} - }, - "allOf": [ - { - "if": {"properties": {"revoked": {"const": true}}}, - "then": {"required": ["revocation_reason"]} - } - ] -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/ai-config.openapi.yaml b/contracts/archive/upstream/2026-09-18-p1-baseline/ai-config.openapi.yaml deleted file mode 100644 index e310606..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/ai-config.openapi.yaml +++ /dev/null @@ -1,145 +0,0 @@ -openapi: 3.1.0 -info: - title: agent-call immutable AI configuration API - version: 1.0.0 - description: >- - Internal configuration publication/read surface. The call.execute business - command remains RabbitMQ-only; secrets, URLs, and provider credentials are - resolved by the execution environment and never enter MQ messages. -servers: - - url: / -paths: - /internal/v1/ai/agent-versions: - post: - operationId: publishAgentVersion - security: - - aiConfigPublish: [] - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionPublishRequest' - responses: - '200': - description: Identical immutable content already exists - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionReceipt' - '201': - description: Immutable version published - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionReceipt' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '409': - description: Existing version has different content - /internal/v1/ai/agent-versions/{agent_version_id}: - get: - operationId: getAgentVersion - security: - - aiConfigRead: [] - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - name: agent_version_id - in: path - required: true - schema: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$' - responses: - '200': - description: Trusted immutable snapshot - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersion' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '404': - description: Agent version not found -components: - parameters: - TenantId: - name: X-Tenant-Id - in: header - required: true - schema: {type: string, minLength: 1} - RequestId: - name: X-Request-Id - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - securitySchemes: - aiConfigPublish: - type: http - scheme: bearer - bearerFormat: JWT - description: >- - Requires scope ai.config.publish and the AI-config issuer/audience. - aiConfigRead: - type: http - scheme: bearer - bearerFormat: JWT - description: >- - Requires scope ai.config.read and the AI-config issuer/audience. - schemas: - AgentVersionPublishRequest: - type: object - additionalProperties: false - required: [agent_version_id, config] - properties: - agent_version_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$' - config: - $ref: 'ai-config.schema.json' - AgentVersionReceipt: - type: object - required: [tenant_id, agent_version_id, status, immutable, content_sha256] - properties: - tenant_id: {type: string} - agent_version_id: {type: string} - status: {enum: [published, reused]} - immutable: {const: true} - content_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - AgentVersion: - allOf: - - $ref: '#/components/schemas/AgentVersionReceipt' - - type: object - required: [config] - properties: - config: - $ref: 'ai-config.schema.json' - created_at: {type: string, format: date-time} - published_at: {type: string, format: date-time} - created_by: {type: string} - Error: - type: object - required: [error] - properties: - error: {type: string} - message: {type: string} - responses: - BadRequest: - description: Invalid configuration - content: - application/json: - schema: {$ref: '#/components/schemas/Error'} - Unauthorized: - description: Missing or invalid AI-config token - Forbidden: - description: Token lacks the AI-config permission diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/ai-config.schema.json b/contracts/archive/upstream/2026-09-18-p1-baseline/ai-config.schema.json deleted file mode 100644 index cf06b62..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/ai-config.schema.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/ai-config.schema.json", - "title": "Immutable AI agent version", - "type": "object", - "additionalProperties": false, - "required": ["agent_version_id", "immutable", "asr", "conversation"], - "properties": { - "agent_version_id": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"}, - "immutable": {"const": true}, - "mode": {"enum": ["full_ai", "asr_only"]}, - "llm": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "model"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "temperature": {"type": "number", "minimum": 0, "maximum": 2}, - "max_tokens": {"type": "integer", "minimum": 1}, - "timeout_ms": {"type": "integer", "minimum": 1} - } - }, - "prompt": { - "type": "object", - "additionalProperties": false, - "required": ["text", "allowed_variables"], - "properties": { - "text": {"type": "string", "minLength": 1, "maxLength": 32768}, - "allowed_variables": { - "type": "array", - "maxItems": 32, - "items": {"type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"} - }, - "max_bytes": {"type": "integer", "minimum": 1, "maximum": 32768} - } - }, - "tts": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "model", "voice", "format"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "voice": {"type": "string", "minLength": 1, "maxLength": 128}, - "speed": {"type": "number", "minimum": 0.25, "maximum": 3}, - "timeout_ms": {"type": "integer", "minimum": 1}, - "format": { - "type": "object", - "additionalProperties": false, - "required": ["encoding", "sample_rate_hz", "channels"], - "properties": { - "encoding": {"enum": ["pcm_s16le", "pcma"]}, - "sample_rate_hz": {"type": "integer", "minimum": 8000, "maximum": 48000}, - "channels": {"const": 1} - } - } - } - }, - "asr": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "language", "input"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "language": {"type": "string", "minLength": 1, "maxLength": 32}, - "interim": {"type": "boolean"}, - "timeout_ms": {"type": "integer", "minimum": 1}, - "input": { - "type": "object", - "additionalProperties": false, - "required": ["encoding", "sample_rate_hz", "channels", "sample_width_bytes"], - "properties": { - "encoding": {"const": "pcm_s16le"}, - "sample_rate_hz": {"type": "integer", "minimum": 8000, "maximum": 48000}, - "channels": {"const": 1}, - "sample_width_bytes": {"const": 2} - } - } - } - }, - "conversation": { - "type": "object", - "additionalProperties": false, - "required": ["allow_interrupt", "silence_timeout_ms", "max_duration_ms", "max_turns", "sentence_max_chars", "max_pending_audio_chunks"], - "properties": { - "opening": {"type": "string", "maxLength": 32768}, - "allow_interrupt": {"type": "boolean"}, - "silence_timeout_ms": {"type": "integer", "minimum": 1}, - "max_duration_ms": {"type": "integer", "minimum": 1, "maximum": 3600000}, - "max_turns": {"type": "integer", "minimum": 1, "maximum": 1000}, - "sentence_max_chars": {"type": "integer", "minimum": 1}, - "max_pending_audio_chunks": {"type": "integer", "minimum": 1} - } - }, - "metadata": {"type": "object", "additionalProperties": true} - }, - "oneOf": [ - { - "title": "Full AI", - "required": ["llm", "prompt", "tts"], - "properties": { - "mode": {"enum": ["full_ai"]}, - "conversation": {"required": ["opening"]} - } - }, - { - "title": "ASR only", - "required": ["mode"], - "properties": {"mode": {"const": "asr_only"}}, - "not": {"anyOf": [ - {"required": ["llm"]}, - {"required": ["prompt"]}, - {"required": ["tts"]} - ]} - } - ] -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/cell-agent.openapi.yaml b/contracts/archive/upstream/2026-09-18-p1-baseline/cell-agent.openapi.yaml deleted file mode 100644 index f37e4c0..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/cell-agent.openapi.yaml +++ /dev/null @@ -1,232 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Cell Agent API - version: 1.0.0 - description: >- - Restricted mTLS API used by the SIP management backend to deliver a - versioned Trunk snapshot to one voice Cell. The Cell validates the SHA-256 - snapshot, applies it with an atomic file replacement, reloads Asterisk, - restores the previous file on reload failure, and returns applied only - after the reload succeeds. A disabled snapshot removes the Cell-local - Trunk fragment and reloads Asterisk. -servers: - - url: https://cell.internal:9443 - description: Cell management network only -tags: - - name: health - - name: trunk-apply -paths: - /healthz/live: - get: - tags: [health] - operationId: live - responses: - '200': - description: Cell Agent is alive - content: - application/json: - schema: {$ref: '#/components/schemas/Health'} - /v1/sip/trunks/{trunk_id}/apply: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [trunk-apply] - operationId: applyTrunk - security: [{CellManagementMtls: []}] - parameters: - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/Publication'} - responses: - '200': - description: Asterisk has loaded the exact snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Acknowledgement'} - '400': {$ref: '#/components/responses/BadRequest'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': - description: >- - Revision or expected local snapshot is stale; the Cell never - guesses over an unknown baseline - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - '502': - description: Asterisk rejected the apply or reload - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - /v1/sip/trunks/{trunk_id}/state: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [trunk-apply] - operationId: getTrunkState - security: [{CellManagementMtls: []}] - responses: - '200': - description: Durable Cell apply state - content: - application/json: - schema: {$ref: '#/components/schemas/State'} - '404': {$ref: '#/components/responses/NotFound'} -components: - securitySchemes: - CellManagementMtls: - type: mutualTLS - description: Management backend client certificate signed by the Cell CA. - parameters: - TrunkId: - name: trunk_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - schemas: - Health: - type: object - additionalProperties: false - required: [status, mode, cell_id] - properties: - status: {type: string, const: ok} - mode: {type: string, const: real} - cell_id: {type: string} - CodecProfile: - type: object - additionalProperties: false - required: [allowed, preferred] - properties: - allowed: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - preferred: {type: string, enum: [PCMA, PCMU]} - SipConfig: - type: object - additionalProperties: false - required: [host, port, transport, auth_mode, register, credential_ref] - properties: - host: {type: string, minLength: 1, maxLength: 253} - port: {type: integer, minimum: 1, maximum: 65535} - transport: {type: string, enum: [udp, tcp, tls]} - auth_mode: {type: string, enum: [ip, digest]} - register: {type: boolean} - credential_ref: - type: [string, 'null'] - description: Secret-store reference only; plaintext is forbidden. - TrunkConfig: - type: object - additionalProperties: false - required: - - provider_id - - display_name - - enabled - - sip - - codec_profile - - caller_ids - - dial_prefix - - egress_pool_id - - max_concurrency - - max_cps - properties: - provider_id: {type: string} - display_name: {type: string, minLength: 1, maxLength: 256} - enabled: {type: boolean} - sip: {$ref: '#/components/schemas/SipConfig'} - codec_profile: {$ref: '#/components/schemas/CodecProfile'} - caller_ids: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, minLength: 1, maxLength: 128} - dial_prefix: {type: string, maxLength: 32} - egress_pool_id: {type: string} - max_concurrency: {type: integer, minimum: 1} - max_cps: {type: integer, minimum: 1} - Publication: - type: object - additionalProperties: false - required: - [mode, cell_id, trunk_id, revision, expected_local_revision, config, - config_sha256] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - expected_local_revision: {type: integer, minimum: 0} - config: {$ref: '#/components/schemas/TrunkConfig'} - config_sha256: - type: string - pattern: '^[0-9a-f]{64}$' - Acknowledgement: - type: object - additionalProperties: false - required: - [mode, cell_id, trunk_id, revision, config_sha256, status, idempotent] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - config_sha256: {type: string, pattern: '^[0-9a-f]{64}$'} - status: {type: string, const: applied} - idempotent: {type: boolean} - State: - type: object - additionalProperties: false - required: - [ - mode, - cell_id, - trunk_id, - desired_revision, - applied_revision, - status, - updated_at, - ] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - desired_revision: {type: integer, minimum: 1} - applied_revision: {type: integer, minimum: 0} - status: {type: string, enum: [applying, applied, failed]} - last_error: {type: [string, 'null']} - updated_at: {type: string, format: date-time} - ErrorResponse: - type: object - required: [error] - properties: - error: - type: object - required: [code, message] - properties: - code: {type: string} - message: {type: string} - responses: - BadRequest: - description: Invalid publication or hash - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Forbidden: - description: Certificate or Cell identity is not authorized - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - NotFound: - description: State does not exist - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/event-payloads.schema.json b/contracts/archive/upstream/2026-09-18-p1-baseline/event-payloads.schema.json deleted file mode 100644 index db4cecc..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/event-payloads.schema.json +++ /dev/null @@ -1,170 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/event-payloads.schema.json", - "title": "Agent-call versioned event envelopes and payloads", - "type": "object", - "additionalProperties": false, - "required": ["schema_version", "event_id", "event_type", "tenant_id", "tenant_key", "trace_id", "occurred_at", "aggregate_type", "aggregate_id", "aggregate_version", "payload"], - "properties": { - "schema_version": {"const": "1.0"}, - "event_id": {"$ref": "#/$defs/id"}, - "event_type": {"type": "string"}, - "tenant_id": {"$ref": "#/$defs/id"}, - "tenant_key": {"type": "string", "minLength": 1, "maxLength": 224}, - "trace_id": {"$ref": "#/$defs/id"}, - "occurred_at": {"type": "string", "format": "date-time"}, - "aggregate_type": {"type": "string", "minLength": 1, "maxLength": 64}, - "aggregate_id": {"$ref": "#/$defs/id"}, - "aggregate_version": {"type": "integer", "minimum": 1}, - "payload": {"type": "object"} - }, - "oneOf": [ - {"properties": {"event_type": {"const": "command.result"}, "payload": {"$ref": "#/$defs/command_result"}}}, - {"properties": {"event_type": {"const": "call.status"}, "payload": {"$ref": "#/$defs/call_status"}}}, - {"properties": {"event_type": {"const": "transcript.updated"}, "payload": {"$ref": "#/$defs/transcript_updated"}}}, - {"properties": {"event_type": {"const": "call.finished"}, "payload": {"$ref": "#/$defs/call_finished"}}}, - {"properties": {"event_type": {"const": "recording.ready"}, "payload": {"$ref": "#/$defs/recording_ready"}}}, - {"properties": {"event_type": {"const": "recording.failed"}, "payload": {"$ref": "#/$defs/recording_failed"}}}, - {"properties": {"event_type": {"const": "transcript.failed"}, "payload": {"$ref": "#/$defs/transcript_failed"}}}, - {"properties": {"event_type": {"const": "contact.opt_out"}, "payload": {"$ref": "#/$defs/contact_opt_out"}}} - ], - "$defs": { - "id": {"type": "string", "minLength": 1, "maxLength": 128}, - "command_result": { - "type": "object", "additionalProperties": false, - "required": ["command_id", "command_type", "status", "reason_code"], - "properties": { - "command_id": {"$ref": "#/$defs/id"}, - "command_type": {"enum": ["call.execute", "task.control"]}, - "status": {"enum": ["accepted", "waiting", "applied", "rejected", "failed", "unknown"]}, - "reason_code": {"type": "string", "minLength": 1, "maxLength": 128}, - "task_id": {"$ref": "#/$defs/id"}, - "task_item_id": {"$ref": "#/$defs/id"}, - "execution_id": {"$ref": "#/$defs/id"}, - "call_id": {"$ref": "#/$defs/id"}, - "requested_task_revision": {"type": "integer", "minimum": 0}, - "applied_task_revision": {"type": "integer", "minimum": 0}, - "admission_state": {"enum": ["open", "closed", "draining", "quarantined", "unknown"]}, - "resource_reservation_id": {"$ref": "#/$defs/id"}, - "permit_id": {"$ref": "#/$defs/id"} - } - }, - "call_status": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "execution_id", "call_state", "call_version", "attempt_id", "attempt_state"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "execution_id": {"$ref": "#/$defs/id"}, - "task_id": {"$ref": "#/$defs/id"}, - "task_item_id": {"$ref": "#/$defs/id"}, - "call_state": {"enum": ["queued", "dialing", "ringing", "answered", "ended"]}, - "call_version": {"type": "integer", "minimum": 1}, - "attempt_id": {"$ref": "#/$defs/id"}, - "attempt_state": {"enum": ["pending", "active", "ended", "unknown"]}, - "route_policy_id": {"$ref": "#/$defs/id"}, - "caller_profile_id": {"$ref": "#/$defs/id"}, - "trunk_id": {"$ref": "#/$defs/id"}, - "cell_id": {"$ref": "#/$defs/id"}, - "egress_pool_id": {"$ref": "#/$defs/id"}, - "observed_at": {"type": "string", "format": "date-time"}, - "reason_code": {"type": "string", "maxLength": 128} - } - }, - "transcript_updated": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "turn_id", "segment_id", "role", "revision", "text", "is_final", "start_ms", "end_ms", "playback_state"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "execution_id": {"$ref": "#/$defs/id"}, - "turn_id": {"$ref": "#/$defs/id"}, - "segment_id": {"$ref": "#/$defs/id"}, - "role": {"enum": ["customer", "agent", "system"]}, - "revision": {"type": "integer", "minimum": 1}, - "text": {"type": "string", "maxLength": 32768}, - "is_final": {"type": "boolean"}, - "start_ms": {"type": "integer", "minimum": 0}, - "end_ms": {"type": "integer", "minimum": 0}, - "playback_state": {"enum": ["not_applicable", "generated", "sent", "playback_confirmed", "cancelled", "unknown"]} - } - }, - "call_finished": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "execution_id", "call_version", "outcome", "started_at", "ended_at", "duration_ms", "reason_code"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "execution_id": {"$ref": "#/$defs/id"}, - "task_id": {"$ref": "#/$defs/id"}, - "task_item_id": {"$ref": "#/$defs/id"}, - "call_version": {"type": "integer", "minimum": 1}, - "outcome": {"enum": ["answered", "no_answer", "busy", "failed", "opt_out", "cancelled", "unknown"]}, - "started_at": {"type": "string", "format": "date-time"}, - "ended_at": {"type": "string", "format": "date-time"}, - "duration_ms": {"type": "integer", "minimum": 0}, - "reason_code": {"type": "string", "minLength": 1, "maxLength": 128}, - "attempt_summary": {"type": "array", "maxItems": 32, "items": {"$ref": "#/$defs/attempt_summary"}}, - "asset_state": {"enum": ["pending", "complete", "failed", "unknown"]} - } - }, - "attempt_summary": { - "type": "object", "additionalProperties": false, - "required": ["attempt_id", "state"], - "properties": { - "attempt_id": {"$ref": "#/$defs/id"}, - "state": {"enum": ["pending", "active", "ended", "unknown"]}, - "trunk_id": {"$ref": "#/$defs/id"}, - "cell_id": {"$ref": "#/$defs/id"}, - "reason_code": {"type": "string", "maxLength": 128} - } - }, - "recording_ready": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "recording_id", "oss_id", "format", "channels", "sample_rate_hz", "duration_ms", "size_bytes", "checksum_sha256"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "recording_id": {"$ref": "#/$defs/id"}, - "oss_id": {"$ref": "#/$defs/id"}, - "format": {"enum": ["wav", "raw_pcm", "pcma"]}, - "channels": {"const": 1}, - "sample_rate_hz": {"type": "integer", "minimum": 8000, "maximum": 48000}, - "duration_ms": {"type": "integer", "minimum": 0}, - "size_bytes": {"type": "integer", "minimum": 1}, - "checksum_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"} - } - }, - "recording_failed": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "recording_id", "stage", "reason_code", "retryable"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "recording_id": {"$ref": "#/$defs/id"}, - "stage": {"enum": ["seal", "request", "upload", "complete", "verify", "cleanup"]}, - "reason_code": {"type": "string", "minLength": 1, "maxLength": 128}, - "retryable": {"type": "boolean"}, - "next_retry_at": {"type": "string", "format": "date-time"} - } - }, - "transcript_failed": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "reason_code", "retryable"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "reason_code": {"type": "string", "minLength": 1, "maxLength": 128}, - "retryable": {"type": "boolean"}, - "segment_id": {"$ref": "#/$defs/id"}, - "affected_segments": {"type": "array", "maxItems": 256, "items": {"$ref": "#/$defs/id"}} - } - }, - "contact_opt_out": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "task_id", "task_item_id", "requested_at"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "task_id": {"$ref": "#/$defs/id"}, - "task_item_id": {"$ref": "#/$defs/id"}, - "requested_at": {"type": "string", "format": "date-time"}, - "turn_id": {"$ref": "#/$defs/id"}, - "segment_id": {"$ref": "#/$defs/id"} - } - } - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/README.md b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/README.md deleted file mode 100644 index ed9b3ae..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Contract fixtures - -`call.execute.json` is the canonical valid command fixture. Runtime tests generate the remaining event fixtures from persisted facts so replay assertions compare original bytes and IDs rather than synthesized history. Invalid cases include unknown schema versions, missing required fields, cross-tenant bindings, conflicting idempotency bodies, and tenant routing keys over 224 UTF-8 bytes. - -The bundle contains legacy full-AI, explicit full-AI, ASR-only, event-positive, and event-negative fixtures. All fixtures are synthetic. The profile is `mock`; it is never a production provider configuration. `transcript.updated` is the only valid transcript event name; `call.transcript` is intentionally invalid. diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version-asr-only.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version-asr-only.json deleted file mode 100644 index 7ecf915..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version-asr-only.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "agent_version_id": "agent_asr_v1", - "immutable": true, - "mode": "asr_only", - "asr": { - "provider_ref": "mock", - "model": "mock-asr-v1", - "language": "zh-CN", - "input": {"encoding": "pcm_s16le", "sample_rate_hz": 16000, "channels": 1, "sample_width_bytes": 2}, - "interim": true, - "timeout_ms": 5000 - }, - "conversation": { - "allow_interrupt": false, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version-full-explicit.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version-full-explicit.json deleted file mode 100644 index 8e0bc7f..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version-full-explicit.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "agent_version_id": "agent_full_v1", - "immutable": true, - "mode": "full_ai", - "llm": { - "provider_ref": "mock", - "model": "mock-chat-v1", - "temperature": 0.2, - "max_tokens": 256, - "timeout_ms": 5000 - }, - "prompt": { - "text": "You are a concise telephone assistant. Answer the caller's last statement.", - "allowed_variables": [], - "max_bytes": 32768 - }, - "tts": { - "provider_ref": "mock", - "model": "mock-tts-v1", - "voice": "mock-neutral", - "speed": 1.0, - "format": {"encoding": "pcm_s16le", "sample_rate_hz": 16000, "channels": 1}, - "timeout_ms": 5000 - }, - "asr": { - "provider_ref": "mock", - "language": "zh-CN", - "input": {"encoding": "pcm_s16le", "sample_rate_hz": 16000, "channels": 1, "sample_width_bytes": 2}, - "interim": true, - "timeout_ms": 5000 - }, - "conversation": { - "opening": "", - "allow_interrupt": true, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version.json deleted file mode 100644 index 61851cd..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/agent-version.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "agent_version_id": "agent_v1", - "immutable": true, - "llm": { - "provider_ref": "mock", - "model": "mock-chat-v1", - "temperature": 0.2, - "max_tokens": 256, - "timeout_ms": 5000 - }, - "prompt": { - "text": "You are a concise telephone assistant. Answer the caller's last statement.", - "allowed_variables": [], - "max_bytes": 32768 - }, - "tts": { - "provider_ref": "mock", - "model": "mock-tts-v1", - "voice": "mock-neutral", - "speed": 1.0, - "format": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1 - }, - "timeout_ms": 5000 - }, - "asr": { - "provider_ref": "mock", - "language": "zh-CN", - "input": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1, - "sample_width_bytes": 2 - }, - "interim": true, - "timeout_ms": 5000 - }, - "conversation": { - "opening": "", - "allow_interrupt": true, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/ai-authorization.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/ai-authorization.json deleted file mode 100644 index 1110b59..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/ai-authorization.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "authorization_id": "auth-1", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "agent_version_id": "agent_asr_v1", - "config_sha256": "24864df1fd72a59efaaaf6d1fc81a0c7db01fbdfcd821aab4069b64a8db9b60b", - "mode": "asr_only", - "issued_at": "2026-09-18T00:00:00Z", - "expires_at": "2026-09-18T00:01:00Z", - "source": "mock-saas", - "credential_refs": {"asr": "mock-asr-credential"}, - "allowed_egress_pool_ids": ["egress-mock"], - "revoked": false -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/call.execute.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/call.execute.json deleted file mode 100644 index 23f9fdc..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/call.execute.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "schema_version": "1.0", - "command_type": "call.execute", - "command_id": "cmd_demo_001", - "tenant_id": "tenant-demo", - "tenant_key": "tenant-demo-key", - "trace_id": "trace_demo_001", - "issued_at": "2026-09-11T08:00:00Z", - "not_after": "2099-09-11T08:05:00Z", - "payload": { - "execution_id": "exec_demo_001", - "task_id": "task-demo", - "task_item_id": "item_demo", - "task_revision": 1, - "callee": "18601013734", - "route_policy_id": "route_policy_test", - "caller_profile_id": "caller_profile_test", - "agent_version_id": "agent_v1", - "variables": {}, - "ring_timeout_ms": 30000, - "max_call_duration_ms": 180000 - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-call-finished.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-call-finished.json deleted file mode 100644 index 1ba64ae..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-call-finished.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-finished-1", - "event_type": "call.finished", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:03Z", - "aggregate_type": "call", - "aggregate_id": "call-1", - "aggregate_version": 2, - "payload": { - "call_id": "call-1", - "execution_id": "execution-1", - "task_id": "task-1", - "task_item_id": "item-1", - "call_version": 1, - "outcome": "answered", - "started_at": "2026-09-18T00:00:00Z", - "ended_at": "2026-09-18T00:00:03Z", - "duration_ms": 3000, - "reason_code": "normal_clearing", - "asset_state": "complete", - "attempt_summary": [{"attempt_id": "attempt-1", "state": "ended", "trunk_id": "trunk-1", "cell_id": "cell-1"}] - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-call-status.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-call-status.json deleted file mode 100644 index 8fc59ac..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-call-status.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-status-1", - "event_type": "call.status", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:01Z", - "aggregate_type": "call", - "aggregate_id": "call-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "execution_id": "execution-1", - "task_id": "task-1", - "task_item_id": "item-1", - "call_state": "answered", - "call_version": 1, - "attempt_id": "attempt-1", - "attempt_state": "active", - "route_policy_id": "route-1", - "caller_profile_id": "caller-1", - "trunk_id": "trunk-1", - "cell_id": "cell-1", - "egress_pool_id": "egress-1", - "observed_at": "2026-09-18T00:00:01Z" - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-command-result.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-command-result.json deleted file mode 100644 index 84daa6e..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-command-result.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-command-result-1", - "event_type": "command.result", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:00Z", - "aggregate_type": "command", - "aggregate_id": "command-1", - "aggregate_version": 1, - "payload": { - "command_id": "command-1", - "command_type": "call.execute", - "status": "accepted", - "reason_code": "accepted", - "execution_id": "execution-1" - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-contact-opt-out.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-contact-opt-out.json deleted file mode 100644 index 1f59c2a..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-contact-opt-out.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-opt-out-1", - "event_type": "contact.opt_out", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:06Z", - "aggregate_type": "contact", - "aggregate_id": "contact-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "task_id": "task-1", - "task_item_id": "item-1", - "requested_at": "2026-09-18T00:00:06Z", - "turn_id": "turn-1", - "segment_id": "segment-1" - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-recording-failed.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-recording-failed.json deleted file mode 100644 index af03187..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-recording-failed.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-recording-failed-1", - "event_type": "recording.failed", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:04Z", - "aggregate_type": "recording", - "aggregate_id": "recording-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "recording_id": "recording-1", - "stage": "upload", - "reason_code": "temporary_oss_unavailable", - "retryable": true, - "next_retry_at": "2026-09-18T00:01:00Z" - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-recording-ready.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-recording-ready.json deleted file mode 100644 index c0ad88f..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-recording-ready.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-recording-1", - "event_type": "recording.ready", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:02Z", - "aggregate_type": "recording", - "aggregate_id": "recording-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "recording_id": "recording-1", - "oss_id": "oss://bucket/object-1", - "format": "wav", - "channels": 1, - "sample_rate_hz": 16000, - "duration_ms": 1000, - "size_bytes": 32000, - "checksum_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-transcript-failed.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-transcript-failed.json deleted file mode 100644 index 8109d97..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-transcript-failed.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-transcript-failed-1", - "event_type": "transcript.failed", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:05Z", - "aggregate_type": "transcript", - "aggregate_id": "call-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "reason_code": "asr_timeout", - "retryable": false, - "segment_id": "segment-1", - "affected_segments": ["segment-1"] - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-transcript-updated.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-transcript-updated.json deleted file mode 100644 index 46d7796..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/event-transcript-updated.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-transcript-1", - "event_type": "transcript.updated", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:01Z", - "aggregate_type": "transcript_segment", - "aggregate_id": "segment-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "turn_id": "turn-1", - "segment_id": "segment-1", - "role": "customer", - "revision": 1, - "text": "您好", - "is_final": true, - "start_ms": 0, - "end_ms": 600, - "playback_state": "not_applicable" - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-ai-authorization-revoked.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-ai-authorization-revoked.json deleted file mode 100644 index 48a591b..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-ai-authorization-revoked.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "authorization_id": "auth-invalid", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "agent_version_id": "agent_asr_v1", - "config_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "mode": "asr_only", - "issued_at": "2026-09-18T00:00:00Z", - "expires_at": "2026-09-18T00:01:00Z", - "source": "mock-saas", - "revoked": true -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-asr-only-with-llm.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-asr-only-with-llm.json deleted file mode 100644 index c09e0f2..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-asr-only-with-llm.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "agent_version_id": "agent_invalid", - "immutable": true, - "mode": "asr_only", - "llm": {"provider_ref": "mock", "model": "must-not-be-present"}, - "asr": { - "provider_ref": "mock", - "language": "zh-CN", - "input": {"encoding": "pcm_s16le", "sample_rate_hz": 16000, "channels": 1, "sample_width_bytes": 2} - }, - "conversation": { - "allow_interrupt": false, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-event-unknown-type.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-event-unknown-type.json deleted file mode 100644 index 25476b8..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-event-unknown-type.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-invalid-1", - "event_type": "call.transcript", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:00Z", - "aggregate_type": "call", - "aggregate_id": "call-1", - "aggregate_version": 1, - "payload": {"text": "invalid alias"} -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-oss-upload-http.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-oss-upload-http.json deleted file mode 100644 index 42033e6..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/invalid-oss-upload-http.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "kind": "grant", - "upload_id": "upload-invalid", - "recording_id": "recording-1", - "upload_url": "http://oss.example.invalid/upload/upload-invalid", - "required_headers": {}, - "expires_at": "2026-09-18T00:05:00Z", - "max_bytes": 16777216, - "object_binding": "recording-1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/oss-upload-grant.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/oss-upload-grant.json deleted file mode 100644 index 6b4ddb3..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/oss-upload-grant.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "kind": "grant", - "upload_id": "upload-1", - "recording_id": "recording-1", - "upload_url": "https://oss.example.invalid/upload/upload-1", - "required_headers": {"x-checksum-sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, - "expires_at": "2026-09-18T00:05:00Z", - "max_bytes": 16777216, - "object_binding": "recording-1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/static-cell-artifact.json b/contracts/archive/upstream/2026-09-18-p1-baseline/examples/static-cell-artifact.json deleted file mode 100644 index 8203251..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/examples/static-cell-artifact.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "artifact_id": "artifact-cell-a-1", - "source_release": "management-snapshot-1", - "source_digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "approval_reference": "mock-approval-1", - "cell_id": "cell-a", - "revision": 1, - "config_sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - "mode": "mock", - "trunks": [ - {"trunk_id": "trunk-mock", "provider_id": "provider-mock", "egress_pool_id": "egress-mock", "codec": "PCMA", "caller_profile_ids": ["caller_profile_test"], "dial_prefix": "7089", "enabled": true, "sip_endpoint_ref": "mock-sip-endpoint", "credential_ref": null} - ], - "load_evidence": null -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/executor.openapi.yaml b/contracts/archive/upstream/2026-09-18-p1-baseline/executor.openapi.yaml deleted file mode 100644 index a9f02fb..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/executor.openapi.yaml +++ /dev/null @@ -1,303 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Executor Control API - version: 1.0.0 - description: >- - Internal control, query, replay, and recording hand-off API. Call execution - enters through RabbitMQ, not HTTP. -servers: - - url: https://executor.internal -security: - - bearerAuth: [] -paths: - /internal/v1/outbound/tasks/{task_id}/controls: - post: - operationId: controlTask - summary: Persist a pause, resume, or stop barrier - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/TaskId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ControlRequest' - responses: - '202': - description: Reliably persisted, not yet necessarily applied - headers: - Location: - schema: {type: string} - content: - application/json: - schema: {$ref: '#/components/schemas/ControlAccepted'} - '409': {$ref: '#/components/responses/Conflict'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/commands/{command_id}: - get: - operationId: getCommand - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/CommandId' - responses: - '200': - description: Command snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Command'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/calls/{call_id}: - get: - operationId: getCall - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/CallId' - responses: - '200': - description: Call snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Call'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/calls/{call_id}/replays: - post: - operationId: replayCall - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/CallId' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayRequest'} - responses: - '202': - description: Replay persisted for bounded broker delivery - headers: - Location: {schema: {type: string}} - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayAccepted'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - '410': {$ref: '#/components/responses/ReplayExpired'} - /internal/v1/outbound/commands/{source_command_id}/replays: - post: - operationId: replayCommand - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/SourceCommandId' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayRequest'} - responses: - '202': - description: Replay persisted for bounded broker delivery - headers: - Location: {schema: {type: string}} - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayAccepted'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - '410': {$ref: '#/components/responses/ReplayExpired'} -components: - securitySchemes: - bearerAuth: - type: http - scheme: bearer - parameters: - TenantId: - name: X-Tenant-ID - in: header - required: true - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string} - IdempotencyKey: - name: Idempotency-Key - in: header - required: true - schema: {type: string} - TaskId: - name: task_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - CommandId: - name: command_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - SourceCommandId: - name: source_command_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - CallId: - name: call_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - schemas: - Id: - type: string - minLength: 1 - maxLength: 128 - pattern: '^[^\s/\\]+$' - ControlRequest: - type: object - additionalProperties: false - required: [command_id, action, expected_task_revision, reason] - properties: - command_id: {$ref: '#/components/schemas/Id'} - action: {type: string, enum: [pause, resume, stop]} - expected_task_revision: {type: integer, minimum: 1} - active_call_policy: {type: string, enum: [drain, hangup]} - reason: {type: string, minLength: 1, maxLength: 512} - ControlAccepted: - type: object - required: - - command_id - - tenant_id - - tenant_key - - task_id - - status - - requested_task_revision - - accepted_at - properties: - command_id: {$ref: '#/components/schemas/Id'} - tenant_id: {type: string} - tenant_key: {type: string} - task_id: {$ref: '#/components/schemas/Id'} - status: {const: accepted} - requested_task_revision: {type: integer} - accepted_at: {type: string, format: date-time} - ReplayRequest: - type: object - additionalProperties: false - required: [command_id, reason] - properties: - command_id: {$ref: '#/components/schemas/Id'} - reason: {type: string, minLength: 1, maxLength: 512} - ReplayAccepted: - type: object - required: [command_id, status, snapshot_cutoff] - properties: - command_id: {$ref: '#/components/schemas/Id'} - status: {const: accepted} - snapshot_cutoff: {type: string, format: date-time} - Command: - type: object - required: - - command_id - - command_type - - tenant_id - - tenant_key - - status - - aggregate_version - properties: - command_id: {$ref: '#/components/schemas/Id'} - command_type: {type: string} - tenant_id: {type: string} - tenant_key: {type: string} - task_id: {type: [string, 'null']} - execution_id: {type: [string, 'null']} - call_id: {type: [string, 'null']} - status: {type: string} - reason_code: {type: [string, 'null']} - wait_reason_code: {type: [string, 'null']} - accepted_at: {type: [string, 'null'], format: date-time} - waiting_since: {type: [string, 'null'], format: date-time} - admission_deadline: {type: [string, 'null'], format: date-time} - requested_task_revision: {type: [integer, 'null']} - applied_task_revision: {type: [integer, 'null']} - task_state: {type: [string, 'null']} - updated_at: {type: string, format: date-time} - aggregate_version: {type: integer, minimum: 1} - Call: - type: object - required: - - call_id - - execution_id - - call_state - - call_version - - attempts - - transcript - - recordings - - delivery - - snapshot_at - properties: - call_id: {type: string} - execution_id: {type: string} - task_id: {type: string} - task_item_id: {type: string} - call_state: {type: string} - call_version: {type: integer} - reason_code: {type: [string, 'null']} - outcome: {type: [string, 'null']} - started_at: {type: [string, 'null'], format: date-time} - ended_at: {type: [string, 'null'], format: date-time} - duration_ms: {type: [integer, 'null']} - attempts: {type: array, items: {type: object}} - transcript: {type: object} - recordings: {type: array, items: {type: object}} - delivery: {type: object} - snapshot_at: {type: string, format: date-time} - Problem: - type: object - additionalProperties: false - required: [type, title, status, code, detail, request_id, retryable] - properties: - type: {type: string, format: uri-reference} - title: {type: string} - status: {type: integer} - code: {type: string} - detail: {type: string} - request_id: {type: string} - retryable: {type: boolean} - responses: - Unauthorized: - description: Unauthorized - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - Forbidden: - description: Forbidden - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - NotFound: - description: Not found without cross-tenant enumeration - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - Conflict: - description: Idempotency or revision conflict - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - ReplayExpired: - description: Retention window expired - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/mock-profile.json b/contracts/archive/upstream/2026-09-18-p1-baseline/mock-profile.json deleted file mode 100644 index 4a79b80..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/mock-profile.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "profile_version": "1.0.0", - "mode": "mock", - "provider_modes": { - "saas": "mock", - "database": "sqlite", - "rabbitmq": "memory", - "sip": "mock", - "asterisk": "mock", - "asr": "mock", - "llm": "mock", - "tts": "mock", - "oss": "mock", - "cloud": "fake-cli" - }, - "versions": {"schema": "1.0", "service": "0.1.0", "seed": "mock-2026-09-11"}, - "limits": { - "admission_window_s": 30, - "ring_timeout_ms": 30000, - "max_call_duration_ms": 180000, - "max_mq_bytes": 262144, - "max_queue_messages": 1000, - "max_queue_bytes": 16777216, - "disk_warn_pct": 0.70, - "disk_stop_pct": 0.80, - "max_http_bytes": 65536, - "recording_max_bytes": 16777216, - "max_recording_bytes": 16777216, - "replay_retention_s": 604800, - "upload_ttl_s": 300, - "global_concurrency": 6, - "global_cps": 3, - "tenant_concurrency": 2, - "tenant_cps": 1, - "tenant_publish_rate": 10, - "scheduler_lease_ttl_s": 10, - "pending_window_per_tenant": 16, - "pending_window_global": 64, - "max_unacked_per_tenant": 4, - "max_replay_attempts": 6, - "cell_capacity": 4, - "turns": 2, - "hold_ms": 0 - }, - "random_seed": 7, - "tenants": [ - {"tenant_id": "tenant-demo", "tenant_key": "tenant-demo-key", "enabled": true}, - {"tenant_id": "tenant-b", "tenant_key": "tenant.b", "enabled": true}, - {"tenant_id": "tenant-c", "tenant_key": "tenant#c", "enabled": true} - ], - "tasks": [ - {"task_id": "task-demo", "tenant_id": "tenant-demo", "state": "running", "revision": 1}, - {"task_id": "task-b", "tenant_id": "tenant-b", "state": "running", "revision": 1}, - {"task_id": "task-c", "tenant_id": "tenant-c", "state": "running", "revision": 1} - ], - "routes": [{"route_policy_id": "route_policy_test", "trunk_id": "trunk-mock", "egress_pool_id": "egress-mock", "dial_prefix": "7089", "allowed": true}], - "caller_profiles": [{"caller_profile_id": "caller_profile_test", "display": "BD93205882", "allowed": true}], - "agents": [{"agent_version_id": "agent_v1", "immutable": true, "llm": "mock", "tts": "mock", "asr": "mock"}], - "cells": [ - {"cell_id": "cell-a", "capacity": 4, "media_capacity": 4, "ai_capacity": 4, "egress_pool_id": "egress-mock", "ari_mode": "mock"}, - {"cell_id": "cell-b", "capacity": 4, "media_capacity": 4, "ai_capacity": 4, "egress_pool_id": "egress-mock", "ari_mode": "mock"} - ], - "failure_scenarios": ["success", "busy", "no_answer", "ai_timeout", "customer_silent", "ari_disconnect", "upload_missing", "upload_bad_checksum", "broker_outage", "clock_jump"] -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/mq-topology.md b/contracts/archive/upstream/2026-09-18-p1-baseline/mq-topology.md deleted file mode 100644 index 60f8501..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/mq-topology.md +++ /dev/null @@ -1,40 +0,0 @@ -# agent-call MQ topology v1.0 - -This file is an implementation companion to the field authority in -`SaaS交互_OpenAPI与MQ契约规划_v0.1.md`. - -| Element | Value | -| --- | --- | -| Namespace | `agent-call` | -| Command exchange | `agent-call.commands.v1`, durable `direct` | -| Tenant command queue | `agent-call.executor.{tenant_key}.v1`, durable, one exact binding | -| Command routing key | `agent-call.tenant.{tenant_key}.call.execute` | -| Event exchange | `agent-call.events.v1`, durable `topic` | -| SaaS result queue | `agent-call.saas.events.v1`, durable, binding `agent-call.#` | -| Event routing key | `agent-call.{event_type}` | -| Body limit | `262144` UTF-8 bytes in the Mock profile | -| Tenant route budget | Broker limit `255` bytes; fixed prefix/suffix consume `31`, leaving `224` UTF-8 bytes | - -## Delivery rules - -1. SaaS persists the command publication record before publishing. A mandatory - publisher confirmation is required; an unroutable/full queue leaves the - original record retained for bounded retry. -2. The executor consumes only its trusted tenant queue. RabbitMQ messages are - acknowledged after durable SQLite acceptance or durable dead-lettering, not - when they are fetched. -3. Executor business events are written to the same database transaction as - the state transition. The outbox dispatcher publishes them durably and the - SaaS inbox applies each `event_id` once. `saas_applied` may remain unknown - after broker confirmation; it does not trigger unbounded republishing. -4. `tenant_key` is copied byte-for-byte into the body, queue name, binding and - routing key. It is not normalized, encoded, truncated or cleaned. A route - over the byte budget is retained and not sent. -5. Replay publishes the original event body and original `event_id` from a - fixed retention cutoff. It never creates a new business fact and never - includes events written after that cutoff. -6. HTTP has no call execution or redial endpoint. Control, query, replay and - recording metadata paths require bearer scope and tenant scope. - -The in-process broker is only for deterministic tests. Docker Compose uses the -same topology through the `pika` adapter and RabbitMQ durable queues. diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/mq.schema.json b/contracts/archive/upstream/2026-09-18-p1-baseline/mq.schema.json deleted file mode 100644 index b5ab065..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/mq.schema.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.invalid/contracts/mq.schema.json", - "title": "agent-call MQ command and event envelope", - "oneOf": [{"$ref": "#/$defs/executeCommand"}, {"$ref": "#/$defs/event"}], - "$defs": { - "id": {"type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[^\\s/\\\\]+$"}, - "tenantKey": {"type": "string", "minLength": 1}, - "time": {"type": "string", "format": "date-time"}, - "executeCommand": { - "type": "object", "additionalProperties": false, - "required": ["schema_version", "command_type", "command_id", "tenant_id", "tenant_key", "trace_id", "issued_at", "not_after", "payload"], - "properties": { - "schema_version": {"const": "1.0"}, "command_type": {"const": "call.execute"}, "command_id": {"$ref": "#/$defs/id"}, - "tenant_id": {"$ref": "#/$defs/id"}, "tenant_key": {"$ref": "#/$defs/tenantKey"}, "trace_id": {"$ref": "#/$defs/id"}, - "issued_at": {"$ref": "#/$defs/time"}, "not_after": {"$ref": "#/$defs/time"}, "payload": {"$ref": "#/$defs/executePayload"} - } - }, - "executePayload": { - "type": "object", "additionalProperties": false, - "required": ["execution_id", "task_id", "task_item_id", "task_revision", "callee", "route_policy_id", "caller_profile_id", "agent_version_id", "variables", "ring_timeout_ms", "max_call_duration_ms"], - "properties": { - "execution_id": {"$ref": "#/$defs/id"}, "task_id": {"$ref": "#/$defs/id"}, "task_item_id": {"$ref": "#/$defs/id"}, - "task_revision": {"type": "integer", "minimum": 1}, "callee": {"type": "string", "minLength": 1, "maxLength": 256}, - "route_policy_id": {"$ref": "#/$defs/id"}, "caller_profile_id": {"$ref": "#/$defs/id"}, "agent_version_id": {"$ref": "#/$defs/id"}, - "variables": {"type": "object", "additionalProperties": true}, "ring_timeout_ms": {"type": "integer", "minimum": 1}, "max_call_duration_ms": {"type": "integer", "minimum": 1} - } - }, - "event": { - "type": "object", "additionalProperties": false, - "required": ["schema_version", "event_id", "event_type", "tenant_id", "tenant_key", "trace_id", "occurred_at", "aggregate_type", "aggregate_id", "aggregate_version", "payload"], - "properties": { - "schema_version": {"const": "1.0"}, "event_id": {"$ref": "#/$defs/id"}, - "event_type": {"enum": ["command.result", "call.status", "transcript.updated", "call.finished", "recording.ready", "recording.failed", "transcript.failed", "contact.opt_out"]}, - "tenant_id": {"$ref": "#/$defs/id"}, "tenant_key": {"$ref": "#/$defs/tenantKey"}, "trace_id": {"$ref": "#/$defs/id"}, "occurred_at": {"$ref": "#/$defs/time"}, - "aggregate_type": {"enum": ["command", "call", "transcript_segment", "recording"]}, "aggregate_id": {"$ref": "#/$defs/id"}, "aggregate_version": {"type": "integer", "minimum": 1}, "payload": {"type": "object"} - } - } - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/oss-upload.schema.json b/contracts/archive/upstream/2026-09-18-p1-baseline/oss-upload.schema.json deleted file mode 100644 index 1393b72..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/oss-upload.schema.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/oss-upload.schema.json", - "title": "Recording upload control-plane messages", - "type": "object", - "required": ["kind"], - "properties": {"kind": {"type": "string"}}, - "oneOf": [ - { - "additionalProperties": false, - "properties": { - "kind": {"const": "request"}, - "upload_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "recording_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "call_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "size_bytes": {"type": "integer", "minimum": 1}, - "checksum_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "format": {"enum": ["wav", "raw_pcm", "pcma"]}, - "channels": {"const": 1}, - "sample_rate_hz": {"type": "integer", "minimum": 8000}, - "duration_ms": {"type": "integer", "minimum": 1} - }, - "required": ["upload_id", "recording_id", "call_id", "size_bytes", "checksum_sha256", "format", "channels", "sample_rate_hz", "duration_ms"] - }, - { - "additionalProperties": false, - "properties": { - "kind": {"const": "grant"}, - "upload_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "recording_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "upload_url": {"type": "string", "format": "uri", "pattern": "^https://"}, - "required_headers": {"type": "object", "additionalProperties": {"type": "string"}}, - "expires_at": {"type": "string", "format": "date-time"}, - "max_bytes": {"type": "integer", "minimum": 1}, - "object_binding": {"type": "string", "minLength": 1, "maxLength": 256} - }, - "required": ["upload_id", "recording_id", "upload_url", "required_headers", "expires_at", "max_bytes", "object_binding"] - }, - { - "additionalProperties": false, - "properties": { - "kind": {"const": "complete"}, - "upload_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "recording_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "size_bytes": {"type": "integer", "minimum": 1}, - "checksum_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "etag": {"type": ["string", "null"], "maxLength": 256} - }, - "required": ["upload_id", "recording_id", "size_bytes", "checksum_sha256", "etag"] - }, - { - "additionalProperties": false, - "properties": { - "kind": {"const": "verified"}, - "upload_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "recording_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "oss_id": {"type": "string", "minLength": 1, "maxLength": 512}, - "verified_at": {"type": "string", "format": "date-time"}, - "checksum_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"} - }, - "required": ["upload_id", "recording_id", "oss_id", "verified_at", "checksum_sha256"] - } - ] -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/p1-development-profile.json b/contracts/archive/upstream/2026-09-18-p1-baseline/p1-development-profile.json deleted file mode 100644 index 21b0db6..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/p1-development-profile.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "profile_id": "p1-mock-two-cell-v1", - "profile_version": "1.0.0", - "environment": "mock", - "external_calls": false, - "real_authorization": "blocked", - "topology": {"dispatcher_count": 1, "agent_count": 2, "cell_count": 2, "tenant_count": 1}, - "limits": { - "global_concurrency": 6, - "global_cps": 3, - "tenant_concurrency": 2, - "tenant_cps": 1, - "pending_window_global": 64, - "pending_window_per_tenant": 16, - "lease_ttl_ms": 10000, - "final_permit_ttl_ms": 1000 - }, - "modes": ["full_ai", "asr_only"], - "retention": {"keep_unverified_assets": true, "delete_only_after_verified": true, "backup_kind": "local-sqlite-wal-consistent"}, - "status": "development-only-not-production-approval", - "real_budget": "unknown", - "operator_approval": "not-granted" -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/p1-development-profile.schema.json b/contracts/archive/upstream/2026-09-18-p1-baseline/p1-development-profile.schema.json deleted file mode 100644 index adb8b5d..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/p1-development-profile.schema.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/p1-development-profile.schema.json", - "title": "P1 isolated development profile", - "type": "object", - "additionalProperties": false, - "required": ["profile_id", "profile_version", "environment", "external_calls", "real_authorization", "topology", "limits", "modes", "retention", "status"], - "properties": { - "profile_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "profile_version": {"type": "string", "minLength": 1, "maxLength": 32}, - "environment": {"const": "mock"}, - "external_calls": {"const": false}, - "real_authorization": {"const": "blocked"}, - "topology": { - "type": "object", "additionalProperties": false, - "required": ["dispatcher_count", "agent_count", "cell_count", "tenant_count"], - "properties": {"dispatcher_count": {"const": 1}, "agent_count": {"const": 2}, "cell_count": {"const": 2}, "tenant_count": {"type": "integer", "minimum": 1}} - }, - "limits": { - "type": "object", "additionalProperties": false, - "required": ["global_concurrency", "global_cps", "tenant_concurrency", "tenant_cps", "pending_window_global", "pending_window_per_tenant", "lease_ttl_ms", "final_permit_ttl_ms"], - "properties": { - "global_concurrency": {"type": "integer", "minimum": 1}, - "global_cps": {"type": "integer", "minimum": 1}, - "tenant_concurrency": {"type": "integer", "minimum": 1}, - "tenant_cps": {"type": "integer", "minimum": 1}, - "pending_window_global": {"type": "integer", "minimum": 1}, - "pending_window_per_tenant": {"type": "integer", "minimum": 1}, - "lease_ttl_ms": {"const": 10000}, - "final_permit_ttl_ms": {"type": "integer", "minimum": 1, "maximum": 1000} - } - }, - "modes": {"type": "array", "minItems": 2, "uniqueItems": true, "items": {"enum": ["full_ai", "asr_only"]}}, - "retention": { - "type": "object", "additionalProperties": false, - "required": ["keep_unverified_assets", "delete_only_after_verified", "backup_kind"], - "properties": {"keep_unverified_assets": {"const": true}, "delete_only_after_verified": {"const": true}, "backup_kind": {"enum": ["local-sqlite-wal-consistent", "not-configured"]}} - }, - "status": {"const": "development-only-not-production-approval"}, - "real_budget": {"const": "unknown"}, - "operator_approval": {"const": "not-granted"} - } -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/release-manifest.json b/contracts/archive/upstream/2026-09-18-p1-baseline/release-manifest.json deleted file mode 100644 index e5d50bc..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/release-manifest.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "release_version": "2026-09-18-p1-baseline", - "release_kind": "project-owned-development-baseline", - "source_bundle": "2026-09-17-snapshot", - "source_worktree": "dirty-inherited-only", - "files": [ - { - "path": "README.md", - "bytes": 1319, - "sha256": "7f13e2f0012dfcc44bb979b71920b781a57db9cccc27099054d5919f1ba379d4" - }, - { - "path": "SNAPSHOT.json", - "bytes": 869, - "sha256": "f3c854b460e9d9a21466e9844bc3a3df5ae9c498643d4a703dd7b437e21bd862" - }, - { - "path": "ai-authorization.schema.json", - "bytes": 1749, - "sha256": "5d6bbd369bd6b406abe9b9f8619e6f299b544dacfdd4473a08257a366fd95d20" - }, - { - "path": "ai-config.openapi.yaml", - "bytes": 4516, - "sha256": "d2f75d8fd2bf76ceb4eef869a838f08dca156938e1f3025d126ce81e436f624a" - }, - { - "path": "ai-config.schema.json", - "bytes": 4797, - "sha256": "dc915bff70e71408fcacbaad47d3554bbfa7a22a51f2f53e127c6bd8bc8ba5a6" - }, - { - "path": "cell-agent.openapi.yaml", - "bytes": 7633, - "sha256": "79dc697d7ce16e2a6aa7e350f30dd006dd847afe2cdc0ea29841f9c6d4310c41" - }, - { - "path": "event-payloads.schema.json", - "bytes": 8683, - "sha256": "5091ded520d692f458699327b13adddeccb0c4b4d4a72ef7cdfebcd5d496eade" - }, - { - "path": "examples/README.md", - "bytes": 728, - "sha256": "a3514c7ef89b4324685bc9025139488000fa42330de72495484add042a6897cf" - }, - { - "path": "examples/agent-version-asr-only.json", - "bytes": 534, - "sha256": "24864df1fd72a59efaaaf6d1fc81a0c7db01fbdfcd821aab4069b64a8db9b60b" - }, - { - "path": "examples/agent-version-full-explicit.json", - "bytes": 1051, - "sha256": "e590148448885a1e88c473ca032d5efd719270689c3cff7aa44ca9c6ffa2b321" - }, - { - "path": "examples/agent-version.json", - "bytes": 1079, - "sha256": "d3d4bf2fae07192674e54bf32172a8e95146f11d70609f3cd8f57f0112633c2e" - }, - { - "path": "examples/ai-authorization.json", - "bytes": 467, - "sha256": "b1c0f723f083d1be45035792482f6f74bd3bca34486cc6408d4bcfe3772bc432" - }, - { - "path": "examples/call.execute.json", - "bytes": 656, - "sha256": "0164664fd3503d72668b24bdecb623aa0414ce58191960b868abe8454988c742" - }, - { - "path": "examples/event-call-finished.json", - "bytes": 783, - "sha256": "fab56aff9c5d4059b8fa65d24f2afa424148e7a07025238fc7fd30e9c5ee63f4" - }, - { - "path": "examples/event-call-status.json", - "bytes": 752, - "sha256": "5c673ceb4a98ce8c90d976356b4c5ffa6c7d96d045b5b3312513a9be93d585ba" - }, - { - "path": "examples/event-command-result.json", - "bytes": 498, - "sha256": "64fe71719573378b0caac2f7c5476a27ba7073df8c346d4748a6b0d534d4a087" - }, - { - "path": "examples/event-contact-opt-out.json", - "bytes": 513, - "sha256": "b661f65f0a195e59fe226b12ebae2feb5a9733a9a779c835245be27319aaf8f2" - }, - { - "path": "examples/event-recording-failed.json", - "bytes": 546, - "sha256": "4f5f46422d2281ffae65c99e947bc7dd44effb5e94eacc12e41b3250ac645c34" - }, - { - "path": "examples/event-recording-ready.json", - "bytes": 648, - "sha256": "2b6d731a8d7993cbbe07a5ba8c7413ec56bae8a1538476c0f1740133a488d5b4" - }, - { - "path": "examples/event-transcript-failed.json", - "bytes": 499, - "sha256": "58d000ce27de6e67054f66d4ded34ffafa983bdcced12613051f670d1eefeed8" - }, - { - "path": "examples/event-transcript-updated.json", - "bytes": 596, - "sha256": "115f276522631d7c4decee71ee238aa0d00b4256adedfc9a6a0c5f9dc89f64f6" - }, - { - "path": "examples/invalid-ai-authorization-revoked.json", - "bytes": 373, - "sha256": "0b946b43c1f773391791dfb60a2b2a03c8a69e64e5e9ea30af8591850c34b8f3" - }, - { - "path": "examples/invalid-asr-only-with-llm.json", - "bytes": 529, - "sha256": "7343ce8d6ce63e22128ab7bc721544d681a5dd9eccfc4ab4f9d6181c5748824c" - }, - { - "path": "examples/invalid-event-unknown-type.json", - "bytes": 348, - "sha256": "80c3f89dc775deec9d1a3b85c81ea4b2fd1b030bc4deba1a4dcd2823e4eb8024" - }, - { - "path": "examples/invalid-oss-upload-http.json", - "bytes": 347, - "sha256": "8e4fb4344c4bec51b47ff9b00a63afdc84d09ab827e1b6823c4e576bf6b6a3f1" - }, - { - "path": "examples/oss-upload-grant.json", - "bytes": 423, - "sha256": "268751a1a0d238636c04c004a635e3bda702bc2ef90ade0e5846b47a3c263b5d" - }, - { - "path": "examples/static-cell-artifact.json", - "bytes": 670, - "sha256": "e18b239adf260e2c9839f0b1527e67826787b7328f9b1e1f82750ded0e3bd0e5" - }, - { - "path": "executor.openapi.yaml", - "bytes": 10244, - "sha256": "b24703783df63e044fc0151c5e215430d2294e13937d2a5ceee3c6fee99b0329" - }, - { - "path": "mock-profile.json", - "bytes": 2549, - "sha256": "4d43097602fed9a68821e765117580706896ac82d4bce361a80a4cea544ab638" - }, - { - "path": "mq-topology.md", - "bytes": 2211, - "sha256": "a85b26596e1b1db7405dcabc967df56d5eb6713cc9908bc05ecaa2075ff1092f" - }, - { - "path": "mq.schema.json", - "bytes": 2953, - "sha256": "4fbfc39d46fb55ca48b71bc11cafce60e0814182ba4f898973c7c4d7657f912a" - }, - { - "path": "oss-upload.schema.json", - "bytes": 3039, - "sha256": "d3f6ffc5e004fba8acbb6a18495be508a63ec45766bab1ef946ece58bbad84de" - }, - { - "path": "p1-development-profile.json", - "bytes": 789, - "sha256": "2aa7cd3f4fa07f7e1a3037107fa7a56183f28370ea06a2a9b8dc18c8790eee2d" - }, - { - "path": "p1-development-profile.schema.json", - "bytes": 2460, - "sha256": "68e1b46194a1f5fa5bc763ba424411f48ada1ab52d39e6f800315a832692794b" - }, - { - "path": "saas.openapi.yaml", - "bytes": 5750, - "sha256": "368c3a7d75ecc74771b88f9bd9fb7131697c69ce695475fc5aaae6099ff889eb" - }, - { - "path": "sip-management.openapi.yaml", - "bytes": 38240, - "sha256": "5006bbb1fb69f7b4a05cbaa5a43f8944e8522172910a41aba61897c9d5e00281" - }, - { - "path": "static-cell-artifact.schema.json", - "bytes": 2199, - "sha256": "b5d6ad4fb8007a427088bf5f84c7ed89834c610a7714d459dbd6ee91fdb428fb" - } - ] -} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/saas.openapi.yaml b/contracts/archive/upstream/2026-09-18-p1-baseline/saas.openapi.yaml deleted file mode 100644 index e3f47c2..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/saas.openapi.yaml +++ /dev/null @@ -1,169 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call SaaS Recording Handoff API - version: 1.0.0 - description: >- - Internal storage handshake. Business results still return through RabbitMQ. -servers: - - url: https://saas.internal -security: - - bearerAuth: [] -paths: - /internal/v1/outbound/recording-uploads: - post: - operationId: createRecordingUpload - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/UploadRequest'} - responses: - '201': - description: Upload session created or existing session returned - headers: {Cache-Control: {schema: {const: no-store}}} - content: - application/json: - schema: {$ref: '#/components/schemas/UploadSession'} - '200': - description: Existing upload session - content: - application/json: - schema: {$ref: '#/components/schemas/UploadSession'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': {$ref: '#/components/responses/Conflict'} - /internal/v1/outbound/recording-uploads/{upload_id}/complete: - post: - operationId: completeRecordingUpload - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - name: upload_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/CompleteRequest'} - responses: - '200': - description: Object independently verified - content: - application/json: - schema: {$ref: '#/components/schemas/VerifiedUpload'} - '409': {$ref: '#/components/responses/Conflict'} - '410': {$ref: '#/components/responses/Expired'} - '422': {$ref: '#/components/responses/Unprocessable'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} -components: - securitySchemes: - bearerAuth: {type: http, scheme: bearer} - parameters: - TenantId: - name: X-Tenant-ID - in: header - required: true - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string} - IdempotencyKey: - name: Idempotency-Key - in: header - required: true - schema: {type: string} - schemas: - Id: - type: string - minLength: 1 - maxLength: 128 - pattern: '^[^\s/\\]+$' - UploadRequest: - type: object - additionalProperties: false - required: - - recording_id - - call_id - - content_type - - size_bytes - - checksum_algorithm - - checksum - - channels - - sample_rate_hz - - duration_ms - properties: - recording_id: {$ref: '#/components/schemas/Id'} - call_id: {$ref: '#/components/schemas/Id'} - content_type: {type: string, const: audio/wav} - size_bytes: {type: integer, minimum: 1} - checksum_algorithm: {type: string, const: SHA-256} - checksum: {type: string, pattern: '^[0-9a-f]{64}$'} - channels: {type: integer, const: 1} - sample_rate_hz: {type: integer, minimum: 8000} - duration_ms: {type: integer, minimum: 1} - UploadSession: - type: object - required: - - upload_id - - recording_id - - expires_at - - upload_method - - upload_url - - required_headers - - constraints - properties: - upload_id: {$ref: '#/components/schemas/Id'} - recording_id: {$ref: '#/components/schemas/Id'} - expires_at: {type: string, format: date-time} - upload_method: {const: PUT} - upload_url: {type: string, format: uri} - required_headers: {type: object} - constraints: {type: object} - oss_id: {type: [string, 'null']} - CompleteRequest: - type: object - additionalProperties: false - required: [recording_id, size_bytes, checksum_algorithm, checksum] - properties: - recording_id: {$ref: '#/components/schemas/Id'} - size_bytes: {type: integer, minimum: 1} - checksum_algorithm: {const: SHA-256} - checksum: {type: string, pattern: '^[0-9a-f]{64}$'} - etag: {type: [string, 'null']} - VerifiedUpload: - type: object - required: [upload_id, recording_id, status, oss_id, verified_at] - properties: - upload_id: {$ref: '#/components/schemas/Id'} - recording_id: {$ref: '#/components/schemas/Id'} - status: {const: verified} - oss_id: {type: string} - verified_at: {type: string, format: date-time} - Problem: - type: object - required: [type, title, status, code, detail, request_id, retryable] - properties: - type: {type: string} - title: {type: string} - status: {type: integer} - code: {type: string} - detail: {type: string} - request_id: {type: string} - retryable: {type: boolean} - responses: - Unauthorized: {description: Unauthorized} - Forbidden: {description: Forbidden} - Conflict: {description: Idempotency conflict} - Expired: {description: Upload expired} - Unprocessable: {description: Object failed independent verification} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/sip-management.openapi.yaml b/contracts/archive/upstream/2026-09-18-p1-baseline/sip-management.openapi.yaml deleted file mode 100644 index 28fee2b..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/sip-management.openapi.yaml +++ /dev/null @@ -1,1125 +0,0 @@ ---- -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Asterisk/SIP Management API - version: 1.0.0 - description: >- - Independent Asterisk/SIP management backend. Admin write operations are - separate from the SaaS read-only Trunk directory and from ordinary - scheduling APIs. In mock mode publication records are intents only. In - real mode a publication is successful only after every selected Cell Agent - returns a matching mTLS acknowledgement. -servers: - - url: https://sip-admin.internal - description: Restricted operator management network - - url: https://sip-read.internal - description: SaaS read-only service network -tags: - - name: health - - name: admin-providers - - name: admin-trunks - - name: admin-cells - - name: admin-status - - name: admin-statistics - - name: admin-audit - - name: saas-readonly -paths: - /healthz/live: - get: - tags: [health] - operationId: live - responses: - '200': - description: Service is alive - content: - application/json: - schema: - $ref: '#/components/schemas/Health' - /admin/v1/providers: - get: - tags: [admin-providers] - operationId: listProviders - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider directory - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderList'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/providers/{provider_id}: - parameters: - - {$ref: '#/components/parameters/ProviderId'} - get: - tags: [admin-providers] - operationId: getProvider - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-providers] - operationId: upsertProvider - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderInput'} - responses: - '200': - description: Updated provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '201': - description: Created provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '400': {$ref: '#/components/responses/BadRequest'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks: - get: - tags: [admin-trunks] - operationId: listAdminTrunks - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/TrunkStatusFilter'} - responses: - '200': - description: All Trunks, including unpublished revisions - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTrunkList' - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - /admin/v1/trunks/{trunk_id}: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: getAdminTrunk - security: [{SipAdminBearer: []}] - responses: - '200': - description: Trunk configuration and revisions - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTrunk' - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-trunks] - operationId: createTrunkRevision - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TrunkConfig' - responses: - '200': - description: New draft revision for an existing Trunk - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '201': - description: New Trunk with its first draft revision - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '400': {$ref: '#/components/responses/BadRequest'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/validate: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: validateTrunk - security: [{SipAdminBearer: []}] - requestBody: - required: false - content: - application/json: - schema: - type: object - additionalProperties: false - properties: - revision: {type: integer, minimum: 1} - responses: - '200': - description: Validation issues, compatible Cells, and impact preview - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/trunks/{trunk_id}/verifications: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: addTrunkVerification - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/VerificationRequest' - responses: - '200': - description: Versioned verification record - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/publish: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: publishTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - responses: - '200': - description: >- - Published revision after all selected Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/disable: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: disableTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - responses: - '200': - description: Trunk disabled after selected Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/rollback: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: rollbackTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - type: object - additionalProperties: false - required: [target_revision] - properties: - target_revision: {type: integer, minimum: 1} - responses: - '200': - description: >- - New revision copied from the target after Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/publications: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: listTrunkPublications - security: [{SipAdminBearer: []}] - responses: - '200': - description: Per-Cell publication intents - content: - application/json: - schema: - type: object - required: [mode, publications] - properties: - mode: {$ref: '#/components/schemas/Mode'} - publications: - type: array - items: {$ref: '#/components/schemas/Publication'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/trunks/{trunk_id}/audit: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: listTrunkAudit - security: [{SipAdminBearer: []}] - responses: - '200': - description: Immutable management audit entries - content: - application/json: - schema: - type: object - required: [mode, audit] - properties: - mode: {$ref: '#/components/schemas/Mode'} - audit: - type: array - items: {$ref: '#/components/schemas/AuditEntry'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/cells: - get: - tags: [admin-cells] - operationId: listCells - security: [{SipAdminBearer: []}] - responses: - '200': - description: Registered multi-machine voice Cells - content: - application/json: - schema: - type: object - required: [mode, cells] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cells: - type: array - items: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/cells/{cell_id}: - parameters: - - {$ref: '#/components/parameters/CellId'} - get: - tags: [admin-cells] - operationId: getCell - security: [{SipAdminBearer: []}] - responses: - '200': - description: Registered Cell - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-cells] - operationId: registerCell - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/CellConfig'} - responses: - '200': - description: Updated Cell revision - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '201': - description: Registered Cell - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/cells/{cell_id}/observations: - parameters: - - {$ref: '#/components/parameters/CellId'} - post: - tags: [admin-cells] - operationId: ingestCellObservation - security: [{SipAdminBearer: []}] - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ObservationInput'} - responses: - '201': - description: >- - Observation accepted for the current boot and monotonic sequence - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/egress-pools: - get: - tags: [admin-cells] - operationId: listEgressPools - security: [{SipAdminBearer: []}] - responses: - '200': - description: Fixed egress pool directory - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/sip-status: - get: - tags: [admin-status] - operationId: getSipStatus - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/CellIdsFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/ProviderFilter'} - responses: - '200': - description: >- - Cell/trunk status matrix with freshness and missing sources - content: - application/json: - schema: {$ref: '#/components/schemas/StatusResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/cells/{cell_id}/sip-status: - parameters: - - {$ref: '#/components/parameters/CellId'} - get: - tags: [admin-status] - operationId: getCellSipStatus - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/TrunkFilter'} - responses: - '200': - description: One Cell status - content: - application/json: - schema: {$ref: '#/components/schemas/StatusItem'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/providers/{provider_id}/status: - parameters: - - {$ref: '#/components/parameters/ProviderId'} - get: - tags: [admin-status] - operationId: getProviderStatus - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider status matrix - content: - application/json: - schema: {$ref: '#/components/schemas/StatusResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/statistics/outbound/summary: - get: - tags: [admin-statistics] - operationId: getOutboundSummary - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Cohort and interval metrics with completeness metadata - content: - application/json: - schema: {$ref: '#/components/schemas/StatisticsSummary'} - '401': {$ref: '#/components/responses/Unauthorized'} - '422': {$ref: '#/components/responses/BadRequest'} - /admin/v1/statistics/outbound/timeseries: - get: - tags: [admin-statistics] - operationId: getOutboundTimeseries - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/Granularity'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Bounded UTC time series - content: - application/json: - schema: {$ref: '#/components/schemas/TimeseriesResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '422': {$ref: '#/components/responses/BadRequest'} - /admin/v1/call-attempts: - get: - tags: [admin-statistics] - operationId: listCallAttempts - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/Limit'} - - {$ref: '#/components/parameters/Cursor'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Redacted raw attempt facts - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/call-attempts/{attempt_id}: - parameters: - - name: attempt_id - in: path - required: true - schema: {type: string} - get: - tags: [admin-statistics] - operationId: getCallAttempt - security: [{SipAdminBearer: []}] - responses: - '200': - description: One redacted attempt fact - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/audit: - get: - tags: [admin-audit] - operationId: listAudit - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/Limit'} - - {$ref: '#/components/parameters/ResourceFilter'} - - {$ref: '#/components/parameters/RequestFilter'} - - {$ref: '#/components/parameters/ActorFilter'} - responses: - '200': - description: Immutable audit entries - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/operations/{operation_id}: - parameters: - - name: operation_id - in: path - required: true - schema: {type: string} - get: - tags: [admin-audit] - operationId: getOperation - security: [{SipAdminBearer: []}] - responses: - '200': - description: Durable operation state for retry/recovery - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /readonly/v1/sip/trunks: - get: - tags: [saas-readonly] - operationId: listAuthorizedTrunks - security: [{SaasTrunkReadBearer: []}] - responses: - '200': - description: Published Trunks authorized for this SaaS principal - content: - application/json: - schema: - $ref: '#/components/schemas/ReadonlyTrunkList' - '401': {$ref: '#/components/responses/Unauthorized'} - /readonly/v1/sip/trunks/{trunk_id}: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [saas-readonly] - operationId: getAuthorizedTrunk - security: [{SaasTrunkReadBearer: []}] - responses: - '200': - description: Published, sanitized Trunk metadata - content: - application/json: - schema: {$ref: '#/components/schemas/ReadonlyTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} -components: - securitySchemes: - SipAdminBearer: - type: http - scheme: bearer - bearerFormat: opaque - description: >- - Dedicated operator/backend credential for SIP management writes. It is - not accepted by the SaaS read-only API or ordinary scheduling API. - SaasTrunkReadBearer: - type: http - scheme: bearer - bearerFormat: opaque - description: >- - Dedicated SaaS read-only credential. It cannot publish, modify, disable, - rollback, or access Cell management. - parameters: - ProviderId: - name: provider_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - TrunkId: - name: trunk_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - CellId: - name: cell_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - IfMatch: - name: If-Match - in: header - required: true - description: Exact latest revision required for CAS; quotes are accepted. - schema: {type: integer, minimum: 0} - CellIdsFilter: - name: cell_ids - in: query - required: false - schema: {type: string} - CellIdFilter: - name: cell_id - in: query - required: false - schema: {type: string} - ProviderFilter: - name: provider_id - in: query - required: false - schema: {type: string} - TrunkFilter: - name: trunk_id - in: query - required: false - schema: {type: string} - TrunkStatusFilter: - name: status - in: query - required: false - schema: {type: string} - ResourceFilter: - name: resource_id - in: query - required: false - schema: {type: string} - ActorFilter: - name: actor - in: query - required: false - schema: {type: string} - From: - name: from - in: query - required: false - schema: {type: string, format: date-time} - To: - name: to - in: query - required: false - schema: {type: string, format: date-time} - StatsMode: - name: mode - in: query - required: false - schema: {type: string, enum: [mock, mixed, real]} - EgressFilter: - name: egress_pool_id - in: query - required: false - schema: {type: string} - Granularity: - name: granularity - in: query - required: false - schema: {type: string, enum: [minute, hour, day]} - Limit: - name: limit - in: query - required: false - schema: {type: integer, minimum: 1, maximum: 200} - Cursor: - name: cursor - in: query - required: false - schema: {type: string} - RequestFilter: - name: request_id - in: query - required: false - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - responses: - BadRequest: - description: Invalid configuration or request - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Unauthorized: - description: Missing or wrong authentication domain - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Forbidden: - description: Credential lacks the required scope - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Conflict: - description: CAS conflict or no compatible Cell - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - NotFound: - description: Resource is not visible or does not exist - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - schemas: - Mode: - type: string - enum: [mock, real] - StatsMode: - type: string - enum: [mock, mixed, real] - Health: - type: object - additionalProperties: false - required: [status, mode] - properties: - status: {type: string, const: ok} - mode: {$ref: '#/components/schemas/Mode'} - CodecProfile: - type: object - additionalProperties: false - required: [allowed, preferred] - properties: - allowed: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - preferred: {type: string, enum: [PCMA, PCMU]} - SipConfig: - type: object - additionalProperties: false - required: [host, port, transport, auth_mode, register] - properties: - host: {type: string, minLength: 1, maxLength: 253} - port: {type: integer, minimum: 1, maximum: 65535} - transport: {type: string, enum: [udp, tcp, tls]} - auth_mode: {type: string, enum: [ip, digest]} - register: {type: boolean} - credential_ref: - type: string - writeOnly: true - description: >- - Secret-store reference only; plaintext credentials are forbidden. - VerificationRequest: - type: object - additionalProperties: false - required: [revision, check_name, result] - properties: - revision: {type: integer, minimum: 1} - check_name: - type: string - enum: - - transport - - registration_auth - - caller_id_rules - - codec - - capacity - - whitelist - result: - type: string - enum: [confirmed, failed, unknown, not_applicable] - evidence_ref: {type: string, maxLength: 512} - checked_by: {type: string, maxLength: 128} - TrunkConfig: - type: object - additionalProperties: false - required: - - provider_id - - display_name - - enabled - - sip - - codec_profile - - caller_ids - - dial_prefix - - egress_pool_id - - max_concurrency - - max_cps - properties: - provider_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - display_name: {type: string, minLength: 1, maxLength: 256} - enabled: {type: boolean} - sip: {$ref: '#/components/schemas/SipConfig'} - codec_profile: {$ref: '#/components/schemas/CodecProfile'} - caller_ids: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, minLength: 1, maxLength: 128} - dial_prefix: {type: string, maxLength: 32} - egress_pool_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - max_concurrency: {type: integer, minimum: 1} - max_cps: {type: integer, minimum: 1} - CellConfig: - type: object - additionalProperties: false - required: [egress_pool_id, codec_capabilities, status, max_concurrency] - properties: - egress_pool_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - codec_capabilities: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - status: {type: string, enum: [healthy, draining, disabled]} - max_concurrency: {type: integer, minimum: 1} - management_url: - type: string - format: uri - pattern: '^https://' - description: >- - mTLS Cell Agent endpoint. Required when mode=real; credentials and - query strings are not allowed. - RevisionInfo: - type: object - additionalProperties: false - required: [revision, state, created_at, created_by] - properties: - revision: {type: integer, minimum: 1} - state: {type: string, enum: [draft, publishing, published, superseded]} - config_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - created_at: {type: string, format: date-time} - created_by: {type: string} - AdminTrunk: - type: object - required: - - mode - - trunk_id - - provider_id - - latest_revision - - active_revision - - active_status - - status - - compatible_cell_ids - - latest - - active - - versions - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunk_id: {type: string} - provider_id: {type: string} - latest_revision: {type: integer, minimum: 1} - active_revision: {type: integer, minimum: 0} - active_status: {type: string, enum: [draft, published, disabled]} - status: {type: string, enum: [draft, published, disabled]} - updated_at: {type: string, format: date-time} - compatible_cell_ids: {type: array, items: {type: string}} - latest: {$ref: '#/components/schemas/TrunkView'} - active: {$ref: '#/components/schemas/TrunkView'} - versions: - type: array - items: - $ref: '#/components/schemas/RevisionInfo' - TrunkView: - allOf: - - {$ref: '#/components/schemas/TrunkConfig'} - - type: object - properties: - trunk_id: {type: string} - credential_configured: {type: boolean} - asterisk_allow: - type: array - items: {type: string, enum: [alaw, ulaw]} - config_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - ReadonlyTrunk: - type: object - required: - - mode - - trunk_id - - provider_id - - revision - - status - - config - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunk_id: {type: string} - provider_id: {type: string} - revision: {type: integer, minimum: 1} - status: {type: string, const: published} - updated_at: {type: string, format: date-time} - config: {$ref: '#/components/schemas/TrunkView'} - AdminTrunkList: - type: object - required: [mode, trunks] - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunks: {type: array, items: {$ref: '#/components/schemas/AdminTrunk'}} - ReadonlyTrunkList: - type: object - required: [mode, trunks] - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunks: - type: array - items: - $ref: '#/components/schemas/ReadonlyTrunk' - Cell: - type: object - required: [mode, cell_id, revision, config, updated_at, updated_by] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cell_id: {type: string} - revision: {type: integer, minimum: 1} - config: {$ref: '#/components/schemas/CellConfig'} - cloud_instance_id: {type: string} - instance_name: {type: string} - region: {type: string} - boot_id: {type: string} - updated_at: {type: string, format: date-time} - updated_by: {type: string} - Publication: - type: object - required: [trunk_id, revision, cell_id, status, updated_at] - properties: - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - cell_id: {type: string} - status: {type: string, enum: [pending, applied, failed]} - error_code: {type: [string, 'null']} - applied_at: {type: [string, 'null'], format: date-time} - target_digest: {type: string} - local_revision: {type: integer, minimum: 0} - local_digest: {type: string} - operation_id: {type: string} - updated_at: {type: string, format: date-time} - AuditEntry: - type: object - required: - - audit_id - - resource_type - - resource_id - - action - - revision - - actor - - details_json - - created_at - properties: - audit_id: {type: string} - resource_type: {type: string, const: trunk} - resource_id: {type: string} - action: - type: string - enum: - [ - upsert, - publish, - publish_failed, - disable, - disable_failed, - rollback, - rollback_failed, - ] - revision: {type: integer, minimum: 0} - actor: {type: string} - request_id: {type: [string, 'null']} - details_json: {type: string} - created_at: {type: string, format: date-time} - ProviderInput: - type: object - additionalProperties: false - required: [display_name, lifecycle] - properties: - display_name: {type: string, minLength: 1, maxLength: 256} - notes: {type: string, maxLength: 2000} - lifecycle: {type: string, enum: [active, archived]} - Provider: - allOf: - - {$ref: '#/components/schemas/ProviderInput'} - - type: object - required: [provider_id, revision, trunk_count, created_at, updated_at] - properties: - provider_id: {type: string} - revision: {type: integer, minimum: 1} - trunk_count: {type: integer, minimum: 0} - created_at: {type: string, format: date-time} - updated_at: {type: string, format: date-time} - updated_by: {type: string} - ProviderList: - type: object - required: [mode, providers] - properties: - mode: {$ref: '#/components/schemas/Mode'} - providers: {type: array, items: {$ref: '#/components/schemas/Provider'}} - ProviderResponse: - type: object - required: [mode, provider] - properties: - mode: {$ref: '#/components/schemas/Mode'} - provider: {$ref: '#/components/schemas/Provider'} - ObservationInput: - type: object - additionalProperties: false - required: [cell_id, boot_id, sequence, observed_at, source, states] - properties: - observation_id: {type: string} - cell_id: {type: string} - trunk_id: {type: string} - boot_id: {type: string, minLength: 1} - sequence: {type: integer, minimum: 1} - observed_at: {type: string, format: date-time} - source: {type: string} - config_revision: {type: integer, minimum: 0} - states: {type: object} - occupancy: {type: object} - sample_id: {type: string} - StatusItem: - type: object - required: [mode, cell_id, availability, complete, missing_sources] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cell_id: {type: string} - availability: {type: string, enum: [healthy, stale, unknown, disabled]} - complete: {type: boolean} - observed_at: {type: [string, 'null'], format: date-time} - received_at: {type: [string, 'null'], format: date-time} - observation_age_seconds: {type: [integer, 'null'], minimum: 0} - clock_skew: {type: boolean} - reason: {type: string} - boot_id: {type: string} - sequence: {type: integer, minimum: 1} - config_revision: {type: integer, minimum: 1} - config_status: {type: string} - egress_pool_id: {type: string} - eligibility: {type: string} - missing_sources: {type: array, items: {type: string}} - states: {type: object} - occupancy: {type: object} - trunks: {type: array, items: {type: object}} - publication: {type: object} - StatusResponse: - type: object - required: [mode, complete, cells] - properties: - mode: {$ref: '#/components/schemas/Mode'} - complete: {type: boolean} - generated_at: {type: string, format: date-time} - data_as_of: {type: [string, 'null'], format: date-time} - coverage: {type: object} - cells: {type: array, items: {$ref: '#/components/schemas/StatusItem'}} - StatisticsSummary: - type: object - required: [mode, from, to, complete, metrics] - properties: - mode: {$ref: '#/components/schemas/StatsMode'} - from: {type: string, format: date-time} - to: {type: string, format: date-time} - timezone: {type: string} - definition_version: {type: string} - filters: {type: object} - complete: {type: boolean} - missing_sources: {type: array, items: {type: string}} - unresolved_count: {type: integer, minimum: 0} - data_as_of: {type: [string, 'null'], format: date-time} - metrics: {type: object} - failure_reasons: {type: array, items: {type: object}} - realtime: {type: object} - TimeseriesResponse: - type: object - required: [mode, from, to, granularity, complete, series] - properties: - mode: {$ref: '#/components/schemas/StatsMode'} - from: {type: string, format: date-time} - to: {type: string, format: date-time} - timezone: {type: string} - definition_version: {type: string} - filters: {type: object} - granularity: {type: string, enum: [minute, hour, day]} - complete: {type: boolean} - series: {type: array, items: {type: object}} - ErrorResponse: - type: object - required: [error] - properties: - error: - type: object - required: [code, message] - properties: - code: {type: string} - message: {type: string} - fields: {type: object} - request_id: {type: string} diff --git a/contracts/archive/upstream/2026-09-18-p1-baseline/static-cell-artifact.schema.json b/contracts/archive/upstream/2026-09-18-p1-baseline/static-cell-artifact.schema.json deleted file mode 100644 index 5ab801f..0000000 --- a/contracts/archive/upstream/2026-09-18-p1-baseline/static-cell-artifact.schema.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/static-cell-artifact.schema.json", - "title": "Approved static Cell/SIP hand-off artifact", - "type": "object", - "additionalProperties": false, - "required": ["artifact_id", "source_release", "source_digest", "approval_reference", "cell_id", "revision", "config_sha256", "mode", "trunks"], - "properties": { - "artifact_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "source_release": {"type": "string", "minLength": 1, "maxLength": 128}, - "source_digest": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "approval_reference": {"type": "string", "minLength": 1, "maxLength": 256}, - "cell_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "revision": {"type": "integer", "minimum": 1}, - "config_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "mode": {"const": "mock"}, - "trunks": { - "type": "array", "minItems": 1, "maxItems": 32, - "items": { - "type": "object", "additionalProperties": false, - "required": ["trunk_id", "provider_id", "egress_pool_id", "codec", "caller_profile_ids", "dial_prefix", "enabled"], - "properties": { - "trunk_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "provider_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "egress_pool_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "codec": {"const": "PCMA"}, - "caller_profile_ids": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "minLength": 1, "maxLength": 128}}, - "dial_prefix": {"type": "string", "maxLength": 32}, - "enabled": {"type": "boolean"}, - "sip_endpoint_ref": {"type": "string", "maxLength": 128}, - "credential_ref": {"type": ["string", "null"], "maxLength": 128} - } - } - }, - "load_evidence": {"type": ["object", "null"], "additionalProperties": false, "properties": {"asterisk_config_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, "loaded_at": {"type": "string", "format": "date-time"}, "status": {"const": "not-yet-loaded"}}} - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/README.md b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/README.md deleted file mode 100644 index 3810491..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/README.md +++ /dev/null @@ -1,31 +0,0 @@ -# 2026-09-19 P1 project-owned v1 contract bundle - -This is the first project-owned W01 contract release authorized for the current -single-node production-closure iteration. It is self-contained and embedded by -`contracts/contracts.go`; runtime code never reads the parent worktree or an -external URL. - -## Scope - -- strict envelope and eight event payload schemas; -- immutable `full_ai` and `asr_only` AI branches; -- Dispatcher-to-Agent AI authorization, tenant binding and digest checks; -- real/mixed/mock static Cell artifact modes; -- single-node ARI, `slin16` ExternalMedia and WAV recording hand-off fields; -- Agent-direct OSS upload request/grant/complete/verified metadata; and -- first-version examples and negative fixtures for local and single-node - production closure. - -This bundle is **project-owned v1**, not a claim that an external SaaS contract -has been published. It is the implementation contract for this iteration and -must be promoted or superseded by an explicitly versioned external release -before any cross-project integration is declared compatible. - -The current release deliberately defers a second Cell. It permits one active -Dispatcher, one Agent, one Asterisk Cell and one approved real-mode artifact; -capacity, N+1, multi-Cell fairness and automatic failover remain separate -acceptance items. - -`release-manifest.json`, `SNAPSHOT.json`, and the parent `manifest.txt` record -source ancestry and SHA-256 hashes. Credentials are referenced by bounded names -only; no provider secret is embedded in this bundle. diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/SNAPSHOT.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/SNAPSHOT.json deleted file mode 100644 index 9eadf95..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/SNAPSHOT.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "release_version": "2026-09-19-p1-v1", - "release_kind": "project-owned-first-production-closure-v1", - "contract_status": "project-owned-v1-authorized-not-external-authoritative", - "source_bundle": "2026-09-18-p1-baseline", - "source_repository": "git.ipao.vip/rogee/ai-call", - "source_snapshot": "2026-09-17", - "source_head": "fa6925010ba47976d2e99893eac92140b3cb0d09", - "source_worktree": "project-authored-v1", - "runtime_dependency": "none (bundle is embedded; parent paths are never read at runtime)", - "amendments": [ - "project-owned first-version contract for the single-node production-closure iteration", - "static-cell-artifact.schema.json adds mock/mixed/real modes plus ARI, slin16 ExternalMedia and recording fields", - "real-mode artifact validation is allowed for one active Cell; second-Cell/N+1 remains out of scope", - "credentials remain bounded references and are never embedded in the contract bundle" - ] -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-authorization.schema.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-authorization.schema.json deleted file mode 100644 index ef7ee1c..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-authorization.schema.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/ai-authorization.schema.json", - "title": "Dispatcher to Agent immutable AI authorization", - "type": "object", - "additionalProperties": false, - "required": ["authorization_id", "tenant_id", "tenant_key", "agent_version_id", "config_sha256", "mode", "issued_at", "expires_at", "source", "revoked"], - "properties": { - "authorization_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "tenant_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "tenant_key": {"type": "string", "minLength": 1, "maxLength": 224}, - "agent_version_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "config_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "mode": {"enum": ["full_ai", "asr_only"]}, - "issued_at": {"type": "string", "format": "date-time"}, - "expires_at": {"type": "string", "format": "date-time"}, - "source": {"enum": ["saas", "mock-saas"]}, - "credential_refs": { - "type": "object", - "additionalProperties": false, - "properties": { - "asr": {"type": "string", "minLength": 1, "maxLength": 128}, - "llm": {"type": "string", "minLength": 1, "maxLength": 128}, - "tts": {"type": "string", "minLength": 1, "maxLength": 128} - } - }, - "allowed_egress_pool_ids": { - "type": "array", "minItems": 1, "uniqueItems": true, - "items": {"type": "string", "minLength": 1, "maxLength": 128} - }, - "revoked": {"type": "boolean"}, - "revocation_reason": {"type": "string", "maxLength": 256} - }, - "allOf": [ - { - "if": {"properties": {"revoked": {"const": true}}}, - "then": {"required": ["revocation_reason"]} - } - ] -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-config.openapi.yaml b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-config.openapi.yaml deleted file mode 100644 index e310606..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-config.openapi.yaml +++ /dev/null @@ -1,145 +0,0 @@ -openapi: 3.1.0 -info: - title: agent-call immutable AI configuration API - version: 1.0.0 - description: >- - Internal configuration publication/read surface. The call.execute business - command remains RabbitMQ-only; secrets, URLs, and provider credentials are - resolved by the execution environment and never enter MQ messages. -servers: - - url: / -paths: - /internal/v1/ai/agent-versions: - post: - operationId: publishAgentVersion - security: - - aiConfigPublish: [] - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionPublishRequest' - responses: - '200': - description: Identical immutable content already exists - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionReceipt' - '201': - description: Immutable version published - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionReceipt' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '409': - description: Existing version has different content - /internal/v1/ai/agent-versions/{agent_version_id}: - get: - operationId: getAgentVersion - security: - - aiConfigRead: [] - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - name: agent_version_id - in: path - required: true - schema: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$' - responses: - '200': - description: Trusted immutable snapshot - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersion' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '404': - description: Agent version not found -components: - parameters: - TenantId: - name: X-Tenant-Id - in: header - required: true - schema: {type: string, minLength: 1} - RequestId: - name: X-Request-Id - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - securitySchemes: - aiConfigPublish: - type: http - scheme: bearer - bearerFormat: JWT - description: >- - Requires scope ai.config.publish and the AI-config issuer/audience. - aiConfigRead: - type: http - scheme: bearer - bearerFormat: JWT - description: >- - Requires scope ai.config.read and the AI-config issuer/audience. - schemas: - AgentVersionPublishRequest: - type: object - additionalProperties: false - required: [agent_version_id, config] - properties: - agent_version_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$' - config: - $ref: 'ai-config.schema.json' - AgentVersionReceipt: - type: object - required: [tenant_id, agent_version_id, status, immutable, content_sha256] - properties: - tenant_id: {type: string} - agent_version_id: {type: string} - status: {enum: [published, reused]} - immutable: {const: true} - content_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - AgentVersion: - allOf: - - $ref: '#/components/schemas/AgentVersionReceipt' - - type: object - required: [config] - properties: - config: - $ref: 'ai-config.schema.json' - created_at: {type: string, format: date-time} - published_at: {type: string, format: date-time} - created_by: {type: string} - Error: - type: object - required: [error] - properties: - error: {type: string} - message: {type: string} - responses: - BadRequest: - description: Invalid configuration - content: - application/json: - schema: {$ref: '#/components/schemas/Error'} - Unauthorized: - description: Missing or invalid AI-config token - Forbidden: - description: Token lacks the AI-config permission diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-config.schema.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-config.schema.json deleted file mode 100644 index cf06b62..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/ai-config.schema.json +++ /dev/null @@ -1,122 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/ai-config.schema.json", - "title": "Immutable AI agent version", - "type": "object", - "additionalProperties": false, - "required": ["agent_version_id", "immutable", "asr", "conversation"], - "properties": { - "agent_version_id": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"}, - "immutable": {"const": true}, - "mode": {"enum": ["full_ai", "asr_only"]}, - "llm": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "model"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "temperature": {"type": "number", "minimum": 0, "maximum": 2}, - "max_tokens": {"type": "integer", "minimum": 1}, - "timeout_ms": {"type": "integer", "minimum": 1} - } - }, - "prompt": { - "type": "object", - "additionalProperties": false, - "required": ["text", "allowed_variables"], - "properties": { - "text": {"type": "string", "minLength": 1, "maxLength": 32768}, - "allowed_variables": { - "type": "array", - "maxItems": 32, - "items": {"type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"} - }, - "max_bytes": {"type": "integer", "minimum": 1, "maximum": 32768} - } - }, - "tts": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "model", "voice", "format"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "voice": {"type": "string", "minLength": 1, "maxLength": 128}, - "speed": {"type": "number", "minimum": 0.25, "maximum": 3}, - "timeout_ms": {"type": "integer", "minimum": 1}, - "format": { - "type": "object", - "additionalProperties": false, - "required": ["encoding", "sample_rate_hz", "channels"], - "properties": { - "encoding": {"enum": ["pcm_s16le", "pcma"]}, - "sample_rate_hz": {"type": "integer", "minimum": 8000, "maximum": 48000}, - "channels": {"const": 1} - } - } - } - }, - "asr": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "language", "input"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "language": {"type": "string", "minLength": 1, "maxLength": 32}, - "interim": {"type": "boolean"}, - "timeout_ms": {"type": "integer", "minimum": 1}, - "input": { - "type": "object", - "additionalProperties": false, - "required": ["encoding", "sample_rate_hz", "channels", "sample_width_bytes"], - "properties": { - "encoding": {"const": "pcm_s16le"}, - "sample_rate_hz": {"type": "integer", "minimum": 8000, "maximum": 48000}, - "channels": {"const": 1}, - "sample_width_bytes": {"const": 2} - } - } - } - }, - "conversation": { - "type": "object", - "additionalProperties": false, - "required": ["allow_interrupt", "silence_timeout_ms", "max_duration_ms", "max_turns", "sentence_max_chars", "max_pending_audio_chunks"], - "properties": { - "opening": {"type": "string", "maxLength": 32768}, - "allow_interrupt": {"type": "boolean"}, - "silence_timeout_ms": {"type": "integer", "minimum": 1}, - "max_duration_ms": {"type": "integer", "minimum": 1, "maximum": 3600000}, - "max_turns": {"type": "integer", "minimum": 1, "maximum": 1000}, - "sentence_max_chars": {"type": "integer", "minimum": 1}, - "max_pending_audio_chunks": {"type": "integer", "minimum": 1} - } - }, - "metadata": {"type": "object", "additionalProperties": true} - }, - "oneOf": [ - { - "title": "Full AI", - "required": ["llm", "prompt", "tts"], - "properties": { - "mode": {"enum": ["full_ai"]}, - "conversation": {"required": ["opening"]} - } - }, - { - "title": "ASR only", - "required": ["mode"], - "properties": {"mode": {"const": "asr_only"}}, - "not": {"anyOf": [ - {"required": ["llm"]}, - {"required": ["prompt"]}, - {"required": ["tts"]} - ]} - } - ] -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/cell-agent.openapi.yaml b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/cell-agent.openapi.yaml deleted file mode 100644 index f37e4c0..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/cell-agent.openapi.yaml +++ /dev/null @@ -1,232 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Cell Agent API - version: 1.0.0 - description: >- - Restricted mTLS API used by the SIP management backend to deliver a - versioned Trunk snapshot to one voice Cell. The Cell validates the SHA-256 - snapshot, applies it with an atomic file replacement, reloads Asterisk, - restores the previous file on reload failure, and returns applied only - after the reload succeeds. A disabled snapshot removes the Cell-local - Trunk fragment and reloads Asterisk. -servers: - - url: https://cell.internal:9443 - description: Cell management network only -tags: - - name: health - - name: trunk-apply -paths: - /healthz/live: - get: - tags: [health] - operationId: live - responses: - '200': - description: Cell Agent is alive - content: - application/json: - schema: {$ref: '#/components/schemas/Health'} - /v1/sip/trunks/{trunk_id}/apply: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [trunk-apply] - operationId: applyTrunk - security: [{CellManagementMtls: []}] - parameters: - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/Publication'} - responses: - '200': - description: Asterisk has loaded the exact snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Acknowledgement'} - '400': {$ref: '#/components/responses/BadRequest'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': - description: >- - Revision or expected local snapshot is stale; the Cell never - guesses over an unknown baseline - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - '502': - description: Asterisk rejected the apply or reload - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - /v1/sip/trunks/{trunk_id}/state: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [trunk-apply] - operationId: getTrunkState - security: [{CellManagementMtls: []}] - responses: - '200': - description: Durable Cell apply state - content: - application/json: - schema: {$ref: '#/components/schemas/State'} - '404': {$ref: '#/components/responses/NotFound'} -components: - securitySchemes: - CellManagementMtls: - type: mutualTLS - description: Management backend client certificate signed by the Cell CA. - parameters: - TrunkId: - name: trunk_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - schemas: - Health: - type: object - additionalProperties: false - required: [status, mode, cell_id] - properties: - status: {type: string, const: ok} - mode: {type: string, const: real} - cell_id: {type: string} - CodecProfile: - type: object - additionalProperties: false - required: [allowed, preferred] - properties: - allowed: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - preferred: {type: string, enum: [PCMA, PCMU]} - SipConfig: - type: object - additionalProperties: false - required: [host, port, transport, auth_mode, register, credential_ref] - properties: - host: {type: string, minLength: 1, maxLength: 253} - port: {type: integer, minimum: 1, maximum: 65535} - transport: {type: string, enum: [udp, tcp, tls]} - auth_mode: {type: string, enum: [ip, digest]} - register: {type: boolean} - credential_ref: - type: [string, 'null'] - description: Secret-store reference only; plaintext is forbidden. - TrunkConfig: - type: object - additionalProperties: false - required: - - provider_id - - display_name - - enabled - - sip - - codec_profile - - caller_ids - - dial_prefix - - egress_pool_id - - max_concurrency - - max_cps - properties: - provider_id: {type: string} - display_name: {type: string, minLength: 1, maxLength: 256} - enabled: {type: boolean} - sip: {$ref: '#/components/schemas/SipConfig'} - codec_profile: {$ref: '#/components/schemas/CodecProfile'} - caller_ids: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, minLength: 1, maxLength: 128} - dial_prefix: {type: string, maxLength: 32} - egress_pool_id: {type: string} - max_concurrency: {type: integer, minimum: 1} - max_cps: {type: integer, minimum: 1} - Publication: - type: object - additionalProperties: false - required: - [mode, cell_id, trunk_id, revision, expected_local_revision, config, - config_sha256] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - expected_local_revision: {type: integer, minimum: 0} - config: {$ref: '#/components/schemas/TrunkConfig'} - config_sha256: - type: string - pattern: '^[0-9a-f]{64}$' - Acknowledgement: - type: object - additionalProperties: false - required: - [mode, cell_id, trunk_id, revision, config_sha256, status, idempotent] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - config_sha256: {type: string, pattern: '^[0-9a-f]{64}$'} - status: {type: string, const: applied} - idempotent: {type: boolean} - State: - type: object - additionalProperties: false - required: - [ - mode, - cell_id, - trunk_id, - desired_revision, - applied_revision, - status, - updated_at, - ] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - desired_revision: {type: integer, minimum: 1} - applied_revision: {type: integer, minimum: 0} - status: {type: string, enum: [applying, applied, failed]} - last_error: {type: [string, 'null']} - updated_at: {type: string, format: date-time} - ErrorResponse: - type: object - required: [error] - properties: - error: - type: object - required: [code, message] - properties: - code: {type: string} - message: {type: string} - responses: - BadRequest: - description: Invalid publication or hash - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Forbidden: - description: Certificate or Cell identity is not authorized - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - NotFound: - description: State does not exist - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/event-payloads.schema.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/event-payloads.schema.json deleted file mode 100644 index db4cecc..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/event-payloads.schema.json +++ /dev/null @@ -1,170 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/event-payloads.schema.json", - "title": "Agent-call versioned event envelopes and payloads", - "type": "object", - "additionalProperties": false, - "required": ["schema_version", "event_id", "event_type", "tenant_id", "tenant_key", "trace_id", "occurred_at", "aggregate_type", "aggregate_id", "aggregate_version", "payload"], - "properties": { - "schema_version": {"const": "1.0"}, - "event_id": {"$ref": "#/$defs/id"}, - "event_type": {"type": "string"}, - "tenant_id": {"$ref": "#/$defs/id"}, - "tenant_key": {"type": "string", "minLength": 1, "maxLength": 224}, - "trace_id": {"$ref": "#/$defs/id"}, - "occurred_at": {"type": "string", "format": "date-time"}, - "aggregate_type": {"type": "string", "minLength": 1, "maxLength": 64}, - "aggregate_id": {"$ref": "#/$defs/id"}, - "aggregate_version": {"type": "integer", "minimum": 1}, - "payload": {"type": "object"} - }, - "oneOf": [ - {"properties": {"event_type": {"const": "command.result"}, "payload": {"$ref": "#/$defs/command_result"}}}, - {"properties": {"event_type": {"const": "call.status"}, "payload": {"$ref": "#/$defs/call_status"}}}, - {"properties": {"event_type": {"const": "transcript.updated"}, "payload": {"$ref": "#/$defs/transcript_updated"}}}, - {"properties": {"event_type": {"const": "call.finished"}, "payload": {"$ref": "#/$defs/call_finished"}}}, - {"properties": {"event_type": {"const": "recording.ready"}, "payload": {"$ref": "#/$defs/recording_ready"}}}, - {"properties": {"event_type": {"const": "recording.failed"}, "payload": {"$ref": "#/$defs/recording_failed"}}}, - {"properties": {"event_type": {"const": "transcript.failed"}, "payload": {"$ref": "#/$defs/transcript_failed"}}}, - {"properties": {"event_type": {"const": "contact.opt_out"}, "payload": {"$ref": "#/$defs/contact_opt_out"}}} - ], - "$defs": { - "id": {"type": "string", "minLength": 1, "maxLength": 128}, - "command_result": { - "type": "object", "additionalProperties": false, - "required": ["command_id", "command_type", "status", "reason_code"], - "properties": { - "command_id": {"$ref": "#/$defs/id"}, - "command_type": {"enum": ["call.execute", "task.control"]}, - "status": {"enum": ["accepted", "waiting", "applied", "rejected", "failed", "unknown"]}, - "reason_code": {"type": "string", "minLength": 1, "maxLength": 128}, - "task_id": {"$ref": "#/$defs/id"}, - "task_item_id": {"$ref": "#/$defs/id"}, - "execution_id": {"$ref": "#/$defs/id"}, - "call_id": {"$ref": "#/$defs/id"}, - "requested_task_revision": {"type": "integer", "minimum": 0}, - "applied_task_revision": {"type": "integer", "minimum": 0}, - "admission_state": {"enum": ["open", "closed", "draining", "quarantined", "unknown"]}, - "resource_reservation_id": {"$ref": "#/$defs/id"}, - "permit_id": {"$ref": "#/$defs/id"} - } - }, - "call_status": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "execution_id", "call_state", "call_version", "attempt_id", "attempt_state"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "execution_id": {"$ref": "#/$defs/id"}, - "task_id": {"$ref": "#/$defs/id"}, - "task_item_id": {"$ref": "#/$defs/id"}, - "call_state": {"enum": ["queued", "dialing", "ringing", "answered", "ended"]}, - "call_version": {"type": "integer", "minimum": 1}, - "attempt_id": {"$ref": "#/$defs/id"}, - "attempt_state": {"enum": ["pending", "active", "ended", "unknown"]}, - "route_policy_id": {"$ref": "#/$defs/id"}, - "caller_profile_id": {"$ref": "#/$defs/id"}, - "trunk_id": {"$ref": "#/$defs/id"}, - "cell_id": {"$ref": "#/$defs/id"}, - "egress_pool_id": {"$ref": "#/$defs/id"}, - "observed_at": {"type": "string", "format": "date-time"}, - "reason_code": {"type": "string", "maxLength": 128} - } - }, - "transcript_updated": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "turn_id", "segment_id", "role", "revision", "text", "is_final", "start_ms", "end_ms", "playback_state"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "execution_id": {"$ref": "#/$defs/id"}, - "turn_id": {"$ref": "#/$defs/id"}, - "segment_id": {"$ref": "#/$defs/id"}, - "role": {"enum": ["customer", "agent", "system"]}, - "revision": {"type": "integer", "minimum": 1}, - "text": {"type": "string", "maxLength": 32768}, - "is_final": {"type": "boolean"}, - "start_ms": {"type": "integer", "minimum": 0}, - "end_ms": {"type": "integer", "minimum": 0}, - "playback_state": {"enum": ["not_applicable", "generated", "sent", "playback_confirmed", "cancelled", "unknown"]} - } - }, - "call_finished": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "execution_id", "call_version", "outcome", "started_at", "ended_at", "duration_ms", "reason_code"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "execution_id": {"$ref": "#/$defs/id"}, - "task_id": {"$ref": "#/$defs/id"}, - "task_item_id": {"$ref": "#/$defs/id"}, - "call_version": {"type": "integer", "minimum": 1}, - "outcome": {"enum": ["answered", "no_answer", "busy", "failed", "opt_out", "cancelled", "unknown"]}, - "started_at": {"type": "string", "format": "date-time"}, - "ended_at": {"type": "string", "format": "date-time"}, - "duration_ms": {"type": "integer", "minimum": 0}, - "reason_code": {"type": "string", "minLength": 1, "maxLength": 128}, - "attempt_summary": {"type": "array", "maxItems": 32, "items": {"$ref": "#/$defs/attempt_summary"}}, - "asset_state": {"enum": ["pending", "complete", "failed", "unknown"]} - } - }, - "attempt_summary": { - "type": "object", "additionalProperties": false, - "required": ["attempt_id", "state"], - "properties": { - "attempt_id": {"$ref": "#/$defs/id"}, - "state": {"enum": ["pending", "active", "ended", "unknown"]}, - "trunk_id": {"$ref": "#/$defs/id"}, - "cell_id": {"$ref": "#/$defs/id"}, - "reason_code": {"type": "string", "maxLength": 128} - } - }, - "recording_ready": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "recording_id", "oss_id", "format", "channels", "sample_rate_hz", "duration_ms", "size_bytes", "checksum_sha256"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "recording_id": {"$ref": "#/$defs/id"}, - "oss_id": {"$ref": "#/$defs/id"}, - "format": {"enum": ["wav", "raw_pcm", "pcma"]}, - "channels": {"const": 1}, - "sample_rate_hz": {"type": "integer", "minimum": 8000, "maximum": 48000}, - "duration_ms": {"type": "integer", "minimum": 0}, - "size_bytes": {"type": "integer", "minimum": 1}, - "checksum_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"} - } - }, - "recording_failed": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "recording_id", "stage", "reason_code", "retryable"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "recording_id": {"$ref": "#/$defs/id"}, - "stage": {"enum": ["seal", "request", "upload", "complete", "verify", "cleanup"]}, - "reason_code": {"type": "string", "minLength": 1, "maxLength": 128}, - "retryable": {"type": "boolean"}, - "next_retry_at": {"type": "string", "format": "date-time"} - } - }, - "transcript_failed": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "reason_code", "retryable"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "reason_code": {"type": "string", "minLength": 1, "maxLength": 128}, - "retryable": {"type": "boolean"}, - "segment_id": {"$ref": "#/$defs/id"}, - "affected_segments": {"type": "array", "maxItems": 256, "items": {"$ref": "#/$defs/id"}} - } - }, - "contact_opt_out": { - "type": "object", "additionalProperties": false, - "required": ["call_id", "task_id", "task_item_id", "requested_at"], - "properties": { - "call_id": {"$ref": "#/$defs/id"}, - "task_id": {"$ref": "#/$defs/id"}, - "task_item_id": {"$ref": "#/$defs/id"}, - "requested_at": {"type": "string", "format": "date-time"}, - "turn_id": {"$ref": "#/$defs/id"}, - "segment_id": {"$ref": "#/$defs/id"} - } - } - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/README.md b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/README.md deleted file mode 100644 index ed9b3ae..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Contract fixtures - -`call.execute.json` is the canonical valid command fixture. Runtime tests generate the remaining event fixtures from persisted facts so replay assertions compare original bytes and IDs rather than synthesized history. Invalid cases include unknown schema versions, missing required fields, cross-tenant bindings, conflicting idempotency bodies, and tenant routing keys over 224 UTF-8 bytes. - -The bundle contains legacy full-AI, explicit full-AI, ASR-only, event-positive, and event-negative fixtures. All fixtures are synthetic. The profile is `mock`; it is never a production provider configuration. `transcript.updated` is the only valid transcript event name; `call.transcript` is intentionally invalid. diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-asr-only.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-asr-only.json deleted file mode 100644 index 7ecf915..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-asr-only.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "agent_version_id": "agent_asr_v1", - "immutable": true, - "mode": "asr_only", - "asr": { - "provider_ref": "mock", - "model": "mock-asr-v1", - "language": "zh-CN", - "input": {"encoding": "pcm_s16le", "sample_rate_hz": 16000, "channels": 1, "sample_width_bytes": 2}, - "interim": true, - "timeout_ms": 5000 - }, - "conversation": { - "allow_interrupt": false, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-full-explicit.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-full-explicit.json deleted file mode 100644 index 8e0bc7f..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-full-explicit.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "agent_version_id": "agent_full_v1", - "immutable": true, - "mode": "full_ai", - "llm": { - "provider_ref": "mock", - "model": "mock-chat-v1", - "temperature": 0.2, - "max_tokens": 256, - "timeout_ms": 5000 - }, - "prompt": { - "text": "You are a concise telephone assistant. Answer the caller's last statement.", - "allowed_variables": [], - "max_bytes": 32768 - }, - "tts": { - "provider_ref": "mock", - "model": "mock-tts-v1", - "voice": "mock-neutral", - "speed": 1.0, - "format": {"encoding": "pcm_s16le", "sample_rate_hz": 16000, "channels": 1}, - "timeout_ms": 5000 - }, - "asr": { - "provider_ref": "mock", - "language": "zh-CN", - "input": {"encoding": "pcm_s16le", "sample_rate_hz": 16000, "channels": 1, "sample_width_bytes": 2}, - "interim": true, - "timeout_ms": 5000 - }, - "conversation": { - "opening": "", - "allow_interrupt": true, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-full-production-v1.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-full-production-v1.json deleted file mode 100644 index 0a83a96..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version-full-production-v1.json +++ /dev/null @@ -1,54 +0,0 @@ -{ - "agent_version_id": "agent_full_v1", - "immutable": true, - "mode": "full_ai", - "llm": { - "provider_ref": "bailian-openai-compatible", - "model": "qwen-plus", - "temperature": 0.2, - "max_tokens": 256, - "timeout_ms": 5000, - "credential_ref": "bailian-default" - }, - "prompt": { - "text": "You are a concise telephone assistant. Answer the caller's last statement.", - "allowed_variables": [], - "max_bytes": 32768 - }, - "tts": { - "provider_ref": "bailian-openai-compatible", - "model": "qwen3-tts-flash", - "voice": "Cherry", - "speed": 1.0, - "format": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1 - }, - "timeout_ms": 5000, - "credential_ref": "bailian-default" - }, - "asr": { - "provider_ref": "volcengine", - "language": "zh-CN", - "input": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1, - "sample_width_bytes": 2 - }, - "interim": true, - "timeout_ms": 5000, - "credential_ref": "volcengine-default", - "model": "volc.bigasr.sauc.duration" - }, - "conversation": { - "opening": "", - "allow_interrupt": true, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version.json deleted file mode 100644 index 61851cd..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/agent-version.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "agent_version_id": "agent_v1", - "immutable": true, - "llm": { - "provider_ref": "mock", - "model": "mock-chat-v1", - "temperature": 0.2, - "max_tokens": 256, - "timeout_ms": 5000 - }, - "prompt": { - "text": "You are a concise telephone assistant. Answer the caller's last statement.", - "allowed_variables": [], - "max_bytes": 32768 - }, - "tts": { - "provider_ref": "mock", - "model": "mock-tts-v1", - "voice": "mock-neutral", - "speed": 1.0, - "format": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1 - }, - "timeout_ms": 5000 - }, - "asr": { - "provider_ref": "mock", - "language": "zh-CN", - "input": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1, - "sample_width_bytes": 2 - }, - "interim": true, - "timeout_ms": 5000 - }, - "conversation": { - "opening": "", - "allow_interrupt": true, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/ai-authorization.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/ai-authorization.json deleted file mode 100644 index 1110b59..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/ai-authorization.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "authorization_id": "auth-1", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "agent_version_id": "agent_asr_v1", - "config_sha256": "24864df1fd72a59efaaaf6d1fc81a0c7db01fbdfcd821aab4069b64a8db9b60b", - "mode": "asr_only", - "issued_at": "2026-09-18T00:00:00Z", - "expires_at": "2026-09-18T00:01:00Z", - "source": "mock-saas", - "credential_refs": {"asr": "mock-asr-credential"}, - "allowed_egress_pool_ids": ["egress-mock"], - "revoked": false -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/call.execute.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/call.execute.json deleted file mode 100644 index 23f9fdc..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/call.execute.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "schema_version": "1.0", - "command_type": "call.execute", - "command_id": "cmd_demo_001", - "tenant_id": "tenant-demo", - "tenant_key": "tenant-demo-key", - "trace_id": "trace_demo_001", - "issued_at": "2026-09-11T08:00:00Z", - "not_after": "2099-09-11T08:05:00Z", - "payload": { - "execution_id": "exec_demo_001", - "task_id": "task-demo", - "task_item_id": "item_demo", - "task_revision": 1, - "callee": "18601013734", - "route_policy_id": "route_policy_test", - "caller_profile_id": "caller_profile_test", - "agent_version_id": "agent_v1", - "variables": {}, - "ring_timeout_ms": 30000, - "max_call_duration_ms": 180000 - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-call-finished.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-call-finished.json deleted file mode 100644 index 1ba64ae..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-call-finished.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-finished-1", - "event_type": "call.finished", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:03Z", - "aggregate_type": "call", - "aggregate_id": "call-1", - "aggregate_version": 2, - "payload": { - "call_id": "call-1", - "execution_id": "execution-1", - "task_id": "task-1", - "task_item_id": "item-1", - "call_version": 1, - "outcome": "answered", - "started_at": "2026-09-18T00:00:00Z", - "ended_at": "2026-09-18T00:00:03Z", - "duration_ms": 3000, - "reason_code": "normal_clearing", - "asset_state": "complete", - "attempt_summary": [{"attempt_id": "attempt-1", "state": "ended", "trunk_id": "trunk-1", "cell_id": "cell-1"}] - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-call-status.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-call-status.json deleted file mode 100644 index 8fc59ac..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-call-status.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-status-1", - "event_type": "call.status", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:01Z", - "aggregate_type": "call", - "aggregate_id": "call-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "execution_id": "execution-1", - "task_id": "task-1", - "task_item_id": "item-1", - "call_state": "answered", - "call_version": 1, - "attempt_id": "attempt-1", - "attempt_state": "active", - "route_policy_id": "route-1", - "caller_profile_id": "caller-1", - "trunk_id": "trunk-1", - "cell_id": "cell-1", - "egress_pool_id": "egress-1", - "observed_at": "2026-09-18T00:00:01Z" - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-command-result.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-command-result.json deleted file mode 100644 index 84daa6e..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-command-result.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-command-result-1", - "event_type": "command.result", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:00Z", - "aggregate_type": "command", - "aggregate_id": "command-1", - "aggregate_version": 1, - "payload": { - "command_id": "command-1", - "command_type": "call.execute", - "status": "accepted", - "reason_code": "accepted", - "execution_id": "execution-1" - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-contact-opt-out.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-contact-opt-out.json deleted file mode 100644 index 1f59c2a..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-contact-opt-out.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-opt-out-1", - "event_type": "contact.opt_out", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:06Z", - "aggregate_type": "contact", - "aggregate_id": "contact-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "task_id": "task-1", - "task_item_id": "item-1", - "requested_at": "2026-09-18T00:00:06Z", - "turn_id": "turn-1", - "segment_id": "segment-1" - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-recording-failed.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-recording-failed.json deleted file mode 100644 index af03187..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-recording-failed.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-recording-failed-1", - "event_type": "recording.failed", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:04Z", - "aggregate_type": "recording", - "aggregate_id": "recording-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "recording_id": "recording-1", - "stage": "upload", - "reason_code": "temporary_oss_unavailable", - "retryable": true, - "next_retry_at": "2026-09-18T00:01:00Z" - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-recording-ready.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-recording-ready.json deleted file mode 100644 index c0ad88f..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-recording-ready.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-recording-1", - "event_type": "recording.ready", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:02Z", - "aggregate_type": "recording", - "aggregate_id": "recording-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "recording_id": "recording-1", - "oss_id": "oss://bucket/object-1", - "format": "wav", - "channels": 1, - "sample_rate_hz": 16000, - "duration_ms": 1000, - "size_bytes": 32000, - "checksum_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-transcript-failed.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-transcript-failed.json deleted file mode 100644 index 8109d97..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-transcript-failed.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-transcript-failed-1", - "event_type": "transcript.failed", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:05Z", - "aggregate_type": "transcript", - "aggregate_id": "call-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "reason_code": "asr_timeout", - "retryable": false, - "segment_id": "segment-1", - "affected_segments": ["segment-1"] - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-transcript-updated.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-transcript-updated.json deleted file mode 100644 index 46d7796..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/event-transcript-updated.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-transcript-1", - "event_type": "transcript.updated", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:01Z", - "aggregate_type": "transcript_segment", - "aggregate_id": "segment-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-1", - "turn_id": "turn-1", - "segment_id": "segment-1", - "role": "customer", - "revision": 1, - "text": "您好", - "is_final": true, - "start_ms": 0, - "end_ms": 600, - "playback_state": "not_applicable" - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-ai-authorization-revoked.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-ai-authorization-revoked.json deleted file mode 100644 index 48a591b..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-ai-authorization-revoked.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "authorization_id": "auth-invalid", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "agent_version_id": "agent_asr_v1", - "config_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "mode": "asr_only", - "issued_at": "2026-09-18T00:00:00Z", - "expires_at": "2026-09-18T00:01:00Z", - "source": "mock-saas", - "revoked": true -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-asr-only-with-llm.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-asr-only-with-llm.json deleted file mode 100644 index c09e0f2..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-asr-only-with-llm.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "agent_version_id": "agent_invalid", - "immutable": true, - "mode": "asr_only", - "llm": {"provider_ref": "mock", "model": "must-not-be-present"}, - "asr": { - "provider_ref": "mock", - "language": "zh-CN", - "input": {"encoding": "pcm_s16le", "sample_rate_hz": 16000, "channels": 1, "sample_width_bytes": 2} - }, - "conversation": { - "allow_interrupt": false, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-event-unknown-type.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-event-unknown-type.json deleted file mode 100644 index 25476b8..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-event-unknown-type.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "schema_version": "1.0", - "event_id": "event-invalid-1", - "event_type": "call.transcript", - "tenant_id": "tenant-1", - "tenant_key": "tenant-demo-key", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:00Z", - "aggregate_type": "call", - "aggregate_id": "call-1", - "aggregate_version": 1, - "payload": {"text": "invalid alias"} -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-oss-upload-http.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-oss-upload-http.json deleted file mode 100644 index 42033e6..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/invalid-oss-upload-http.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "kind": "grant", - "upload_id": "upload-invalid", - "recording_id": "recording-1", - "upload_url": "http://oss.example.invalid/upload/upload-invalid", - "required_headers": {}, - "expires_at": "2026-09-18T00:05:00Z", - "max_bytes": 16777216, - "object_binding": "recording-1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/oss-upload-grant.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/oss-upload-grant.json deleted file mode 100644 index 6b4ddb3..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/oss-upload-grant.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "kind": "grant", - "upload_id": "upload-1", - "recording_id": "recording-1", - "upload_url": "https://oss.example.invalid/upload/upload-1", - "required_headers": {"x-checksum-sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, - "expires_at": "2026-09-18T00:05:00Z", - "max_bytes": 16777216, - "object_binding": "recording-1:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/static-cell-artifact-real-v1.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/static-cell-artifact-real-v1.json deleted file mode 100644 index 6e2c7bb..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/static-cell-artifact-real-v1.json +++ /dev/null @@ -1,95 +0,0 @@ -{ - "artifact_id": "cell-single-real-v1", - "source_release": "asterisk-22.10.1-native-v1", - "source_digest": "68006a1a8efed288be4ca4a2ae3cb9554a31d733eac08eaacf4c646c95faf74d", - "approval_reference": "project-auto-approved:2026-09-19:single-node-v1", - "cell_id": "cell-single", - "revision": 1, - "config_sha256": "89d2686d0d1ca60159c3c6bd725dc9e6f511cbdb56bf6ce7b65ca7d4dc3f2d60", - "mode": "real", - "trunks": [ - { - "trunk_id": "provider-primary", - "provider_id": "provider-primary", - "egress_pool_id": "egress-single", - "codec": "PCMA", - "caller_profile_ids": [ - "caller-primary" - ], - "dial_prefix": "7089", - "enabled": true, - "sip_endpoint_ref": "provider-primary", - "credential_ref": "sip-provider-primary", - "media_profile_id": "pcma-8k-pt8" - }, - { - "trunk_id": "provider-second", - "provider_id": "provider-second", - "egress_pool_id": "egress-single", - "codec": "PCMA", - "caller_profile_ids": [ - "caller-second" - ], - "dial_prefix": "", - "enabled": true, - "sip_endpoint_ref": "provider-second", - "credential_ref": "sip-provider-second", - "media_profile_id": "pcma-8k-pt8" - }, - { - "trunk_id": "provider-third", - "provider_id": "provider-third", - "egress_pool_id": "egress-single", - "codec": "PCMA", - "caller_profile_ids": [ - "caller-third" - ], - "dial_prefix": "mka755", - "enabled": true, - "sip_endpoint_ref": "provider-third", - "credential_ref": "sip-provider-third", - "media_profile_id": "pcma-8k-pt8" - } - ], - "ari": { - "base_url": "https://127.0.0.1:8088/ari", - "websocket_url": "wss://127.0.0.1:8088/ari/events", - "application": "agent-call", - "credential_ref": "ari-single" - }, - "media": { - "bind_address": "127.0.0.1", - "port": 12000, - "format": "alaw", - "sample_rate_hz": 8000, - "channels": 1, - "payload_type": 8 - }, - "recording": { - "enabled": true, - "format": "wav", - "directory": "/var/lib/sip-go-agent/recordings", - "max_bytes": 67108864 - }, - "load_evidence": { - "status": "not-yet-loaded" - }, - "allowed_targets": [ - "15003164745", - "15830461047" - ], - "media_profiles": { - "pcma-8k-pt8": { - "format": "alaw", - "sample_rate_hz": 8000, - "channels": 1, - "payload_type": 8 - }, - "slin16-16k-pt118": { - "format": "slin16", - "sample_rate_hz": 16000, - "channels": 1, - "payload_type": 118 - } - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/static-cell-artifact.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/static-cell-artifact.json deleted file mode 100644 index bc4c0b2..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/examples/static-cell-artifact.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "artifact_id": "artifact-cell-a-1", - "source_release": "management-snapshot-1", - "source_digest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "approval_reference": "mock-approval-1", - "cell_id": "cell-a", - "revision": 1, - "config_sha256": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", - "mode": "mock", - "trunks": [ - { - "trunk_id": "trunk-mock", - "provider_id": "provider-mock", - "egress_pool_id": "egress-mock", - "codec": "PCMA", - "caller_profile_ids": [ - "caller_profile_test" - ], - "dial_prefix": "7089", - "enabled": true, - "sip_endpoint_ref": "mock-sip-endpoint", - "credential_ref": null, - "media_profile_id": "slin16-16k-pt118" - } - ], - "load_evidence": null, - "allowed_targets": [ - "15003164745", - "15830461047" - ], - "media_profiles": { - "pcma-8k-pt8": { - "format": "alaw", - "sample_rate_hz": 8000, - "channels": 1, - "payload_type": 8 - }, - "slin16-16k-pt118": { - "format": "slin16", - "sample_rate_hz": 16000, - "channels": 1, - "payload_type": 118 - } - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/executor.openapi.yaml b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/executor.openapi.yaml deleted file mode 100644 index a9f02fb..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/executor.openapi.yaml +++ /dev/null @@ -1,303 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Executor Control API - version: 1.0.0 - description: >- - Internal control, query, replay, and recording hand-off API. Call execution - enters through RabbitMQ, not HTTP. -servers: - - url: https://executor.internal -security: - - bearerAuth: [] -paths: - /internal/v1/outbound/tasks/{task_id}/controls: - post: - operationId: controlTask - summary: Persist a pause, resume, or stop barrier - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/TaskId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ControlRequest' - responses: - '202': - description: Reliably persisted, not yet necessarily applied - headers: - Location: - schema: {type: string} - content: - application/json: - schema: {$ref: '#/components/schemas/ControlAccepted'} - '409': {$ref: '#/components/responses/Conflict'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/commands/{command_id}: - get: - operationId: getCommand - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/CommandId' - responses: - '200': - description: Command snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Command'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/calls/{call_id}: - get: - operationId: getCall - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/CallId' - responses: - '200': - description: Call snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Call'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/calls/{call_id}/replays: - post: - operationId: replayCall - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/CallId' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayRequest'} - responses: - '202': - description: Replay persisted for bounded broker delivery - headers: - Location: {schema: {type: string}} - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayAccepted'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - '410': {$ref: '#/components/responses/ReplayExpired'} - /internal/v1/outbound/commands/{source_command_id}/replays: - post: - operationId: replayCommand - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/SourceCommandId' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayRequest'} - responses: - '202': - description: Replay persisted for bounded broker delivery - headers: - Location: {schema: {type: string}} - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayAccepted'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - '410': {$ref: '#/components/responses/ReplayExpired'} -components: - securitySchemes: - bearerAuth: - type: http - scheme: bearer - parameters: - TenantId: - name: X-Tenant-ID - in: header - required: true - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string} - IdempotencyKey: - name: Idempotency-Key - in: header - required: true - schema: {type: string} - TaskId: - name: task_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - CommandId: - name: command_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - SourceCommandId: - name: source_command_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - CallId: - name: call_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - schemas: - Id: - type: string - minLength: 1 - maxLength: 128 - pattern: '^[^\s/\\]+$' - ControlRequest: - type: object - additionalProperties: false - required: [command_id, action, expected_task_revision, reason] - properties: - command_id: {$ref: '#/components/schemas/Id'} - action: {type: string, enum: [pause, resume, stop]} - expected_task_revision: {type: integer, minimum: 1} - active_call_policy: {type: string, enum: [drain, hangup]} - reason: {type: string, minLength: 1, maxLength: 512} - ControlAccepted: - type: object - required: - - command_id - - tenant_id - - tenant_key - - task_id - - status - - requested_task_revision - - accepted_at - properties: - command_id: {$ref: '#/components/schemas/Id'} - tenant_id: {type: string} - tenant_key: {type: string} - task_id: {$ref: '#/components/schemas/Id'} - status: {const: accepted} - requested_task_revision: {type: integer} - accepted_at: {type: string, format: date-time} - ReplayRequest: - type: object - additionalProperties: false - required: [command_id, reason] - properties: - command_id: {$ref: '#/components/schemas/Id'} - reason: {type: string, minLength: 1, maxLength: 512} - ReplayAccepted: - type: object - required: [command_id, status, snapshot_cutoff] - properties: - command_id: {$ref: '#/components/schemas/Id'} - status: {const: accepted} - snapshot_cutoff: {type: string, format: date-time} - Command: - type: object - required: - - command_id - - command_type - - tenant_id - - tenant_key - - status - - aggregate_version - properties: - command_id: {$ref: '#/components/schemas/Id'} - command_type: {type: string} - tenant_id: {type: string} - tenant_key: {type: string} - task_id: {type: [string, 'null']} - execution_id: {type: [string, 'null']} - call_id: {type: [string, 'null']} - status: {type: string} - reason_code: {type: [string, 'null']} - wait_reason_code: {type: [string, 'null']} - accepted_at: {type: [string, 'null'], format: date-time} - waiting_since: {type: [string, 'null'], format: date-time} - admission_deadline: {type: [string, 'null'], format: date-time} - requested_task_revision: {type: [integer, 'null']} - applied_task_revision: {type: [integer, 'null']} - task_state: {type: [string, 'null']} - updated_at: {type: string, format: date-time} - aggregate_version: {type: integer, minimum: 1} - Call: - type: object - required: - - call_id - - execution_id - - call_state - - call_version - - attempts - - transcript - - recordings - - delivery - - snapshot_at - properties: - call_id: {type: string} - execution_id: {type: string} - task_id: {type: string} - task_item_id: {type: string} - call_state: {type: string} - call_version: {type: integer} - reason_code: {type: [string, 'null']} - outcome: {type: [string, 'null']} - started_at: {type: [string, 'null'], format: date-time} - ended_at: {type: [string, 'null'], format: date-time} - duration_ms: {type: [integer, 'null']} - attempts: {type: array, items: {type: object}} - transcript: {type: object} - recordings: {type: array, items: {type: object}} - delivery: {type: object} - snapshot_at: {type: string, format: date-time} - Problem: - type: object - additionalProperties: false - required: [type, title, status, code, detail, request_id, retryable] - properties: - type: {type: string, format: uri-reference} - title: {type: string} - status: {type: integer} - code: {type: string} - detail: {type: string} - request_id: {type: string} - retryable: {type: boolean} - responses: - Unauthorized: - description: Unauthorized - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - Forbidden: - description: Forbidden - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - NotFound: - description: Not found without cross-tenant enumeration - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - Conflict: - description: Idempotency or revision conflict - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - ReplayExpired: - description: Retention window expired - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/mock-profile.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/mock-profile.json deleted file mode 100644 index 4a79b80..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/mock-profile.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "profile_version": "1.0.0", - "mode": "mock", - "provider_modes": { - "saas": "mock", - "database": "sqlite", - "rabbitmq": "memory", - "sip": "mock", - "asterisk": "mock", - "asr": "mock", - "llm": "mock", - "tts": "mock", - "oss": "mock", - "cloud": "fake-cli" - }, - "versions": {"schema": "1.0", "service": "0.1.0", "seed": "mock-2026-09-11"}, - "limits": { - "admission_window_s": 30, - "ring_timeout_ms": 30000, - "max_call_duration_ms": 180000, - "max_mq_bytes": 262144, - "max_queue_messages": 1000, - "max_queue_bytes": 16777216, - "disk_warn_pct": 0.70, - "disk_stop_pct": 0.80, - "max_http_bytes": 65536, - "recording_max_bytes": 16777216, - "max_recording_bytes": 16777216, - "replay_retention_s": 604800, - "upload_ttl_s": 300, - "global_concurrency": 6, - "global_cps": 3, - "tenant_concurrency": 2, - "tenant_cps": 1, - "tenant_publish_rate": 10, - "scheduler_lease_ttl_s": 10, - "pending_window_per_tenant": 16, - "pending_window_global": 64, - "max_unacked_per_tenant": 4, - "max_replay_attempts": 6, - "cell_capacity": 4, - "turns": 2, - "hold_ms": 0 - }, - "random_seed": 7, - "tenants": [ - {"tenant_id": "tenant-demo", "tenant_key": "tenant-demo-key", "enabled": true}, - {"tenant_id": "tenant-b", "tenant_key": "tenant.b", "enabled": true}, - {"tenant_id": "tenant-c", "tenant_key": "tenant#c", "enabled": true} - ], - "tasks": [ - {"task_id": "task-demo", "tenant_id": "tenant-demo", "state": "running", "revision": 1}, - {"task_id": "task-b", "tenant_id": "tenant-b", "state": "running", "revision": 1}, - {"task_id": "task-c", "tenant_id": "tenant-c", "state": "running", "revision": 1} - ], - "routes": [{"route_policy_id": "route_policy_test", "trunk_id": "trunk-mock", "egress_pool_id": "egress-mock", "dial_prefix": "7089", "allowed": true}], - "caller_profiles": [{"caller_profile_id": "caller_profile_test", "display": "BD93205882", "allowed": true}], - "agents": [{"agent_version_id": "agent_v1", "immutable": true, "llm": "mock", "tts": "mock", "asr": "mock"}], - "cells": [ - {"cell_id": "cell-a", "capacity": 4, "media_capacity": 4, "ai_capacity": 4, "egress_pool_id": "egress-mock", "ari_mode": "mock"}, - {"cell_id": "cell-b", "capacity": 4, "media_capacity": 4, "ai_capacity": 4, "egress_pool_id": "egress-mock", "ari_mode": "mock"} - ], - "failure_scenarios": ["success", "busy", "no_answer", "ai_timeout", "customer_silent", "ari_disconnect", "upload_missing", "upload_bad_checksum", "broker_outage", "clock_jump"] -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/mq-topology.md b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/mq-topology.md deleted file mode 100644 index 60f8501..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/mq-topology.md +++ /dev/null @@ -1,40 +0,0 @@ -# agent-call MQ topology v1.0 - -This file is an implementation companion to the field authority in -`SaaS交互_OpenAPI与MQ契约规划_v0.1.md`. - -| Element | Value | -| --- | --- | -| Namespace | `agent-call` | -| Command exchange | `agent-call.commands.v1`, durable `direct` | -| Tenant command queue | `agent-call.executor.{tenant_key}.v1`, durable, one exact binding | -| Command routing key | `agent-call.tenant.{tenant_key}.call.execute` | -| Event exchange | `agent-call.events.v1`, durable `topic` | -| SaaS result queue | `agent-call.saas.events.v1`, durable, binding `agent-call.#` | -| Event routing key | `agent-call.{event_type}` | -| Body limit | `262144` UTF-8 bytes in the Mock profile | -| Tenant route budget | Broker limit `255` bytes; fixed prefix/suffix consume `31`, leaving `224` UTF-8 bytes | - -## Delivery rules - -1. SaaS persists the command publication record before publishing. A mandatory - publisher confirmation is required; an unroutable/full queue leaves the - original record retained for bounded retry. -2. The executor consumes only its trusted tenant queue. RabbitMQ messages are - acknowledged after durable SQLite acceptance or durable dead-lettering, not - when they are fetched. -3. Executor business events are written to the same database transaction as - the state transition. The outbox dispatcher publishes them durably and the - SaaS inbox applies each `event_id` once. `saas_applied` may remain unknown - after broker confirmation; it does not trigger unbounded republishing. -4. `tenant_key` is copied byte-for-byte into the body, queue name, binding and - routing key. It is not normalized, encoded, truncated or cleaned. A route - over the byte budget is retained and not sent. -5. Replay publishes the original event body and original `event_id` from a - fixed retention cutoff. It never creates a new business fact and never - includes events written after that cutoff. -6. HTTP has no call execution or redial endpoint. Control, query, replay and - recording metadata paths require bearer scope and tenant scope. - -The in-process broker is only for deterministic tests. Docker Compose uses the -same topology through the `pika` adapter and RabbitMQ durable queues. diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/mq.schema.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/mq.schema.json deleted file mode 100644 index b5ab065..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/mq.schema.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.invalid/contracts/mq.schema.json", - "title": "agent-call MQ command and event envelope", - "oneOf": [{"$ref": "#/$defs/executeCommand"}, {"$ref": "#/$defs/event"}], - "$defs": { - "id": {"type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[^\\s/\\\\]+$"}, - "tenantKey": {"type": "string", "minLength": 1}, - "time": {"type": "string", "format": "date-time"}, - "executeCommand": { - "type": "object", "additionalProperties": false, - "required": ["schema_version", "command_type", "command_id", "tenant_id", "tenant_key", "trace_id", "issued_at", "not_after", "payload"], - "properties": { - "schema_version": {"const": "1.0"}, "command_type": {"const": "call.execute"}, "command_id": {"$ref": "#/$defs/id"}, - "tenant_id": {"$ref": "#/$defs/id"}, "tenant_key": {"$ref": "#/$defs/tenantKey"}, "trace_id": {"$ref": "#/$defs/id"}, - "issued_at": {"$ref": "#/$defs/time"}, "not_after": {"$ref": "#/$defs/time"}, "payload": {"$ref": "#/$defs/executePayload"} - } - }, - "executePayload": { - "type": "object", "additionalProperties": false, - "required": ["execution_id", "task_id", "task_item_id", "task_revision", "callee", "route_policy_id", "caller_profile_id", "agent_version_id", "variables", "ring_timeout_ms", "max_call_duration_ms"], - "properties": { - "execution_id": {"$ref": "#/$defs/id"}, "task_id": {"$ref": "#/$defs/id"}, "task_item_id": {"$ref": "#/$defs/id"}, - "task_revision": {"type": "integer", "minimum": 1}, "callee": {"type": "string", "minLength": 1, "maxLength": 256}, - "route_policy_id": {"$ref": "#/$defs/id"}, "caller_profile_id": {"$ref": "#/$defs/id"}, "agent_version_id": {"$ref": "#/$defs/id"}, - "variables": {"type": "object", "additionalProperties": true}, "ring_timeout_ms": {"type": "integer", "minimum": 1}, "max_call_duration_ms": {"type": "integer", "minimum": 1} - } - }, - "event": { - "type": "object", "additionalProperties": false, - "required": ["schema_version", "event_id", "event_type", "tenant_id", "tenant_key", "trace_id", "occurred_at", "aggregate_type", "aggregate_id", "aggregate_version", "payload"], - "properties": { - "schema_version": {"const": "1.0"}, "event_id": {"$ref": "#/$defs/id"}, - "event_type": {"enum": ["command.result", "call.status", "transcript.updated", "call.finished", "recording.ready", "recording.failed", "transcript.failed", "contact.opt_out"]}, - "tenant_id": {"$ref": "#/$defs/id"}, "tenant_key": {"$ref": "#/$defs/tenantKey"}, "trace_id": {"$ref": "#/$defs/id"}, "occurred_at": {"$ref": "#/$defs/time"}, - "aggregate_type": {"enum": ["command", "call", "transcript_segment", "recording"]}, "aggregate_id": {"$ref": "#/$defs/id"}, "aggregate_version": {"type": "integer", "minimum": 1}, "payload": {"type": "object"} - } - } - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/oss-upload.schema.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/oss-upload.schema.json deleted file mode 100644 index 1393b72..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/oss-upload.schema.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/oss-upload.schema.json", - "title": "Recording upload control-plane messages", - "type": "object", - "required": ["kind"], - "properties": {"kind": {"type": "string"}}, - "oneOf": [ - { - "additionalProperties": false, - "properties": { - "kind": {"const": "request"}, - "upload_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "recording_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "call_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "size_bytes": {"type": "integer", "minimum": 1}, - "checksum_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "format": {"enum": ["wav", "raw_pcm", "pcma"]}, - "channels": {"const": 1}, - "sample_rate_hz": {"type": "integer", "minimum": 8000}, - "duration_ms": {"type": "integer", "minimum": 1} - }, - "required": ["upload_id", "recording_id", "call_id", "size_bytes", "checksum_sha256", "format", "channels", "sample_rate_hz", "duration_ms"] - }, - { - "additionalProperties": false, - "properties": { - "kind": {"const": "grant"}, - "upload_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "recording_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "upload_url": {"type": "string", "format": "uri", "pattern": "^https://"}, - "required_headers": {"type": "object", "additionalProperties": {"type": "string"}}, - "expires_at": {"type": "string", "format": "date-time"}, - "max_bytes": {"type": "integer", "minimum": 1}, - "object_binding": {"type": "string", "minLength": 1, "maxLength": 256} - }, - "required": ["upload_id", "recording_id", "upload_url", "required_headers", "expires_at", "max_bytes", "object_binding"] - }, - { - "additionalProperties": false, - "properties": { - "kind": {"const": "complete"}, - "upload_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "recording_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "size_bytes": {"type": "integer", "minimum": 1}, - "checksum_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "etag": {"type": ["string", "null"], "maxLength": 256} - }, - "required": ["upload_id", "recording_id", "size_bytes", "checksum_sha256", "etag"] - }, - { - "additionalProperties": false, - "properties": { - "kind": {"const": "verified"}, - "upload_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "recording_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "oss_id": {"type": "string", "minLength": 1, "maxLength": 512}, - "verified_at": {"type": "string", "format": "date-time"}, - "checksum_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"} - }, - "required": ["upload_id", "recording_id", "oss_id", "verified_at", "checksum_sha256"] - } - ] -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/p1-development-profile.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/p1-development-profile.json deleted file mode 100644 index 21b0db6..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/p1-development-profile.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "profile_id": "p1-mock-two-cell-v1", - "profile_version": "1.0.0", - "environment": "mock", - "external_calls": false, - "real_authorization": "blocked", - "topology": {"dispatcher_count": 1, "agent_count": 2, "cell_count": 2, "tenant_count": 1}, - "limits": { - "global_concurrency": 6, - "global_cps": 3, - "tenant_concurrency": 2, - "tenant_cps": 1, - "pending_window_global": 64, - "pending_window_per_tenant": 16, - "lease_ttl_ms": 10000, - "final_permit_ttl_ms": 1000 - }, - "modes": ["full_ai", "asr_only"], - "retention": {"keep_unverified_assets": true, "delete_only_after_verified": true, "backup_kind": "local-sqlite-wal-consistent"}, - "status": "development-only-not-production-approval", - "real_budget": "unknown", - "operator_approval": "not-granted" -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/p1-development-profile.schema.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/p1-development-profile.schema.json deleted file mode 100644 index adb8b5d..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/p1-development-profile.schema.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/p1-development-profile.schema.json", - "title": "P1 isolated development profile", - "type": "object", - "additionalProperties": false, - "required": ["profile_id", "profile_version", "environment", "external_calls", "real_authorization", "topology", "limits", "modes", "retention", "status"], - "properties": { - "profile_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "profile_version": {"type": "string", "minLength": 1, "maxLength": 32}, - "environment": {"const": "mock"}, - "external_calls": {"const": false}, - "real_authorization": {"const": "blocked"}, - "topology": { - "type": "object", "additionalProperties": false, - "required": ["dispatcher_count", "agent_count", "cell_count", "tenant_count"], - "properties": {"dispatcher_count": {"const": 1}, "agent_count": {"const": 2}, "cell_count": {"const": 2}, "tenant_count": {"type": "integer", "minimum": 1}} - }, - "limits": { - "type": "object", "additionalProperties": false, - "required": ["global_concurrency", "global_cps", "tenant_concurrency", "tenant_cps", "pending_window_global", "pending_window_per_tenant", "lease_ttl_ms", "final_permit_ttl_ms"], - "properties": { - "global_concurrency": {"type": "integer", "minimum": 1}, - "global_cps": {"type": "integer", "minimum": 1}, - "tenant_concurrency": {"type": "integer", "minimum": 1}, - "tenant_cps": {"type": "integer", "minimum": 1}, - "pending_window_global": {"type": "integer", "minimum": 1}, - "pending_window_per_tenant": {"type": "integer", "minimum": 1}, - "lease_ttl_ms": {"const": 10000}, - "final_permit_ttl_ms": {"type": "integer", "minimum": 1, "maximum": 1000} - } - }, - "modes": {"type": "array", "minItems": 2, "uniqueItems": true, "items": {"enum": ["full_ai", "asr_only"]}}, - "retention": { - "type": "object", "additionalProperties": false, - "required": ["keep_unverified_assets", "delete_only_after_verified", "backup_kind"], - "properties": {"keep_unverified_assets": {"const": true}, "delete_only_after_verified": {"const": true}, "backup_kind": {"enum": ["local-sqlite-wal-consistent", "not-configured"]}} - }, - "status": {"const": "development-only-not-production-approval"}, - "real_budget": {"const": "unknown"}, - "operator_approval": {"const": "not-granted"} - } -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/release-manifest.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/release-manifest.json deleted file mode 100644 index 780715c..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/release-manifest.json +++ /dev/null @@ -1,205 +0,0 @@ -{ - "release_version": "2026-09-19-p1-v1", - "release_kind": "project-owned-first-production-closure-v1", - "contract_status": "project-owned-v1-authorized-not-external-authoritative", - "source_bundle": "2026-09-18-p1-baseline", - "source_worktree": "project-authored-v1", - "runtime_dependency": "none (bundle is embedded; parent paths are never read at runtime)", - "files": [ - { - "path": "README.md", - "bytes": 1531, - "sha256": "3332e4c71021189b03f3031106c08b3c9c08eb2f9bb1a4f4b0a96fe1598ceaba" - }, - { - "path": "SNAPSHOT.json", - "bytes": 948, - "sha256": "a41adc5ec329a9010cc45d08f309eb3620e0d6311a5c565a9f26a35ffc4ecb42" - }, - { - "path": "ai-authorization.schema.json", - "bytes": 1749, - "sha256": "5d6bbd369bd6b406abe9b9f8619e6f299b544dacfdd4473a08257a366fd95d20" - }, - { - "path": "ai-config.openapi.yaml", - "bytes": 4516, - "sha256": "d2f75d8fd2bf76ceb4eef869a838f08dca156938e1f3025d126ce81e436f624a" - }, - { - "path": "ai-config.schema.json", - "bytes": 4797, - "sha256": "dc915bff70e71408fcacbaad47d3554bbfa7a22a51f2f53e127c6bd8bc8ba5a6" - }, - { - "path": "cell-agent.openapi.yaml", - "bytes": 7633, - "sha256": "79dc697d7ce16e2a6aa7e350f30dd006dd847afe2cdc0ea29841f9c6d4310c41" - }, - { - "path": "event-payloads.schema.json", - "bytes": 8683, - "sha256": "5091ded520d692f458699327b13adddeccb0c4b4d4a72ef7cdfebcd5d496eade" - }, - { - "path": "examples/README.md", - "bytes": 728, - "sha256": "a3514c7ef89b4324685bc9025139488000fa42330de72495484add042a6897cf" - }, - { - "path": "examples/agent-version-asr-only.json", - "bytes": 534, - "sha256": "24864df1fd72a59efaaaf6d1fc81a0c7db01fbdfcd821aab4069b64a8db9b60b" - }, - { - "path": "examples/agent-version-full-explicit.json", - "bytes": 1051, - "sha256": "e590148448885a1e88c473ca032d5efd719270689c3cff7aa44ca9c6ffa2b321" - }, - { - "path": "examples/agent-version-full-production-v1.json", - "bytes": 1316, - "sha256": "6a5f35f8cc4256c048d4f1ca567a3544ea7bc92bb835cfab39a000d22b73102b" - }, - { - "path": "examples/agent-version.json", - "bytes": 1079, - "sha256": "d3d4bf2fae07192674e54bf32172a8e95146f11d70609f3cd8f57f0112633c2e" - }, - { - "path": "examples/ai-authorization.json", - "bytes": 467, - "sha256": "b1c0f723f083d1be45035792482f6f74bd3bca34486cc6408d4bcfe3772bc432" - }, - { - "path": "examples/call.execute.json", - "bytes": 656, - "sha256": "0164664fd3503d72668b24bdecb623aa0414ce58191960b868abe8454988c742" - }, - { - "path": "examples/event-call-finished.json", - "bytes": 783, - "sha256": "fab56aff9c5d4059b8fa65d24f2afa424148e7a07025238fc7fd30e9c5ee63f4" - }, - { - "path": "examples/event-call-status.json", - "bytes": 752, - "sha256": "5c673ceb4a98ce8c90d976356b4c5ffa6c7d96d045b5b3312513a9be93d585ba" - }, - { - "path": "examples/event-command-result.json", - "bytes": 498, - "sha256": "64fe71719573378b0caac2f7c5476a27ba7073df8c346d4748a6b0d534d4a087" - }, - { - "path": "examples/event-contact-opt-out.json", - "bytes": 513, - "sha256": "b661f65f0a195e59fe226b12ebae2feb5a9733a9a779c835245be27319aaf8f2" - }, - { - "path": "examples/event-recording-failed.json", - "bytes": 546, - "sha256": "4f5f46422d2281ffae65c99e947bc7dd44effb5e94eacc12e41b3250ac645c34" - }, - { - "path": "examples/event-recording-ready.json", - "bytes": 648, - "sha256": "2b6d731a8d7993cbbe07a5ba8c7413ec56bae8a1538476c0f1740133a488d5b4" - }, - { - "path": "examples/event-transcript-failed.json", - "bytes": 499, - "sha256": "58d000ce27de6e67054f66d4ded34ffafa983bdcced12613051f670d1eefeed8" - }, - { - "path": "examples/event-transcript-updated.json", - "bytes": 596, - "sha256": "115f276522631d7c4decee71ee238aa0d00b4256adedfc9a6a0c5f9dc89f64f6" - }, - { - "path": "examples/invalid-ai-authorization-revoked.json", - "bytes": 373, - "sha256": "0b946b43c1f773391791dfb60a2b2a03c8a69e64e5e9ea30af8591850c34b8f3" - }, - { - "path": "examples/invalid-asr-only-with-llm.json", - "bytes": 529, - "sha256": "7343ce8d6ce63e22128ab7bc721544d681a5dd9eccfc4ab4f9d6181c5748824c" - }, - { - "path": "examples/invalid-event-unknown-type.json", - "bytes": 348, - "sha256": "80c3f89dc775deec9d1a3b85c81ea4b2fd1b030bc4deba1a4dcd2823e4eb8024" - }, - { - "path": "examples/invalid-oss-upload-http.json", - "bytes": 347, - "sha256": "8e4fb4344c4bec51b47ff9b00a63afdc84d09ab827e1b6823c4e576bf6b6a3f1" - }, - { - "path": "examples/oss-upload-grant.json", - "bytes": 423, - "sha256": "268751a1a0d238636c04c004a635e3bda702bc2ef90ade0e5846b47a3c263b5d" - }, - { - "path": "examples/static-cell-artifact-real-v1.json", - "bytes": 2526, - "sha256": "b4a001457e747a039677870a3ddeccc902b8f87819c3ce2d2e37ae6a14f1ffe0" - }, - { - "path": "examples/static-cell-artifact.json", - "bytes": 1147, - "sha256": "129821e4de654ef12d3e7f155e9301ecddf798f9ca3399316a20a55273fbc61f" - }, - { - "path": "executor.openapi.yaml", - "bytes": 10244, - "sha256": "b24703783df63e044fc0151c5e215430d2294e13937d2a5ceee3c6fee99b0329" - }, - { - "path": "mock-profile.json", - "bytes": 2549, - "sha256": "4d43097602fed9a68821e765117580706896ac82d4bce361a80a4cea544ab638" - }, - { - "path": "mq-topology.md", - "bytes": 2211, - "sha256": "a85b26596e1b1db7405dcabc967df56d5eb6713cc9908bc05ecaa2075ff1092f" - }, - { - "path": "mq.schema.json", - "bytes": 2953, - "sha256": "4fbfc39d46fb55ca48b71bc11cafce60e0814182ba4f898973c7c4d7657f912a" - }, - { - "path": "oss-upload.schema.json", - "bytes": 3039, - "sha256": "d3f6ffc5e004fba8acbb6a18495be508a63ec45766bab1ef946ece58bbad84de" - }, - { - "path": "p1-development-profile.json", - "bytes": 789, - "sha256": "2aa7cd3f4fa07f7e1a3037107fa7a56183f28370ea06a2a9b8dc18c8790eee2d" - }, - { - "path": "p1-development-profile.schema.json", - "bytes": 2460, - "sha256": "68e1b46194a1f5fa5bc763ba424411f48ada1ab52d39e6f800315a832692794b" - }, - { - "path": "saas.openapi.yaml", - "bytes": 5750, - "sha256": "368c3a7d75ecc74771b88f9bd9fb7131697c69ce695475fc5aaae6099ff889eb" - }, - { - "path": "sip-management.openapi.yaml", - "bytes": 38240, - "sha256": "5006bbb1fb69f7b4a05cbaa5a43f8944e8522172910a41aba61897c9d5e00281" - }, - { - "path": "static-cell-artifact.schema.json", - "bytes": 5156, - "sha256": "46333f6a161ebbfd42f4a326e2509d562164fe836e6d1c88368428795362138d" - } - ] -} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/saas.openapi.yaml b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/saas.openapi.yaml deleted file mode 100644 index e3f47c2..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/saas.openapi.yaml +++ /dev/null @@ -1,169 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call SaaS Recording Handoff API - version: 1.0.0 - description: >- - Internal storage handshake. Business results still return through RabbitMQ. -servers: - - url: https://saas.internal -security: - - bearerAuth: [] -paths: - /internal/v1/outbound/recording-uploads: - post: - operationId: createRecordingUpload - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/UploadRequest'} - responses: - '201': - description: Upload session created or existing session returned - headers: {Cache-Control: {schema: {const: no-store}}} - content: - application/json: - schema: {$ref: '#/components/schemas/UploadSession'} - '200': - description: Existing upload session - content: - application/json: - schema: {$ref: '#/components/schemas/UploadSession'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': {$ref: '#/components/responses/Conflict'} - /internal/v1/outbound/recording-uploads/{upload_id}/complete: - post: - operationId: completeRecordingUpload - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - name: upload_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/CompleteRequest'} - responses: - '200': - description: Object independently verified - content: - application/json: - schema: {$ref: '#/components/schemas/VerifiedUpload'} - '409': {$ref: '#/components/responses/Conflict'} - '410': {$ref: '#/components/responses/Expired'} - '422': {$ref: '#/components/responses/Unprocessable'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} -components: - securitySchemes: - bearerAuth: {type: http, scheme: bearer} - parameters: - TenantId: - name: X-Tenant-ID - in: header - required: true - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string} - IdempotencyKey: - name: Idempotency-Key - in: header - required: true - schema: {type: string} - schemas: - Id: - type: string - minLength: 1 - maxLength: 128 - pattern: '^[^\s/\\]+$' - UploadRequest: - type: object - additionalProperties: false - required: - - recording_id - - call_id - - content_type - - size_bytes - - checksum_algorithm - - checksum - - channels - - sample_rate_hz - - duration_ms - properties: - recording_id: {$ref: '#/components/schemas/Id'} - call_id: {$ref: '#/components/schemas/Id'} - content_type: {type: string, const: audio/wav} - size_bytes: {type: integer, minimum: 1} - checksum_algorithm: {type: string, const: SHA-256} - checksum: {type: string, pattern: '^[0-9a-f]{64}$'} - channels: {type: integer, const: 1} - sample_rate_hz: {type: integer, minimum: 8000} - duration_ms: {type: integer, minimum: 1} - UploadSession: - type: object - required: - - upload_id - - recording_id - - expires_at - - upload_method - - upload_url - - required_headers - - constraints - properties: - upload_id: {$ref: '#/components/schemas/Id'} - recording_id: {$ref: '#/components/schemas/Id'} - expires_at: {type: string, format: date-time} - upload_method: {const: PUT} - upload_url: {type: string, format: uri} - required_headers: {type: object} - constraints: {type: object} - oss_id: {type: [string, 'null']} - CompleteRequest: - type: object - additionalProperties: false - required: [recording_id, size_bytes, checksum_algorithm, checksum] - properties: - recording_id: {$ref: '#/components/schemas/Id'} - size_bytes: {type: integer, minimum: 1} - checksum_algorithm: {const: SHA-256} - checksum: {type: string, pattern: '^[0-9a-f]{64}$'} - etag: {type: [string, 'null']} - VerifiedUpload: - type: object - required: [upload_id, recording_id, status, oss_id, verified_at] - properties: - upload_id: {$ref: '#/components/schemas/Id'} - recording_id: {$ref: '#/components/schemas/Id'} - status: {const: verified} - oss_id: {type: string} - verified_at: {type: string, format: date-time} - Problem: - type: object - required: [type, title, status, code, detail, request_id, retryable] - properties: - type: {type: string} - title: {type: string} - status: {type: integer} - code: {type: string} - detail: {type: string} - request_id: {type: string} - retryable: {type: boolean} - responses: - Unauthorized: {description: Unauthorized} - Forbidden: {description: Forbidden} - Conflict: {description: Idempotency conflict} - Expired: {description: Upload expired} - Unprocessable: {description: Object failed independent verification} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/sip-management.openapi.yaml b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/sip-management.openapi.yaml deleted file mode 100644 index 28fee2b..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/sip-management.openapi.yaml +++ /dev/null @@ -1,1125 +0,0 @@ ---- -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Asterisk/SIP Management API - version: 1.0.0 - description: >- - Independent Asterisk/SIP management backend. Admin write operations are - separate from the SaaS read-only Trunk directory and from ordinary - scheduling APIs. In mock mode publication records are intents only. In - real mode a publication is successful only after every selected Cell Agent - returns a matching mTLS acknowledgement. -servers: - - url: https://sip-admin.internal - description: Restricted operator management network - - url: https://sip-read.internal - description: SaaS read-only service network -tags: - - name: health - - name: admin-providers - - name: admin-trunks - - name: admin-cells - - name: admin-status - - name: admin-statistics - - name: admin-audit - - name: saas-readonly -paths: - /healthz/live: - get: - tags: [health] - operationId: live - responses: - '200': - description: Service is alive - content: - application/json: - schema: - $ref: '#/components/schemas/Health' - /admin/v1/providers: - get: - tags: [admin-providers] - operationId: listProviders - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider directory - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderList'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/providers/{provider_id}: - parameters: - - {$ref: '#/components/parameters/ProviderId'} - get: - tags: [admin-providers] - operationId: getProvider - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-providers] - operationId: upsertProvider - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderInput'} - responses: - '200': - description: Updated provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '201': - description: Created provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '400': {$ref: '#/components/responses/BadRequest'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks: - get: - tags: [admin-trunks] - operationId: listAdminTrunks - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/TrunkStatusFilter'} - responses: - '200': - description: All Trunks, including unpublished revisions - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTrunkList' - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - /admin/v1/trunks/{trunk_id}: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: getAdminTrunk - security: [{SipAdminBearer: []}] - responses: - '200': - description: Trunk configuration and revisions - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTrunk' - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-trunks] - operationId: createTrunkRevision - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TrunkConfig' - responses: - '200': - description: New draft revision for an existing Trunk - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '201': - description: New Trunk with its first draft revision - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '400': {$ref: '#/components/responses/BadRequest'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/validate: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: validateTrunk - security: [{SipAdminBearer: []}] - requestBody: - required: false - content: - application/json: - schema: - type: object - additionalProperties: false - properties: - revision: {type: integer, minimum: 1} - responses: - '200': - description: Validation issues, compatible Cells, and impact preview - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/trunks/{trunk_id}/verifications: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: addTrunkVerification - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/VerificationRequest' - responses: - '200': - description: Versioned verification record - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/publish: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: publishTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - responses: - '200': - description: >- - Published revision after all selected Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/disable: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: disableTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - responses: - '200': - description: Trunk disabled after selected Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/rollback: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: rollbackTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - type: object - additionalProperties: false - required: [target_revision] - properties: - target_revision: {type: integer, minimum: 1} - responses: - '200': - description: >- - New revision copied from the target after Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/publications: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: listTrunkPublications - security: [{SipAdminBearer: []}] - responses: - '200': - description: Per-Cell publication intents - content: - application/json: - schema: - type: object - required: [mode, publications] - properties: - mode: {$ref: '#/components/schemas/Mode'} - publications: - type: array - items: {$ref: '#/components/schemas/Publication'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/trunks/{trunk_id}/audit: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: listTrunkAudit - security: [{SipAdminBearer: []}] - responses: - '200': - description: Immutable management audit entries - content: - application/json: - schema: - type: object - required: [mode, audit] - properties: - mode: {$ref: '#/components/schemas/Mode'} - audit: - type: array - items: {$ref: '#/components/schemas/AuditEntry'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/cells: - get: - tags: [admin-cells] - operationId: listCells - security: [{SipAdminBearer: []}] - responses: - '200': - description: Registered multi-machine voice Cells - content: - application/json: - schema: - type: object - required: [mode, cells] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cells: - type: array - items: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/cells/{cell_id}: - parameters: - - {$ref: '#/components/parameters/CellId'} - get: - tags: [admin-cells] - operationId: getCell - security: [{SipAdminBearer: []}] - responses: - '200': - description: Registered Cell - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-cells] - operationId: registerCell - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/CellConfig'} - responses: - '200': - description: Updated Cell revision - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '201': - description: Registered Cell - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/cells/{cell_id}/observations: - parameters: - - {$ref: '#/components/parameters/CellId'} - post: - tags: [admin-cells] - operationId: ingestCellObservation - security: [{SipAdminBearer: []}] - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ObservationInput'} - responses: - '201': - description: >- - Observation accepted for the current boot and monotonic sequence - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/egress-pools: - get: - tags: [admin-cells] - operationId: listEgressPools - security: [{SipAdminBearer: []}] - responses: - '200': - description: Fixed egress pool directory - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/sip-status: - get: - tags: [admin-status] - operationId: getSipStatus - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/CellIdsFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/ProviderFilter'} - responses: - '200': - description: >- - Cell/trunk status matrix with freshness and missing sources - content: - application/json: - schema: {$ref: '#/components/schemas/StatusResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/cells/{cell_id}/sip-status: - parameters: - - {$ref: '#/components/parameters/CellId'} - get: - tags: [admin-status] - operationId: getCellSipStatus - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/TrunkFilter'} - responses: - '200': - description: One Cell status - content: - application/json: - schema: {$ref: '#/components/schemas/StatusItem'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/providers/{provider_id}/status: - parameters: - - {$ref: '#/components/parameters/ProviderId'} - get: - tags: [admin-status] - operationId: getProviderStatus - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider status matrix - content: - application/json: - schema: {$ref: '#/components/schemas/StatusResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/statistics/outbound/summary: - get: - tags: [admin-statistics] - operationId: getOutboundSummary - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Cohort and interval metrics with completeness metadata - content: - application/json: - schema: {$ref: '#/components/schemas/StatisticsSummary'} - '401': {$ref: '#/components/responses/Unauthorized'} - '422': {$ref: '#/components/responses/BadRequest'} - /admin/v1/statistics/outbound/timeseries: - get: - tags: [admin-statistics] - operationId: getOutboundTimeseries - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/Granularity'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Bounded UTC time series - content: - application/json: - schema: {$ref: '#/components/schemas/TimeseriesResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '422': {$ref: '#/components/responses/BadRequest'} - /admin/v1/call-attempts: - get: - tags: [admin-statistics] - operationId: listCallAttempts - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/Limit'} - - {$ref: '#/components/parameters/Cursor'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Redacted raw attempt facts - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/call-attempts/{attempt_id}: - parameters: - - name: attempt_id - in: path - required: true - schema: {type: string} - get: - tags: [admin-statistics] - operationId: getCallAttempt - security: [{SipAdminBearer: []}] - responses: - '200': - description: One redacted attempt fact - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/audit: - get: - tags: [admin-audit] - operationId: listAudit - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/Limit'} - - {$ref: '#/components/parameters/ResourceFilter'} - - {$ref: '#/components/parameters/RequestFilter'} - - {$ref: '#/components/parameters/ActorFilter'} - responses: - '200': - description: Immutable audit entries - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/operations/{operation_id}: - parameters: - - name: operation_id - in: path - required: true - schema: {type: string} - get: - tags: [admin-audit] - operationId: getOperation - security: [{SipAdminBearer: []}] - responses: - '200': - description: Durable operation state for retry/recovery - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /readonly/v1/sip/trunks: - get: - tags: [saas-readonly] - operationId: listAuthorizedTrunks - security: [{SaasTrunkReadBearer: []}] - responses: - '200': - description: Published Trunks authorized for this SaaS principal - content: - application/json: - schema: - $ref: '#/components/schemas/ReadonlyTrunkList' - '401': {$ref: '#/components/responses/Unauthorized'} - /readonly/v1/sip/trunks/{trunk_id}: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [saas-readonly] - operationId: getAuthorizedTrunk - security: [{SaasTrunkReadBearer: []}] - responses: - '200': - description: Published, sanitized Trunk metadata - content: - application/json: - schema: {$ref: '#/components/schemas/ReadonlyTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} -components: - securitySchemes: - SipAdminBearer: - type: http - scheme: bearer - bearerFormat: opaque - description: >- - Dedicated operator/backend credential for SIP management writes. It is - not accepted by the SaaS read-only API or ordinary scheduling API. - SaasTrunkReadBearer: - type: http - scheme: bearer - bearerFormat: opaque - description: >- - Dedicated SaaS read-only credential. It cannot publish, modify, disable, - rollback, or access Cell management. - parameters: - ProviderId: - name: provider_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - TrunkId: - name: trunk_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - CellId: - name: cell_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - IfMatch: - name: If-Match - in: header - required: true - description: Exact latest revision required for CAS; quotes are accepted. - schema: {type: integer, minimum: 0} - CellIdsFilter: - name: cell_ids - in: query - required: false - schema: {type: string} - CellIdFilter: - name: cell_id - in: query - required: false - schema: {type: string} - ProviderFilter: - name: provider_id - in: query - required: false - schema: {type: string} - TrunkFilter: - name: trunk_id - in: query - required: false - schema: {type: string} - TrunkStatusFilter: - name: status - in: query - required: false - schema: {type: string} - ResourceFilter: - name: resource_id - in: query - required: false - schema: {type: string} - ActorFilter: - name: actor - in: query - required: false - schema: {type: string} - From: - name: from - in: query - required: false - schema: {type: string, format: date-time} - To: - name: to - in: query - required: false - schema: {type: string, format: date-time} - StatsMode: - name: mode - in: query - required: false - schema: {type: string, enum: [mock, mixed, real]} - EgressFilter: - name: egress_pool_id - in: query - required: false - schema: {type: string} - Granularity: - name: granularity - in: query - required: false - schema: {type: string, enum: [minute, hour, day]} - Limit: - name: limit - in: query - required: false - schema: {type: integer, minimum: 1, maximum: 200} - Cursor: - name: cursor - in: query - required: false - schema: {type: string} - RequestFilter: - name: request_id - in: query - required: false - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - responses: - BadRequest: - description: Invalid configuration or request - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Unauthorized: - description: Missing or wrong authentication domain - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Forbidden: - description: Credential lacks the required scope - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Conflict: - description: CAS conflict or no compatible Cell - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - NotFound: - description: Resource is not visible or does not exist - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - schemas: - Mode: - type: string - enum: [mock, real] - StatsMode: - type: string - enum: [mock, mixed, real] - Health: - type: object - additionalProperties: false - required: [status, mode] - properties: - status: {type: string, const: ok} - mode: {$ref: '#/components/schemas/Mode'} - CodecProfile: - type: object - additionalProperties: false - required: [allowed, preferred] - properties: - allowed: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - preferred: {type: string, enum: [PCMA, PCMU]} - SipConfig: - type: object - additionalProperties: false - required: [host, port, transport, auth_mode, register] - properties: - host: {type: string, minLength: 1, maxLength: 253} - port: {type: integer, minimum: 1, maximum: 65535} - transport: {type: string, enum: [udp, tcp, tls]} - auth_mode: {type: string, enum: [ip, digest]} - register: {type: boolean} - credential_ref: - type: string - writeOnly: true - description: >- - Secret-store reference only; plaintext credentials are forbidden. - VerificationRequest: - type: object - additionalProperties: false - required: [revision, check_name, result] - properties: - revision: {type: integer, minimum: 1} - check_name: - type: string - enum: - - transport - - registration_auth - - caller_id_rules - - codec - - capacity - - whitelist - result: - type: string - enum: [confirmed, failed, unknown, not_applicable] - evidence_ref: {type: string, maxLength: 512} - checked_by: {type: string, maxLength: 128} - TrunkConfig: - type: object - additionalProperties: false - required: - - provider_id - - display_name - - enabled - - sip - - codec_profile - - caller_ids - - dial_prefix - - egress_pool_id - - max_concurrency - - max_cps - properties: - provider_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - display_name: {type: string, minLength: 1, maxLength: 256} - enabled: {type: boolean} - sip: {$ref: '#/components/schemas/SipConfig'} - codec_profile: {$ref: '#/components/schemas/CodecProfile'} - caller_ids: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, minLength: 1, maxLength: 128} - dial_prefix: {type: string, maxLength: 32} - egress_pool_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - max_concurrency: {type: integer, minimum: 1} - max_cps: {type: integer, minimum: 1} - CellConfig: - type: object - additionalProperties: false - required: [egress_pool_id, codec_capabilities, status, max_concurrency] - properties: - egress_pool_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - codec_capabilities: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - status: {type: string, enum: [healthy, draining, disabled]} - max_concurrency: {type: integer, minimum: 1} - management_url: - type: string - format: uri - pattern: '^https://' - description: >- - mTLS Cell Agent endpoint. Required when mode=real; credentials and - query strings are not allowed. - RevisionInfo: - type: object - additionalProperties: false - required: [revision, state, created_at, created_by] - properties: - revision: {type: integer, minimum: 1} - state: {type: string, enum: [draft, publishing, published, superseded]} - config_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - created_at: {type: string, format: date-time} - created_by: {type: string} - AdminTrunk: - type: object - required: - - mode - - trunk_id - - provider_id - - latest_revision - - active_revision - - active_status - - status - - compatible_cell_ids - - latest - - active - - versions - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunk_id: {type: string} - provider_id: {type: string} - latest_revision: {type: integer, minimum: 1} - active_revision: {type: integer, minimum: 0} - active_status: {type: string, enum: [draft, published, disabled]} - status: {type: string, enum: [draft, published, disabled]} - updated_at: {type: string, format: date-time} - compatible_cell_ids: {type: array, items: {type: string}} - latest: {$ref: '#/components/schemas/TrunkView'} - active: {$ref: '#/components/schemas/TrunkView'} - versions: - type: array - items: - $ref: '#/components/schemas/RevisionInfo' - TrunkView: - allOf: - - {$ref: '#/components/schemas/TrunkConfig'} - - type: object - properties: - trunk_id: {type: string} - credential_configured: {type: boolean} - asterisk_allow: - type: array - items: {type: string, enum: [alaw, ulaw]} - config_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - ReadonlyTrunk: - type: object - required: - - mode - - trunk_id - - provider_id - - revision - - status - - config - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunk_id: {type: string} - provider_id: {type: string} - revision: {type: integer, minimum: 1} - status: {type: string, const: published} - updated_at: {type: string, format: date-time} - config: {$ref: '#/components/schemas/TrunkView'} - AdminTrunkList: - type: object - required: [mode, trunks] - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunks: {type: array, items: {$ref: '#/components/schemas/AdminTrunk'}} - ReadonlyTrunkList: - type: object - required: [mode, trunks] - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunks: - type: array - items: - $ref: '#/components/schemas/ReadonlyTrunk' - Cell: - type: object - required: [mode, cell_id, revision, config, updated_at, updated_by] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cell_id: {type: string} - revision: {type: integer, minimum: 1} - config: {$ref: '#/components/schemas/CellConfig'} - cloud_instance_id: {type: string} - instance_name: {type: string} - region: {type: string} - boot_id: {type: string} - updated_at: {type: string, format: date-time} - updated_by: {type: string} - Publication: - type: object - required: [trunk_id, revision, cell_id, status, updated_at] - properties: - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - cell_id: {type: string} - status: {type: string, enum: [pending, applied, failed]} - error_code: {type: [string, 'null']} - applied_at: {type: [string, 'null'], format: date-time} - target_digest: {type: string} - local_revision: {type: integer, minimum: 0} - local_digest: {type: string} - operation_id: {type: string} - updated_at: {type: string, format: date-time} - AuditEntry: - type: object - required: - - audit_id - - resource_type - - resource_id - - action - - revision - - actor - - details_json - - created_at - properties: - audit_id: {type: string} - resource_type: {type: string, const: trunk} - resource_id: {type: string} - action: - type: string - enum: - [ - upsert, - publish, - publish_failed, - disable, - disable_failed, - rollback, - rollback_failed, - ] - revision: {type: integer, minimum: 0} - actor: {type: string} - request_id: {type: [string, 'null']} - details_json: {type: string} - created_at: {type: string, format: date-time} - ProviderInput: - type: object - additionalProperties: false - required: [display_name, lifecycle] - properties: - display_name: {type: string, minLength: 1, maxLength: 256} - notes: {type: string, maxLength: 2000} - lifecycle: {type: string, enum: [active, archived]} - Provider: - allOf: - - {$ref: '#/components/schemas/ProviderInput'} - - type: object - required: [provider_id, revision, trunk_count, created_at, updated_at] - properties: - provider_id: {type: string} - revision: {type: integer, minimum: 1} - trunk_count: {type: integer, minimum: 0} - created_at: {type: string, format: date-time} - updated_at: {type: string, format: date-time} - updated_by: {type: string} - ProviderList: - type: object - required: [mode, providers] - properties: - mode: {$ref: '#/components/schemas/Mode'} - providers: {type: array, items: {$ref: '#/components/schemas/Provider'}} - ProviderResponse: - type: object - required: [mode, provider] - properties: - mode: {$ref: '#/components/schemas/Mode'} - provider: {$ref: '#/components/schemas/Provider'} - ObservationInput: - type: object - additionalProperties: false - required: [cell_id, boot_id, sequence, observed_at, source, states] - properties: - observation_id: {type: string} - cell_id: {type: string} - trunk_id: {type: string} - boot_id: {type: string, minLength: 1} - sequence: {type: integer, minimum: 1} - observed_at: {type: string, format: date-time} - source: {type: string} - config_revision: {type: integer, minimum: 0} - states: {type: object} - occupancy: {type: object} - sample_id: {type: string} - StatusItem: - type: object - required: [mode, cell_id, availability, complete, missing_sources] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cell_id: {type: string} - availability: {type: string, enum: [healthy, stale, unknown, disabled]} - complete: {type: boolean} - observed_at: {type: [string, 'null'], format: date-time} - received_at: {type: [string, 'null'], format: date-time} - observation_age_seconds: {type: [integer, 'null'], minimum: 0} - clock_skew: {type: boolean} - reason: {type: string} - boot_id: {type: string} - sequence: {type: integer, minimum: 1} - config_revision: {type: integer, minimum: 1} - config_status: {type: string} - egress_pool_id: {type: string} - eligibility: {type: string} - missing_sources: {type: array, items: {type: string}} - states: {type: object} - occupancy: {type: object} - trunks: {type: array, items: {type: object}} - publication: {type: object} - StatusResponse: - type: object - required: [mode, complete, cells] - properties: - mode: {$ref: '#/components/schemas/Mode'} - complete: {type: boolean} - generated_at: {type: string, format: date-time} - data_as_of: {type: [string, 'null'], format: date-time} - coverage: {type: object} - cells: {type: array, items: {$ref: '#/components/schemas/StatusItem'}} - StatisticsSummary: - type: object - required: [mode, from, to, complete, metrics] - properties: - mode: {$ref: '#/components/schemas/StatsMode'} - from: {type: string, format: date-time} - to: {type: string, format: date-time} - timezone: {type: string} - definition_version: {type: string} - filters: {type: object} - complete: {type: boolean} - missing_sources: {type: array, items: {type: string}} - unresolved_count: {type: integer, minimum: 0} - data_as_of: {type: [string, 'null'], format: date-time} - metrics: {type: object} - failure_reasons: {type: array, items: {type: object}} - realtime: {type: object} - TimeseriesResponse: - type: object - required: [mode, from, to, granularity, complete, series] - properties: - mode: {$ref: '#/components/schemas/StatsMode'} - from: {type: string, format: date-time} - to: {type: string, format: date-time} - timezone: {type: string} - definition_version: {type: string} - filters: {type: object} - granularity: {type: string, enum: [minute, hour, day]} - complete: {type: boolean} - series: {type: array, items: {type: object}} - ErrorResponse: - type: object - required: [error] - properties: - error: - type: object - required: [code, message] - properties: - code: {type: string} - message: {type: string} - fields: {type: object} - request_id: {type: string} diff --git a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/static-cell-artifact.schema.json b/contracts/archive/upstream/2026-09-19-p1-v1-legacy/static-cell-artifact.schema.json deleted file mode 100644 index e365a72..0000000 --- a/contracts/archive/upstream/2026-09-19-p1-v1-legacy/static-cell-artifact.schema.json +++ /dev/null @@ -1,102 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/2026-09-19-p1-v1/static-cell-artifact.schema.json", - "title": "Project-owned v1 static Cell/SIP hand-off artifact", - "type": "object", - "additionalProperties": false, - "required": ["artifact_id", "source_release", "source_digest", "approval_reference", "cell_id", "revision", "config_sha256", "mode", "allowed_targets", "trunks"], - "properties": { - "artifact_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "source_release": {"type": "string", "minLength": 1, "maxLength": 128}, - "source_digest": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "approval_reference": {"type": "string", "minLength": 1, "maxLength": 256}, - "cell_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "revision": {"type": "integer", "minimum": 1}, - "config_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "mode": {"enum": ["mock", "mixed", "real"]}, - "allowed_targets": {"type": "array", "minItems": 1, "maxItems": 1000, "uniqueItems": true, "items": {"type": "string", "pattern": "^[0-9]{11,15}$"}}, - "trunks": { - "type": "array", "minItems": 1, "maxItems": 32, - "items": { - "type": "object", "additionalProperties": false, - "required": ["trunk_id", "provider_id", "egress_pool_id", "codec", "caller_profile_ids", "dial_prefix", "enabled", "media_profile_id"], - "properties": { - "trunk_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "provider_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "egress_pool_id": {"type": "string", "minLength": 1, "maxLength": 128}, - "codec": {"const": "PCMA"}, - "caller_profile_ids": {"type": "array", "minItems": 1, "uniqueItems": true, "items": {"type": "string", "minLength": 1, "maxLength": 128}}, - "dial_prefix": {"type": "string", "maxLength": 32}, - "enabled": {"type": "boolean"}, - "sip_endpoint_ref": {"type": "string", "maxLength": 128}, - "credential_ref": {"type": ["string", "null"], "maxLength": 128}, - "media_profile_id": {"type": "string", "minLength": 1, "maxLength": 128} - } - } - }, - "ari": { - "type": "object", "additionalProperties": false, - "required": ["base_url", "websocket_url", "application", "credential_ref"], - "properties": { - "base_url": {"type": "string", "format": "uri", "pattern": "^https?://"}, - "websocket_url": {"type": "string", "format": "uri", "pattern": "^wss?://"}, - "application": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$"}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128} - } - }, - "media_profiles": { - "type": "object", "minProperties": 1, "maxProperties": 16, - "additionalProperties": { - "type": "object", "additionalProperties": false, - "required": ["format", "sample_rate_hz", "channels", "payload_type"], - "properties": { - "format": {"enum": ["slin16", "alaw"]}, - "sample_rate_hz": {"enum": [8000, 16000]}, - "channels": {"const": 1}, - "payload_type": {"type": "integer", "minimum": 0, "maximum": 127} - }, - "allOf": [ - {"if": {"properties": {"format": {"const": "alaw"}}}, "then": {"properties": {"sample_rate_hz": {"const": 8000}, "payload_type": {"const": 8}}}}, - {"if": {"properties": {"format": {"const": "slin16"}}}, "then": {"properties": {"sample_rate_hz": {"const": 16000}, "payload_type": {"type": "integer", "minimum": 96, "maximum": 127}}}} - ] - } - }, - "media": { - "type": "object", "additionalProperties": false, - "required": ["bind_address", "port", "format", "sample_rate_hz", "channels", "payload_type"], - "properties": { - "bind_address": {"type": "string", "minLength": 1, "maxLength": 255}, - "port": {"type": "integer", "minimum": 1024, "maximum": 65535}, - "format": {"enum": ["slin16", "alaw"]}, - "sample_rate_hz": {"enum": [8000, 16000]}, - "channels": {"const": 1}, - "payload_type": {"type": "integer", "minimum": 0, "maximum": 127} - } - }, - "recording": { - "type": "object", "additionalProperties": false, - "required": ["enabled", "format", "directory", "max_bytes"], - "properties": { - "enabled": {"const": true}, - "format": {"const": "wav"}, - "directory": {"type": "string", "minLength": 1, "maxLength": 512}, - "max_bytes": {"type": "integer", "minimum": 16000, "maximum": 1073741824} - } - }, - "load_evidence": { - "type": ["object", "null"], - "additionalProperties": false, - "properties": { - "asterisk_config_sha256": {"type": "string", "pattern": "^[a-f0-9]{64}$"}, - "loaded_at": {"type": "string", "format": "date-time"}, - "status": {"enum": ["not-yet-loaded", "loaded"]} - } - } - }, - "allOf": [ - { - "if": {"properties": {"mode": {"enum": ["mixed", "real"]}}}, - "then": {"required": ["ari", "media", "media_profiles", "recording"]} - } - ] -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/README.md b/contracts/archive/upstream/2026-09-21-p1-v2/README.md deleted file mode 100644 index 193e12a..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Project-local MQ-only v2 - -Approved design: docs/contracts/mq-only-v2-freeze-proposal.md, amended by the enqueue-only upload goal. -This is a local project contract, not external SaaS acceptance. Old v1 files are untouched. -Publisher: scripts/publish-mq-v2.py. Validator: go test ./contracts -run TestV2. - -Upload notification: recording.uploaded, no recording.ready, upload session or verified reply. Completion means persistent delivery to the designated durable MQ queue, mandatory routing and publisher confirm; not SaaS consumption. -Payload: call_id, recording_id, upload_id, bucket, object_key, format, channels, sample_rate_hz, duration_ms, size_bytes, checksum_sha256. No TOKEN, credentials, signed URL or SaaS OSS ID. - -Control/replay command_id belongs solely to the envelope. Query nested structures reuse typed events and delivery counts. AI receipt/config composition is flattened without widening fields. -Schema limits characters; runtime also checks UTF-8 bytes and aggregate response size. Oversized snapshots fail explicitly, never silently truncate. diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/ai-authorization.schema.json b/contracts/archive/upstream/2026-09-21-p1-v2/ai-authorization.schema.json deleted file mode 100644 index 4b6d10e..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/ai-authorization.schema.json +++ /dev/null @@ -1,119 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://go-sip.local/contracts/2026-09-21-p1-v2/ai-authorization.schema.json", - "title": "Dispatcher to Agent immutable AI authorization", - "type": "object", - "additionalProperties": false, - "required": [ - "authorization_id", - "tenant_id", - "tenant_key", - "agent_version_id", - "config_sha256", - "mode", - "issued_at", - "expires_at", - "source", - "revoked" - ], - "properties": { - "authorization_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "tenant_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "tenant_key": { - "type": "string", - "minLength": 1, - "maxLength": 224 - }, - "agent_version_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "config_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "mode": { - "enum": [ - "full_ai", - "asr_only" - ] - }, - "issued_at": { - "type": "string", - "format": "date-time" - }, - "expires_at": { - "type": "string", - "format": "date-time" - }, - "source": { - "enum": [ - "saas", - "mock-saas" - ] - }, - "credential_refs": { - "type": "object", - "additionalProperties": false, - "properties": { - "asr": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "llm": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "tts": { - "type": "string", - "minLength": 1, - "maxLength": 128 - } - } - }, - "allowed_egress_pool_ids": { - "type": "array", - "minItems": 1, - "uniqueItems": true, - "items": { - "type": "string", - "minLength": 1, - "maxLength": 128 - } - }, - "revoked": { - "type": "boolean" - }, - "revocation_reason": { - "type": "string", - "maxLength": 256 - } - }, - "allOf": [ - { - "if": { - "properties": { - "revoked": { - "const": true - } - } - }, - "then": { - "required": [ - "revocation_reason" - ] - } - } - ] -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/ai-config.schema.json b/contracts/archive/upstream/2026-09-21-p1-v2/ai-config.schema.json deleted file mode 100644 index 87c24c3..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/ai-config.schema.json +++ /dev/null @@ -1,323 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://go-sip.local/contracts/2026-09-21-p1-v2/ai-config.schema.json", - "title": "Immutable AI agent version", - "type": "object", - "additionalProperties": false, - "required": [ - "agent_version_id", - "immutable", - "asr", - "conversation" - ], - "properties": { - "agent_version_id": { - "type": "string", - "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$" - }, - "immutable": { - "const": true - }, - "mode": { - "enum": [ - "full_ai", - "asr_only" - ] - }, - "llm": { - "type": "object", - "additionalProperties": false, - "required": [ - "provider_ref", - "model" - ], - "properties": { - "provider_ref": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "credential_ref": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "model": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "temperature": { - "type": "number", - "minimum": 0, - "maximum": 2 - }, - "max_tokens": { - "type": "integer", - "minimum": 1 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - } - } - }, - "prompt": { - "type": "object", - "additionalProperties": false, - "required": [ - "text", - "allowed_variables" - ], - "properties": { - "text": { - "type": "string", - "minLength": 1, - "maxLength": 32768 - }, - "allowed_variables": { - "type": "array", - "maxItems": 32, - "items": { - "type": "string", - "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" - } - }, - "max_bytes": { - "type": "integer", - "minimum": 1, - "maximum": 32768 - } - } - }, - "tts": { - "type": "object", - "additionalProperties": false, - "required": [ - "provider_ref", - "model", - "voice", - "format" - ], - "properties": { - "provider_ref": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "credential_ref": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "model": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "voice": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "speed": { - "type": "number", - "minimum": 0.25, - "maximum": 3 - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "format": { - "type": "object", - "additionalProperties": false, - "required": [ - "encoding", - "sample_rate_hz", - "channels" - ], - "properties": { - "encoding": { - "enum": [ - "pcm_s16le", - "pcma" - ] - }, - "sample_rate_hz": { - "type": "integer", - "minimum": 8000, - "maximum": 48000 - }, - "channels": { - "const": 1 - } - } - } - } - }, - "asr": { - "type": "object", - "additionalProperties": false, - "required": [ - "provider_ref", - "language", - "input" - ], - "properties": { - "provider_ref": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "credential_ref": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "model": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "language": { - "type": "string", - "minLength": 1, - "maxLength": 32 - }, - "interim": { - "type": "boolean" - }, - "timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "input": { - "type": "object", - "additionalProperties": false, - "required": [ - "encoding", - "sample_rate_hz", - "channels", - "sample_width_bytes" - ], - "properties": { - "encoding": { - "const": "pcm_s16le" - }, - "sample_rate_hz": { - "type": "integer", - "minimum": 8000, - "maximum": 48000 - }, - "channels": { - "const": 1 - }, - "sample_width_bytes": { - "const": 2 - } - } - } - } - }, - "conversation": { - "type": "object", - "additionalProperties": false, - "required": [ - "allow_interrupt", - "silence_timeout_ms", - "max_duration_ms", - "max_turns", - "sentence_max_chars", - "max_pending_audio_chunks" - ], - "properties": { - "opening": { - "type": "string", - "maxLength": 32768 - }, - "allow_interrupt": { - "type": "boolean" - }, - "silence_timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "max_duration_ms": { - "type": "integer", - "minimum": 1, - "maximum": 3600000 - }, - "max_turns": { - "type": "integer", - "minimum": 1, - "maximum": 1000 - }, - "sentence_max_chars": { - "type": "integer", - "minimum": 1 - }, - "max_pending_audio_chunks": { - "type": "integer", - "minimum": 1 - } - } - }, - "metadata": { - "type": "object", - "additionalProperties": true - } - }, - "oneOf": [ - { - "title": "Full AI", - "required": [ - "llm", - "prompt", - "tts" - ], - "properties": { - "mode": { - "enum": [ - "full_ai" - ] - }, - "conversation": { - "required": [ - "opening" - ] - } - } - }, - { - "title": "ASR only", - "required": [ - "mode" - ], - "properties": { - "mode": { - "const": "asr_only" - } - }, - "not": { - "anyOf": [ - { - "required": [ - "llm" - ] - }, - { - "required": [ - "prompt" - ] - }, - { - "required": [ - "tts" - ] - } - ] - } - } - ] -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/dispatcher-config.schema.json b/contracts/archive/upstream/2026-09-21-p1-v2/dispatcher-config.schema.json deleted file mode 100644 index 60f7d9d..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/dispatcher-config.schema.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "type": "object", - "additionalProperties": false, - "required": [ - "schema_version", - "dispatcher_id", - "oss" - ], - "properties": { - "schema_version": { - "const": "1.0" - }, - "dispatcher_id": { - "type": "string", - "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" - }, - "oss": { - "type": "object", - "additionalProperties": false, - "required": [ - "endpoint", - "region", - "bucket", - "object_prefix", - "access_key_id_env", - "access_key_secret_env" - ], - "properties": { - "endpoint": { - "type": "string", - "minLength": 1, - "format": "uri", - "pattern": "^https?://" - }, - "region": { - "type": "string", - "minLength": 1 - }, - "bucket": { - "type": "string", - "minLength": 1 - }, - "object_prefix": { - "type": "string", - "minLength": 1 - }, - "access_key_id_env": { - "type": "string", - "minLength": 1, - "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" - }, - "access_key_secret_env": { - "type": "string", - "minLength": 1, - "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" - } - } - } - }, - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://go-sip.local/contracts/2026-09-21-p1-v2/dispatcher-config.schema.json" -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/event-payloads.schema.json b/contracts/archive/upstream/2026-09-21-p1-v2/event-payloads.schema.json deleted file mode 100644 index 360f8f1..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/event-payloads.schema.json +++ /dev/null @@ -1,646 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://go-sip.local/contracts/2026-09-21-p1-v2/event-payloads.schema.json", - "title": "Agent-call versioned event envelopes and payloads", - "type": "object", - "additionalProperties": false, - "required": [ - "schema_version", - "event_id", - "event_type", - "tenant_id", - "tenant_key", - "trace_id", - "occurred_at", - "aggregate_type", - "aggregate_id", - "aggregate_version", - "payload", - "dispatcher_id" - ], - "properties": { - "schema_version": { - "const": "2.0" - }, - "event_id": { - "$ref": "#/$defs/id" - }, - "event_type": { - "type": "string" - }, - "tenant_id": { - "$ref": "#/$defs/id" - }, - "tenant_key": { - "type": "string", - "minLength": 1, - "maxLength": 196, - "not": { - "pattern": "(^|\\.)[*#](\\.|$)" - }, - "$comment": "Runtime also enforces 196 UTF-8 bytes and each AMQP resource's 255-byte budget." - }, - "trace_id": { - "$ref": "#/$defs/id" - }, - "occurred_at": { - "type": "string", - "format": "date-time" - }, - "aggregate_type": { - "type": "string", - "minLength": 1, - "maxLength": 64 - }, - "aggregate_id": { - "$ref": "#/$defs/id" - }, - "aggregate_version": { - "type": "integer", - "minimum": 1 - }, - "payload": { - "type": "object" - }, - "dispatcher_id": { - "type": "string", - "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" - } - }, - "oneOf": [ - { - "properties": { - "event_type": { - "const": "command.result" - }, - "payload": { - "$ref": "#/$defs/command_result" - } - } - }, - { - "properties": { - "event_type": { - "const": "call.status" - }, - "payload": { - "$ref": "#/$defs/call_status" - } - } - }, - { - "properties": { - "event_type": { - "const": "transcript.updated" - }, - "payload": { - "$ref": "#/$defs/transcript_updated" - } - } - }, - { - "properties": { - "event_type": { - "const": "call.finished" - }, - "payload": { - "$ref": "#/$defs/call_finished" - } - } - }, - { - "properties": { - "event_type": { - "const": "recording.uploaded" - }, - "payload": { - "$ref": "#/$defs/recording_uploaded" - } - } - }, - { - "properties": { - "event_type": { - "const": "recording.failed" - }, - "payload": { - "$ref": "#/$defs/recording_failed" - } - } - }, - { - "properties": { - "event_type": { - "const": "transcript.failed" - }, - "payload": { - "$ref": "#/$defs/transcript_failed" - } - } - }, - { - "properties": { - "event_type": { - "const": "contact.opt_out" - }, - "payload": { - "$ref": "#/$defs/contact_opt_out" - } - } - } - ], - "$defs": { - "id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "command_result": { - "type": "object", - "additionalProperties": false, - "required": [ - "command_id", - "command_type", - "status", - "reason_code" - ], - "properties": { - "command_id": { - "$ref": "#/$defs/id" - }, - "command_type": { - "enum": [ - "call.execute", - "task.control", - "call.replay", - "command.replay" - ] - }, - "status": { - "enum": [ - "accepted", - "waiting", - "applied", - "rejected", - "failed", - "unknown" - ] - }, - "reason_code": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "task_id": { - "$ref": "#/$defs/id" - }, - "task_item_id": { - "$ref": "#/$defs/id" - }, - "execution_id": { - "$ref": "#/$defs/id" - }, - "call_id": { - "$ref": "#/$defs/id" - }, - "requested_task_revision": { - "type": "integer", - "minimum": 0 - }, - "applied_task_revision": { - "type": "integer", - "minimum": 0 - }, - "admission_state": { - "enum": [ - "open", - "closed", - "draining", - "quarantined", - "unknown" - ] - }, - "resource_reservation_id": { - "$ref": "#/$defs/id" - }, - "permit_id": { - "$ref": "#/$defs/id" - } - } - }, - "call_status": { - "type": "object", - "additionalProperties": false, - "required": [ - "call_id", - "execution_id", - "call_state", - "call_version", - "attempt_id", - "attempt_state" - ], - "properties": { - "call_id": { - "$ref": "#/$defs/id" - }, - "execution_id": { - "$ref": "#/$defs/id" - }, - "task_id": { - "$ref": "#/$defs/id" - }, - "task_item_id": { - "$ref": "#/$defs/id" - }, - "call_state": { - "enum": [ - "queued", - "dialing", - "ringing", - "answered", - "ended" - ] - }, - "call_version": { - "type": "integer", - "minimum": 1 - }, - "attempt_id": { - "$ref": "#/$defs/id" - }, - "attempt_state": { - "enum": [ - "pending", - "active", - "ended", - "unknown" - ] - }, - "route_policy_id": { - "$ref": "#/$defs/id" - }, - "caller_profile_id": { - "$ref": "#/$defs/id" - }, - "trunk_id": { - "$ref": "#/$defs/id" - }, - "cell_id": { - "$ref": "#/$defs/id" - }, - "egress_pool_id": { - "$ref": "#/$defs/id" - }, - "observed_at": { - "type": "string", - "format": "date-time" - }, - "reason_code": { - "type": "string", - "maxLength": 128 - } - } - }, - "transcript_updated": { - "type": "object", - "additionalProperties": false, - "required": [ - "call_id", - "turn_id", - "segment_id", - "role", - "revision", - "text", - "is_final", - "start_ms", - "end_ms", - "playback_state" - ], - "properties": { - "call_id": { - "$ref": "#/$defs/id" - }, - "execution_id": { - "$ref": "#/$defs/id" - }, - "turn_id": { - "$ref": "#/$defs/id" - }, - "segment_id": { - "$ref": "#/$defs/id" - }, - "role": { - "enum": [ - "customer", - "agent", - "system" - ] - }, - "revision": { - "type": "integer", - "minimum": 1 - }, - "text": { - "type": "string", - "maxLength": 32768 - }, - "is_final": { - "type": "boolean" - }, - "start_ms": { - "type": "integer", - "minimum": 0 - }, - "end_ms": { - "type": "integer", - "minimum": 0 - }, - "playback_state": { - "enum": [ - "not_applicable", - "generated", - "sent", - "playback_confirmed", - "cancelled", - "unknown" - ] - } - } - }, - "call_finished": { - "type": "object", - "additionalProperties": false, - "required": [ - "call_id", - "execution_id", - "call_version", - "outcome", - "started_at", - "ended_at", - "duration_ms", - "reason_code" - ], - "properties": { - "call_id": { - "$ref": "#/$defs/id" - }, - "execution_id": { - "$ref": "#/$defs/id" - }, - "task_id": { - "$ref": "#/$defs/id" - }, - "task_item_id": { - "$ref": "#/$defs/id" - }, - "call_version": { - "type": "integer", - "minimum": 1 - }, - "outcome": { - "enum": [ - "answered", - "no_answer", - "busy", - "failed", - "opt_out", - "cancelled", - "unknown" - ] - }, - "started_at": { - "type": "string", - "format": "date-time" - }, - "ended_at": { - "type": "string", - "format": "date-time" - }, - "duration_ms": { - "type": "integer", - "minimum": 0 - }, - "reason_code": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "attempt_summary": { - "type": "array", - "maxItems": 32, - "items": { - "$ref": "#/$defs/attempt_summary" - } - }, - "asset_state": { - "enum": [ - "pending", - "complete", - "failed", - "unknown" - ] - } - } - }, - "attempt_summary": { - "type": "object", - "additionalProperties": false, - "required": [ - "attempt_id", - "state" - ], - "properties": { - "attempt_id": { - "$ref": "#/$defs/id" - }, - "state": { - "enum": [ - "pending", - "active", - "ended", - "unknown" - ] - }, - "trunk_id": { - "$ref": "#/$defs/id" - }, - "cell_id": { - "$ref": "#/$defs/id" - }, - "reason_code": { - "type": "string", - "maxLength": 128 - } - } - }, - "recording_failed": { - "type": "object", - "additionalProperties": false, - "required": [ - "call_id", - "recording_id", - "stage", - "reason_code", - "retryable" - ], - "properties": { - "call_id": { - "$ref": "#/$defs/id" - }, - "recording_id": { - "$ref": "#/$defs/id" - }, - "stage": { - "enum": [ - "seal", - "request", - "upload", - "complete", - "verify", - "cleanup" - ] - }, - "reason_code": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "retryable": { - "type": "boolean" - }, - "next_retry_at": { - "type": "string", - "format": "date-time" - } - } - }, - "transcript_failed": { - "type": "object", - "additionalProperties": false, - "required": [ - "call_id", - "reason_code", - "retryable" - ], - "properties": { - "call_id": { - "$ref": "#/$defs/id" - }, - "reason_code": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "retryable": { - "type": "boolean" - }, - "segment_id": { - "$ref": "#/$defs/id" - }, - "affected_segments": { - "type": "array", - "maxItems": 256, - "items": { - "$ref": "#/$defs/id" - } - } - } - }, - "contact_opt_out": { - "type": "object", - "additionalProperties": false, - "required": [ - "call_id", - "task_id", - "task_item_id", - "requested_at" - ], - "properties": { - "call_id": { - "$ref": "#/$defs/id" - }, - "task_id": { - "$ref": "#/$defs/id" - }, - "task_item_id": { - "$ref": "#/$defs/id" - }, - "requested_at": { - "type": "string", - "format": "date-time" - }, - "turn_id": { - "$ref": "#/$defs/id" - }, - "segment_id": { - "$ref": "#/$defs/id" - } - } - }, - "recording_uploaded": { - "type": "object", - "additionalProperties": false, - "required": [ - "call_id", - "recording_id", - "format", - "channels", - "sample_rate_hz", - "duration_ms", - "size_bytes", - "checksum_sha256", - "upload_id", - "bucket", - "object_key" - ], - "properties": { - "call_id": { - "$ref": "#/$defs/id" - }, - "recording_id": { - "$ref": "#/$defs/id" - }, - "format": { - "enum": [ - "wav", - "raw_pcm", - "pcma" - ] - }, - "channels": { - "const": 1 - }, - "sample_rate_hz": { - "type": "integer", - "minimum": 8000, - "maximum": 48000 - }, - "duration_ms": { - "type": "integer", - "minimum": 0 - }, - "size_bytes": { - "type": "integer", - "minimum": 1 - }, - "checksum_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "upload_id": { - "$ref": "#/$defs/id" - }, - "bucket": { - "type": "string", - "minLength": 1, - "maxLength": 63 - }, - "object_key": { - "type": "string", - "minLength": 1, - "maxLength": 1024 - } - } - } - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/ai-config-request.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/ai-config-request.json deleted file mode 100644 index e80178b..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/ai-config-request.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "message_id": "ai.config.request-a", - "message_type": "ai.config.request", - "not_after": "2026-09-21T00:00:30Z", - "payload": { - "agent_version_id": "version-a" - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/ai-config-result.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/ai-config-result.json deleted file mode 100644 index a7fda1f..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/ai-config-result.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "message_id": "ai-config-reply-a", - "message_type": "ai.config.result", - "correlation_id": "ai.config.request-a", - "status": "ok", - "reason_code": "ok", - "payload": { - "snapshot": { - "tenant_id": "tenant-a", - "agent_version_id": "version-a", - "status": "published", - "immutable": true, - "content_sha256": "5f7a7531839338c0a0a9b8f8f5329c2f5d1aaa6e42d11bdd25446294b119ee8e", - "config": { - "agent_version_id": "version-a", - "immutable": true, - "mode": "full_ai", - "llm": { - "provider_ref": "mock", - "model": "mock-chat-v1", - "temperature": 0.2, - "max_tokens": 256, - "timeout_ms": 5000 - }, - "prompt": { - "text": "You are a concise telephone assistant. Answer the caller's last statement.", - "allowed_variables": [], - "max_bytes": 32768 - }, - "tts": { - "provider_ref": "mock", - "model": "mock-tts-v1", - "voice": "mock-neutral", - "speed": 1.0, - "format": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1 - }, - "timeout_ms": 5000 - }, - "asr": { - "provider_ref": "mock", - "language": "zh-CN", - "input": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1, - "sample_width_bytes": 2 - }, - "interim": true, - "timeout_ms": 5000 - }, - "conversation": { - "opening": "", - "allow_interrupt": true, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } - } - }, - "authorization": { - "authorization_id": "auth-1", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "agent_version_id": "version-a", - "config_sha256": "5f7a7531839338c0a0a9b8f8f5329c2f5d1aaa6e42d11bdd25446294b119ee8e", - "mode": "full_ai", - "issued_at": "2026-09-18T00:00:00Z", - "expires_at": "2026-09-18T00:01:00Z", - "source": "mock-saas", - "credential_refs": { - "asr": "mock-asr-credential" - }, - "allowed_egress_pool_ids": [ - "egress-mock" - ], - "revoked": false - } - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-execute.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-execute.json deleted file mode 100644 index 1adfb12..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-execute.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "command_id": "command-a", - "command_type": "call.execute", - "not_after": "2026-09-21T00:00:30Z", - "payload": { - "execution_id": "execution-a", - "task_id": "task-a", - "task_item_id": "item-a", - "task_revision": 1, - "callee": "15003164745", - "route_policy_id": "route-a", - "caller_profile_id": "caller-a", - "agent_version_id": "version-a", - "variables": {}, - "ring_timeout_ms": 1000, - "max_call_duration_ms": 10000 - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-query-result.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-query-result.json deleted file mode 100644 index 163514b..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-query-result.json +++ /dev/null @@ -1,157 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "message_id": "call-query-reply-a", - "message_type": "call.query.result", - "correlation_id": "call.query-a", - "status": "ok", - "reason_code": "ok", - "payload": { - "call_id": "call-a", - "execution_id": "execution-1", - "call_state": "answered", - "call_version": 1, - "attempts": [ - { - "schema_version": "2.0", - "event_id": "call.status-event-a", - "event_type": "call.status", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:01Z", - "aggregate_type": "call", - "aggregate_id": "call-a", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "execution_id": "execution-1", - "task_id": "task-1", - "task_item_id": "item-1", - "call_state": "answered", - "call_version": 1, - "attempt_id": "attempt-1", - "attempt_state": "active", - "route_policy_id": "route-1", - "caller_profile_id": "caller-1", - "trunk_id": "trunk-1", - "cell_id": "cell-1", - "egress_pool_id": "egress-1", - "observed_at": "2026-09-18T00:00:01Z" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" - } - ], - "transcript": { - "events": [ - { - "schema_version": "2.0", - "event_id": "transcript.updated-event-a", - "event_type": "transcript.updated", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:01Z", - "aggregate_type": "transcript_segment", - "aggregate_id": "segment-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "turn_id": "turn-1", - "segment_id": "segment-1", - "role": "customer", - "revision": 1, - "text": "您好", - "is_final": true, - "start_ms": 0, - "end_ms": 600, - "playback_state": "not_applicable" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" - }, - { - "schema_version": "2.0", - "event_id": "transcript.failed-event-a", - "event_type": "transcript.failed", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:05Z", - "aggregate_type": "transcript", - "aggregate_id": "call-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "reason_code": "asr_timeout", - "retryable": false, - "segment_id": "segment-1", - "affected_segments": [ - "segment-1" - ] - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" - } - ] - }, - "recordings": [ - { - "schema_version": "2.0", - "event_id": "recording.uploaded-event-a", - "event_type": "recording.uploaded", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:02Z", - "aggregate_type": "recording", - "aggregate_id": "recording-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "recording_id": "recording-1", - "format": "wav", - "channels": 1, - "sample_rate_hz": 16000, - "duration_ms": 1000, - "size_bytes": 32000, - "checksum_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "upload_id": "upload-a", - "bucket": "example-bucket", - "object_key": "recordings/recording-a.wav" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" - }, - { - "schema_version": "2.0", - "event_id": "recording.failed-event-a", - "event_type": "recording.failed", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:04Z", - "aggregate_type": "recording", - "aggregate_id": "recording-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "recording_id": "recording-1", - "stage": "upload", - "reason_code": "temporary_oss_unavailable", - "retryable": true, - "next_retry_at": "2026-09-18T00:01:00Z" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" - } - ], - "delivery": { - "pending": 1, - "retry": 0, - "dispatching": 0, - "published": 0 - }, - "snapshot_at": "2026-09-21T00:00:00Z" - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-query.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-query.json deleted file mode 100644 index 5859a0e..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-query.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "message_id": "call.query-a", - "message_type": "call.query", - "not_after": "2026-09-21T00:00:30Z", - "payload": { - "call_id": "call-a" - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-replay.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-replay.json deleted file mode 100644 index 04e9eec..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/call-replay.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "command_id": "call.replay-a", - "command_type": "call.replay", - "not_after": "2026-09-21T00:00:30Z", - "payload": { - "call_id": "call-a", - "reason": "local-test" - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/command-query-result.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/command-query-result.json deleted file mode 100644 index 3c0daaf..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/command-query-result.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "message_id": "query-reply-a", - "message_type": "command.query.result", - "correlation_id": "command.query-a", - "status": "ok", - "reason_code": "ok", - "payload": { - "command_id": "command-a", - "command_type": "call.execute", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "status": "accepted", - "aggregate_version": 1 - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/command-query.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/command-query.json deleted file mode 100644 index 365fde9..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/command-query.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "message_id": "command.query-a", - "message_type": "command.query", - "not_after": "2026-09-21T00:00:30Z", - "payload": { - "command_id": "command-a" - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/command-replay.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/command-replay.json deleted file mode 100644 index aa6f503..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/command-replay.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "command_id": "command.replay-a", - "command_type": "command.replay", - "not_after": "2026-09-21T00:00:30Z", - "payload": { - "source_command_id": "command-a", - "reason": "local-test" - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/dispatcher-config.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/dispatcher-config.json deleted file mode 100644 index f60820c..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/dispatcher-config.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "schema_version": "1.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "oss": { - "endpoint": "https://oss.example.invalid", - "region": "example-region", - "bucket": "example-bucket", - "object_prefix": "recordings", - "access_key_id_env": "DISPATCHER_OSS_ACCESS_KEY_ID", - "access_key_secret_env": "DISPATCHER_OSS_ACCESS_KEY_SECRET" - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-call-finished.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-call-finished.json deleted file mode 100644 index c1b6ac7..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-call-finished.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "schema_version": "2.0", - "event_id": "call.finished-event-a", - "event_type": "call.finished", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:03Z", - "aggregate_type": "call", - "aggregate_id": "call-a", - "aggregate_version": 2, - "payload": { - "call_id": "call-a", - "execution_id": "execution-1", - "task_id": "task-1", - "task_item_id": "item-1", - "call_version": 1, - "outcome": "answered", - "started_at": "2026-09-18T00:00:00Z", - "ended_at": "2026-09-18T00:00:03Z", - "duration_ms": 3000, - "reason_code": "normal_clearing", - "asset_state": "complete", - "attempt_summary": [ - { - "attempt_id": "attempt-1", - "state": "ended", - "trunk_id": "trunk-1", - "cell_id": "cell-1" - } - ] - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-call-status.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-call-status.json deleted file mode 100644 index 3c6ba28..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-call-status.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "schema_version": "2.0", - "event_id": "call.status-event-a", - "event_type": "call.status", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:01Z", - "aggregate_type": "call", - "aggregate_id": "call-a", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "execution_id": "execution-1", - "task_id": "task-1", - "task_item_id": "item-1", - "call_state": "answered", - "call_version": 1, - "attempt_id": "attempt-1", - "attempt_state": "active", - "route_policy_id": "route-1", - "caller_profile_id": "caller-1", - "trunk_id": "trunk-1", - "cell_id": "cell-1", - "egress_pool_id": "egress-1", - "observed_at": "2026-09-18T00:00:01Z" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-command-result.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-command-result.json deleted file mode 100644 index 3f6c279..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-command-result.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "schema_version": "2.0", - "event_id": "command.result-event-a", - "event_type": "command.result", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:00Z", - "aggregate_type": "command", - "aggregate_id": "command-1", - "aggregate_version": 1, - "payload": { - "command_id": "command-1", - "command_type": "call.execute", - "status": "accepted", - "reason_code": "accepted", - "execution_id": "execution-1" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-contact-opt-out.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-contact-opt-out.json deleted file mode 100644 index a0bc4cd..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-contact-opt-out.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "schema_version": "2.0", - "event_id": "contact.opt_out-event-a", - "event_type": "contact.opt_out", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:06Z", - "aggregate_type": "contact", - "aggregate_id": "contact-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "task_id": "task-1", - "task_item_id": "item-1", - "requested_at": "2026-09-18T00:00:06Z", - "turn_id": "turn-1", - "segment_id": "segment-1" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-recording-failed.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-recording-failed.json deleted file mode 100644 index 8bbd601..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-recording-failed.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "schema_version": "2.0", - "event_id": "recording.failed-event-a", - "event_type": "recording.failed", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:04Z", - "aggregate_type": "recording", - "aggregate_id": "recording-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "recording_id": "recording-1", - "stage": "upload", - "reason_code": "temporary_oss_unavailable", - "retryable": true, - "next_retry_at": "2026-09-18T00:01:00Z" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-recording-uploaded.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-recording-uploaded.json deleted file mode 100644 index 38aff36..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-recording-uploaded.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "schema_version": "2.0", - "event_id": "recording.uploaded-event-a", - "event_type": "recording.uploaded", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:02Z", - "aggregate_type": "recording", - "aggregate_id": "recording-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "recording_id": "recording-1", - "format": "wav", - "channels": 1, - "sample_rate_hz": 16000, - "duration_ms": 1000, - "size_bytes": 32000, - "checksum_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "upload_id": "upload-a", - "bucket": "example-bucket", - "object_key": "recordings/recording-a.wav" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-transcript-failed.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-transcript-failed.json deleted file mode 100644 index 4f8084c..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-transcript-failed.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "schema_version": "2.0", - "event_id": "transcript.failed-event-a", - "event_type": "transcript.failed", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:05Z", - "aggregate_type": "transcript", - "aggregate_id": "call-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "reason_code": "asr_timeout", - "retryable": false, - "segment_id": "segment-1", - "affected_segments": [ - "segment-1" - ] - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-transcript-updated.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-transcript-updated.json deleted file mode 100644 index b08f673..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/event-transcript-updated.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "schema_version": "2.0", - "event_id": "transcript.updated-event-a", - "event_type": "transcript.updated", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:01Z", - "aggregate_type": "transcript_segment", - "aggregate_id": "segment-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "turn_id": "turn-1", - "segment_id": "segment-1", - "role": "customer", - "revision": 1, - "text": "您好", - "is_final": true, - "start_ms": 0, - "end_ms": 600, - "playback_state": "not_applicable" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-call-query-extra.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-call-query-extra.json deleted file mode 100644 index 36b1de9..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-call-query-extra.json +++ /dev/null @@ -1,158 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "message_id": "query-reply-a", - "message_type": "call.query.result", - "correlation_id": "command.query-a", - "status": "ok", - "reason_code": "ok", - "payload": { - "call_id": "call-a", - "execution_id": "execution-1", - "call_state": "answered", - "call_version": 1, - "attempts": [ - { - "schema_version": "2.0", - "event_id": "call.status-event-a", - "event_type": "call.status", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:01Z", - "aggregate_type": "call", - "aggregate_id": "call-a", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "execution_id": "execution-1", - "task_id": "task-1", - "task_item_id": "item-1", - "call_state": "answered", - "call_version": 1, - "attempt_id": "attempt-1", - "attempt_state": "active", - "route_policy_id": "route-1", - "caller_profile_id": "caller-1", - "trunk_id": "trunk-1", - "cell_id": "cell-1", - "egress_pool_id": "egress-1", - "observed_at": "2026-09-18T00:00:01Z" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" - } - ], - "transcript": { - "events": [ - { - "schema_version": "2.0", - "event_id": "transcript.updated-event-a", - "event_type": "transcript.updated", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:01Z", - "aggregate_type": "transcript_segment", - "aggregate_id": "segment-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "turn_id": "turn-1", - "segment_id": "segment-1", - "role": "customer", - "revision": 1, - "text": "您好", - "is_final": true, - "start_ms": 0, - "end_ms": 600, - "playback_state": "not_applicable" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" - }, - { - "schema_version": "2.0", - "event_id": "transcript.failed-event-a", - "event_type": "transcript.failed", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:05Z", - "aggregate_type": "transcript", - "aggregate_id": "call-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "reason_code": "asr_timeout", - "retryable": false, - "segment_id": "segment-1", - "affected_segments": [ - "segment-1" - ] - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" - } - ] - }, - "recordings": [ - { - "schema_version": "2.0", - "event_id": "recording.uploaded-event-a", - "event_type": "recording.uploaded", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:02Z", - "aggregate_type": "recording", - "aggregate_id": "recording-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "recording_id": "recording-1", - "format": "wav", - "channels": 1, - "sample_rate_hz": 16000, - "duration_ms": 1000, - "size_bytes": 32000, - "checksum_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - "upload_id": "upload-a", - "bucket": "example-bucket", - "object_key": "recordings/recording-a.wav" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" - }, - { - "schema_version": "2.0", - "event_id": "recording.failed-event-a", - "event_type": "recording.failed", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-1", - "occurred_at": "2026-09-18T00:00:04Z", - "aggregate_type": "recording", - "aggregate_id": "recording-1", - "aggregate_version": 1, - "payload": { - "call_id": "call-a", - "recording_id": "recording-1", - "stage": "upload", - "reason_code": "temporary_oss_unavailable", - "retryable": true, - "next_retry_at": "2026-09-18T00:01:00Z" - }, - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6" - } - ], - "delivery": { - "pending": 1, - "retry": 0, - "dispatching": 0, - "published": 0, - "raw": {} - }, - "snapshot_at": "2026-09-21T00:00:00Z" - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-correlation.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-correlation.json deleted file mode 100644 index 4c9d94f..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-correlation.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "message_id": "query-reply-a", - "message_type": "command.query.result", - "status": "ok", - "reason_code": "ok", - "payload": { - "command_id": "command-a", - "command_type": "call.execute", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "status": "accepted", - "aggregate_version": 1 - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-dispatcher.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-dispatcher.json deleted file mode 100644 index f60819b..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-dispatcher.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "dispatcher-a", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "command_id": "command-a", - "command_type": "call.execute", - "not_after": "2026-09-21T00:00:30Z", - "payload": { - "execution_id": "execution-a", - "task_id": "task-a", - "task_item_id": "item-a", - "task_revision": 1, - "callee": "15003164745", - "route_policy_id": "route-a", - "caller_profile_id": "caller-a", - "agent_version_id": "version-a", - "variables": {}, - "ring_timeout_ms": 1000, - "max_call_duration_ms": 10000 - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-v1.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-v1.json deleted file mode 100644 index 7757e3d..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-v1.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "schema_version": "1.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "command_id": "command-a", - "command_type": "call.execute", - "not_after": "2026-09-21T00:00:30Z", - "payload": { - "execution_id": "execution-a", - "task_id": "task-a", - "task_item_id": "item-a", - "task_revision": 1, - "callee": "15003164745", - "route_policy_id": "route-a", - "caller_profile_id": "caller-a", - "agent_version_id": "version-a", - "variables": {}, - "ring_timeout_ms": 1000, - "max_call_duration_ms": 10000 - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-wildcard.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-wildcard.json deleted file mode 100644 index b31d0f0..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/invalid-wildcard.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant.#", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "command_id": "command-a", - "command_type": "call.execute", - "not_after": "2026-09-21T00:00:30Z", - "payload": { - "execution_id": "execution-a", - "task_id": "task-a", - "task_item_id": "item-a", - "task_revision": 1, - "callee": "15003164745", - "route_policy_id": "route-a", - "caller_profile_id": "caller-a", - "agent_version_id": "version-a", - "variables": {}, - "ring_timeout_ms": 1000, - "max_call_duration_ms": 10000 - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/query-pending.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/query-pending.json deleted file mode 100644 index 7e7afb3..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/query-pending.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "message_id": "query-reply-a", - "message_type": "command.query.result", - "correlation_id": "command.query-a", - "status": "pending", - "reason_code": "waiting", - "payload": {} -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/query-rejected.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/query-rejected.json deleted file mode 100644 index 15dc9d8..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/query-rejected.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "message_id": "query-reply-a", - "message_type": "command.query.result", - "correlation_id": "command.query-a", - "status": "rejected", - "reason_code": "not_found", - "payload": { - "detail": "command not found", - "retryable": false - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/examples/task-control.json b/contracts/archive/upstream/2026-09-21-p1-v2/examples/task-control.json deleted file mode 100644 index 63bf5a6..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/examples/task-control.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "schema_version": "2.0", - "dispatcher_id": "c046b893-8628-4589-ae50-619d049248a6", - "tenant_id": "tenant-a", - "tenant_key": "tenant-a", - "trace_id": "trace-v2", - "issued_at": "2026-09-21T00:00:00Z", - "command_id": "task.control-a", - "command_type": "task.control", - "not_after": "2026-09-21T00:00:30Z", - "payload": { - "task_id": "task-a", - "action": "pause", - "expected_task_revision": 1, - "active_call_policy": "drain", - "reason": "local-test" - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/fixtures.json b/contracts/archive/upstream/2026-09-21-p1-v2/fixtures.json deleted file mode 100644 index aaa94cc..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/fixtures.json +++ /dev/null @@ -1,132 +0,0 @@ -[ - { - "file": "examples/call-execute.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/task-control.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/call-replay.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/command-replay.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/command-query.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/call-query.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/ai-config-request.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/query-pending.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/query-rejected.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/dispatcher-config.json", - "schema": "dispatcher-config.schema.json", - "valid": true - }, - { - "file": "examples/invalid-v1.json", - "schema": "mq.schema.json", - "valid": false - }, - { - "file": "examples/invalid-wildcard.json", - "schema": "mq.schema.json", - "valid": false - }, - { - "file": "examples/invalid-dispatcher.json", - "schema": "mq.schema.json", - "valid": false - }, - { - "file": "examples/event-call-finished.json", - "schema": "event-payloads.schema.json", - "valid": true - }, - { - "file": "examples/event-call-status.json", - "schema": "event-payloads.schema.json", - "valid": true - }, - { - "file": "examples/event-command-result.json", - "schema": "event-payloads.schema.json", - "valid": true - }, - { - "file": "examples/event-contact-opt-out.json", - "schema": "event-payloads.schema.json", - "valid": true - }, - { - "file": "examples/event-recording-failed.json", - "schema": "event-payloads.schema.json", - "valid": true - }, - { - "file": "examples/event-recording-uploaded.json", - "schema": "event-payloads.schema.json", - "valid": true - }, - { - "file": "examples/event-transcript-failed.json", - "schema": "event-payloads.schema.json", - "valid": true - }, - { - "file": "examples/event-transcript-updated.json", - "schema": "event-payloads.schema.json", - "valid": true - }, - { - "file": "examples/command-query-result.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/invalid-correlation.json", - "schema": "mq.schema.json", - "valid": false - }, - { - "file": "examples/call-query-result.json", - "schema": "mq.schema.json", - "valid": true - }, - { - "file": "examples/invalid-call-query-extra.json", - "schema": "mq.schema.json", - "valid": false - }, - { - "file": "examples/ai-config-result.json", - "schema": "mq.schema.json", - "valid": true - } -] diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/manifest.json b/contracts/archive/upstream/2026-09-21-p1-v2/manifest.json deleted file mode 100644 index 11160d1..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/manifest.json +++ /dev/null @@ -1,86 +0,0 @@ -{ - "version": "2026-09-21-p1-v2", - "source": "project-approved-mq-only-v2", - "derived_from": "2026-09-19-p1-v1", - "source_files": { - "README.md": "3332e4c71021189b03f3031106c08b3c9c08eb2f9bb1a4f4b0a96fe1598ceaba", - "SNAPSHOT.json": "a41adc5ec329a9010cc45d08f309eb3620e0d6311a5c565a9f26a35ffc4ecb42", - "ai-authorization.schema.json": "5d6bbd369bd6b406abe9b9f8619e6f299b544dacfdd4473a08257a366fd95d20", - "ai-config.openapi.yaml": "d2f75d8fd2bf76ceb4eef869a838f08dca156938e1f3025d126ce81e436f624a", - "ai-config.schema.json": "dc915bff70e71408fcacbaad47d3554bbfa7a22a51f2f53e127c6bd8bc8ba5a6", - "cell-agent.openapi.yaml": "79dc697d7ce16e2a6aa7e350f30dd006dd847afe2cdc0ea29841f9c6d4310c41", - "event-payloads.schema.json": "5091ded520d692f458699327b13adddeccb0c4b4d4a72ef7cdfebcd5d496eade", - "examples/README.md": "a3514c7ef89b4324685bc9025139488000fa42330de72495484add042a6897cf", - "examples/agent-version-asr-only.json": "24864df1fd72a59efaaaf6d1fc81a0c7db01fbdfcd821aab4069b64a8db9b60b", - "examples/agent-version-full-explicit.json": "e590148448885a1e88c473ca032d5efd719270689c3cff7aa44ca9c6ffa2b321", - "examples/agent-version-full-production-v1.json": "6a5f35f8cc4256c048d4f1ca567a3544ea7bc92bb835cfab39a000d22b73102b", - "examples/agent-version.json": "d3d4bf2fae07192674e54bf32172a8e95146f11d70609f3cd8f57f0112633c2e", - "examples/ai-authorization.json": "b1c0f723f083d1be45035792482f6f74bd3bca34486cc6408d4bcfe3772bc432", - "examples/call.execute.json": "0164664fd3503d72668b24bdecb623aa0414ce58191960b868abe8454988c742", - "examples/event-call-finished.json": "fab56aff9c5d4059b8fa65d24f2afa424148e7a07025238fc7fd30e9c5ee63f4", - "examples/event-call-status.json": "5c673ceb4a98ce8c90d976356b4c5ffa6c7d96d045b5b3312513a9be93d585ba", - "examples/event-command-result.json": "64fe71719573378b0caac2f7c5476a27ba7073df8c346d4748a6b0d534d4a087", - "examples/event-contact-opt-out.json": "b661f65f0a195e59fe226b12ebae2feb5a9733a9a779c835245be27319aaf8f2", - "examples/event-recording-failed.json": "4f5f46422d2281ffae65c99e947bc7dd44effb5e94eacc12e41b3250ac645c34", - "examples/event-recording-ready.json": "2b6d731a8d7993cbbe07a5ba8c7413ec56bae8a1538476c0f1740133a488d5b4", - "examples/event-transcript-failed.json": "58d000ce27de6e67054f66d4ded34ffafa983bdcced12613051f670d1eefeed8", - "examples/event-transcript-updated.json": "115f276522631d7c4decee71ee238aa0d00b4256adedfc9a6a0c5f9dc89f64f6", - "examples/invalid-ai-authorization-revoked.json": "0b946b43c1f773391791dfb60a2b2a03c8a69e64e5e9ea30af8591850c34b8f3", - "examples/invalid-asr-only-with-llm.json": "7343ce8d6ce63e22128ab7bc721544d681a5dd9eccfc4ab4f9d6181c5748824c", - "examples/invalid-event-unknown-type.json": "80c3f89dc775deec9d1a3b85c81ea4b2fd1b030bc4deba1a4dcd2823e4eb8024", - "examples/invalid-oss-upload-http.json": "8e4fb4344c4bec51b47ff9b00a63afdc84d09ab827e1b6823c4e576bf6b6a3f1", - "examples/oss-upload-grant.json": "268751a1a0d238636c04c004a635e3bda702bc2ef90ade0e5846b47a3c263b5d", - "examples/static-cell-artifact-real-v1.json": "b4a001457e747a039677870a3ddeccc902b8f87819c3ce2d2e37ae6a14f1ffe0", - "examples/static-cell-artifact.json": "129821e4de654ef12d3e7f155e9301ecddf798f9ca3399316a20a55273fbc61f", - "executor.openapi.yaml": "b24703783df63e044fc0151c5e215430d2294e13937d2a5ceee3c6fee99b0329", - "mock-profile.json": "4d43097602fed9a68821e765117580706896ac82d4bce361a80a4cea544ab638", - "mq-topology.md": "a85b26596e1b1db7405dcabc967df56d5eb6713cc9908bc05ecaa2075ff1092f", - "mq.schema.json": "4fbfc39d46fb55ca48b71bc11cafce60e0814182ba4f898973c7c4d7657f912a", - "oss-upload.schema.json": "d3f6ffc5e004fba8acbb6a18495be508a63ec45766bab1ef946ece58bbad84de", - "p1-development-profile.json": "2aa7cd3f4fa07f7e1a3037107fa7a56183f28370ea06a2a9b8dc18c8790eee2d", - "p1-development-profile.schema.json": "68e1b46194a1f5fa5bc763ba424411f48ada1ab52d39e6f800315a832692794b", - "release-manifest.json": "251127dfbb8fe60da58312c9785bc7eafa4135ef91f241a8e07c3868a30e123a", - "saas.openapi.yaml": "368c3a7d75ecc74771b88f9bd9fb7131697c69ce695475fc5aaae6099ff889eb", - "sip-management.openapi.yaml": "5006bbb1fb69f7b4a05cbaa5a43f8944e8522172910a41aba61897c9d5e00281", - "static-cell-artifact.schema.json": "46333f6a161ebbfd42f4a326e2509d562164fe836e6d1c88368428795362138d" - }, - "files": { - "README.md": "3ca0606a76cd63d411e4ad4ec9b3334b7e62f9bda63653620584e29e57894979", - "ai-authorization.schema.json": "d954218b1d8c6f3a8d83e959425ed6cab0f63593d18b4876a5cd374c9cf1ded6", - "ai-config.schema.json": "62a5205b00c287e9ea14b9ce2e681d7945a2cd1f5fb0d4809c2d0ec76a009486", - "dispatcher-config.schema.json": "37bf6d4636005e49bb60a016c1045325ae9799b8ce58d2a601f889961a78a73c", - "event-payloads.schema.json": "e24869dfc946e20847d37e6f13c5ce1312dc3db8c5c7e1b1794422358df87e65", - "examples/ai-config-request.json": "d6fba0382ccbac1e1585052326e9a393d941ee7d1e96cce19ece462a92c7e374", - "examples/ai-config-result.json": "e93474304ef5d7785dd56ac83823d45846f94d54c7047ee8672190eccf8cb90d", - "examples/call-execute.json": "b96a7ab2eed238b0c8c1d9534a8932955819e32b7e5d0e554fad076c3c3a4b7a", - "examples/call-query-result.json": "07bfe067e56138964f2708c1860ab57c22b06567a8d633d21d6057d2a0004004", - "examples/call-query.json": "3a1f2af373a8504da32f3a113ae7a033eaeeb50dbcee5836d2042026ffc63902", - "examples/call-replay.json": "74bdc281b27bb6513f8199455149545a9ed446a59cba1e3463db2e58884cbe0d", - "examples/command-query-result.json": "34e533bd6f07c8f72f79964f7637dc39052f8ba0dc16f3b4dcf11aeff4f898b3", - "examples/command-query.json": "76392b74382d8dfb02b987c8b2a6e8b9a56c5311557557579756e507ddb48d04", - "examples/command-replay.json": "a885310aebddc6c0e579e32e328690795668ecfcf6a26990ab1f09b89e25bc5a", - "examples/dispatcher-config.json": "0432e3e4b758c9d049f40ed52581d48422a9e1a87c8f5a95590a26f8d7dae872", - "examples/event-call-finished.json": "206c9c95273012720800ec41ac5b4347ade4288b3c086c9f782d62e96b1eaef5", - "examples/event-call-status.json": "ed68df5d40efd8b71bc0cc00fd67c5e65d68a2580361ff3d464cdaf44af09013", - "examples/event-command-result.json": "21d86e11db96374f393126eb7bb1f7188609292d446bf322f521c15c8719a5b4", - "examples/event-contact-opt-out.json": "6b396965c33f5e284363d612bb5bf53dcdb3ec4b56eea26d6c89778ba471f57b", - "examples/event-recording-failed.json": "911086c4954474a5494b7054660629f22d1f10a21fe129091ec0609cc16616ef", - "examples/event-recording-uploaded.json": "3189da1e9966931b92aa5b9e13dab1f70d9abda1822e8c7772bcf04f24aa09f4", - "examples/event-transcript-failed.json": "56385f45b43394a6061853343600e4ebf5aa01d7b6d0ff23ea79628ebfecb308", - "examples/event-transcript-updated.json": "4747266786b1cbfdfe483e5c3c7c36c587eab710fd77eb7152b8172f1620ca3e", - "examples/invalid-call-query-extra.json": "d5baeaacf73f4fbe4d57b1fcb6a3ca8c82603d763ccd2882298a412f00cdeb1a", - "examples/invalid-correlation.json": "79051aeecb5b4726d3a392b72e2cf6d9b90a873e3a1c5065879721655a859d4d", - "examples/invalid-dispatcher.json": "1a98856bf3d50a783eab538b37b1b84bd98ac5acca57a4c271244f5fa90b50e9", - "examples/invalid-v1.json": "dc795727448254a97781ae163583a0bb776a6ebcc589b1330d018083886a4a09", - "examples/invalid-wildcard.json": "becd89c7d9ccfc2343417efa9d7502a629ca3a33ee8dae419a121dfa01cb7257", - "examples/query-pending.json": "a3c4102102d4652d2c1ffaefec88d7ea50f694ad37811d82a1dfbd0cd985ca11", - "examples/query-rejected.json": "6260c6dbb5748a8140106930ac03a5a59c4d2103a30c66239c234e39f4800a11", - "examples/task-control.json": "f5b5df31c7a5d332412472db26f99d49b1d3a9aabdeb05e8a6dea9c4c85e4089", - "fixtures.json": "103ff072caafeb8a0399dccb27bc0619068e9b35baf738054fdfb3c225135c78", - "mq-topology.json": "ade0f2dcf4247351db82ca7498941b925c832ef1ee6d546c5bf34a4921011c68", - "mq.schema.json": "dc212fa183efc90843e6180af49482502ad4445d2be234b910c3b2570010deb7", - "oss-upload.schema.json": "7e80b414d27d98e44cf755faeacc30e51612cf45c6edfa1d1e55f675b6bcd50c", - "p1-development-profile.schema.json": "e1a5504dd38cf7f7503fa59b894eac65a50e32f7ddac13694f7a92ef633a0bcd", - "static-cell-artifact.schema.json": "7ff58fcfc3d5911ea7444a6e86557410e94d8b395501940c379ef80040048630" - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/mq-topology.json b/contracts/archive/upstream/2026-09-21-p1-v2/mq-topology.json deleted file mode 100644 index c7344d1..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/mq-topology.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": "2.0", - "exchanges": { - "agent-call.dispatchers.v2": { - "type": "topic", - "durable": true - }, - "agent-call.saas.v2": { - "type": "topic", - "durable": true - }, - "agent-call.dead-letter.v2": { - "type": "topic", - "durable": true - } - }, - "inbox_queue": "agent-call.d..t..v2", - "dead_letter_queue": "agent-call.d..t..dlq.v2", - "inbound_key": "d..t..in", - "outbound_key": "d..t..out", - "saas_queue": "agent-call.saas.events.v2", - "owner_queue": "agent-call.d..owner.v2", - "owner_exclusive": true, - "business_queues_durable": true, - "message_persistent": true, - "publish_mandatory": true, - "publisher_confirms": true, - "tenant_key_max_utf8_bytes": 196, - "message_max_bytes": 262144, - "service_request_deadline_seconds": 30, - "upload_token_seconds": 900 -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/mq.schema.json b/contracts/archive/upstream/2026-09-21-p1-v2/mq.schema.json deleted file mode 100644 index 3081590..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/mq.schema.json +++ /dev/null @@ -1,956 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://go-sip.local/contracts/2026-09-21-p1-v2/mq.schema.json", - "title": "agent-call MQ command and event envelope", - "oneOf": [ - { - "$ref": "#/$defs/command" - }, - { - "$ref": "#/$defs/event" - }, - { - "$ref": "#/$defs/request" - }, - { - "$ref": "#/$defs/response" - } - ], - "$defs": { - "aiConfigResult": { - "type": "object", - "additionalProperties": false, - "required": [ - "snapshot", - "authorization" - ], - "properties": { - "snapshot": { - "$ref": "#/$defs/ai_AgentVersion" - }, - "authorization": { - "$ref": "ai-authorization.schema.json" - } - } - }, - "ai_AgentVersion": { - "type": "object", - "required": [ - "tenant_id", - "agent_version_id", - "status", - "immutable", - "content_sha256", - "config" - ], - "properties": { - "tenant_id": { - "type": "string" - }, - "agent_version_id": { - "type": "string" - }, - "status": { - "enum": [ - "published", - "reused" - ] - }, - "immutable": { - "const": true - }, - "content_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "config": { - "$ref": "ai-config.schema.json" - } - } - }, - "callReplay": { - "type": "object", - "additionalProperties": false, - "required": [ - "reason", - "call_id" - ], - "properties": { - "reason": { - "type": "string", - "minLength": 1, - "maxLength": 512 - }, - "call_id": { - "$ref": "#/$defs/id" - } - } - }, - "command": { - "type": "object", - "additionalProperties": false, - "required": [ - "schema_version", - "command_type", - "command_id", - "tenant_id", - "tenant_key", - "trace_id", - "issued_at", - "not_after", - "payload", - "dispatcher_id" - ], - "properties": { - "schema_version": { - "const": "2.0" - }, - "command_type": { - "enum": [ - "call.execute", - "task.control", - "call.replay", - "command.replay" - ] - }, - "command_id": { - "$ref": "#/$defs/id" - }, - "tenant_id": { - "$ref": "#/$defs/id" - }, - "tenant_key": { - "$ref": "#/$defs/tenantKey" - }, - "trace_id": { - "$ref": "#/$defs/id" - }, - "issued_at": { - "$ref": "#/$defs/time" - }, - "not_after": { - "$ref": "#/$defs/time" - }, - "payload": { - "type": "object" - }, - "dispatcher_id": { - "$ref": "#/$defs/dispatcherId" - } - }, - "allOf": [ - { - "if": { - "properties": { - "command_type": { - "const": "call.execute" - } - } - }, - "then": { - "properties": { - "payload": { - "$ref": "#/$defs/executePayload" - } - } - } - }, - { - "if": { - "properties": { - "command_type": { - "const": "task.control" - } - } - }, - "then": { - "properties": { - "payload": { - "$ref": "#/$defs/taskControl" - } - } - } - }, - { - "if": { - "properties": { - "command_type": { - "const": "call.replay" - } - } - }, - "then": { - "properties": { - "payload": { - "$ref": "#/$defs/callReplay" - } - } - } - }, - { - "if": { - "properties": { - "command_type": { - "const": "command.replay" - } - } - }, - "then": { - "properties": { - "payload": { - "$ref": "#/$defs/commandReplay" - } - } - } - } - ] - }, - "commandReplay": { - "type": "object", - "additionalProperties": false, - "required": [ - "reason", - "source_command_id" - ], - "properties": { - "reason": { - "type": "string", - "minLength": 1, - "maxLength": 512 - }, - "source_command_id": { - "$ref": "#/$defs/id" - } - } - }, - "dispatcherId": { - "type": "string", - "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$" - }, - "event": { - "$ref": "event-payloads.schema.json" - }, - "executePayload": { - "type": "object", - "additionalProperties": false, - "required": [ - "execution_id", - "task_id", - "task_item_id", - "task_revision", - "callee", - "route_policy_id", - "caller_profile_id", - "agent_version_id", - "variables", - "ring_timeout_ms", - "max_call_duration_ms" - ], - "properties": { - "execution_id": { - "$ref": "#/$defs/id" - }, - "task_id": { - "$ref": "#/$defs/id" - }, - "task_item_id": { - "$ref": "#/$defs/id" - }, - "task_revision": { - "type": "integer", - "minimum": 1 - }, - "callee": { - "type": "string", - "minLength": 1, - "maxLength": 256 - }, - "route_policy_id": { - "$ref": "#/$defs/id" - }, - "caller_profile_id": { - "$ref": "#/$defs/id" - }, - "agent_version_id": { - "$ref": "#/$defs/id" - }, - "variables": { - "type": "object", - "additionalProperties": true - }, - "ring_timeout_ms": { - "type": "integer", - "minimum": 1 - }, - "max_call_duration_ms": { - "type": "integer", - "minimum": 1 - } - } - }, - "executor_Call": { - "type": "object", - "required": [ - "call_id", - "execution_id", - "call_state", - "call_version", - "attempts", - "transcript", - "recordings", - "delivery", - "snapshot_at" - ], - "properties": { - "call_id": { - "type": "string" - }, - "execution_id": { - "type": "string" - }, - "task_id": { - "type": "string" - }, - "task_item_id": { - "type": "string" - }, - "call_state": { - "type": "string" - }, - "call_version": { - "type": "integer" - }, - "reason_code": { - "type": [ - "string", - "null" - ] - }, - "outcome": { - "type": [ - "string", - "null" - ] - }, - "started_at": { - "type": [ - "string", - "null" - ], - "format": "date-time" - }, - "ended_at": { - "type": [ - "string", - "null" - ], - "format": "date-time" - }, - "duration_ms": { - "type": [ - "integer", - "null" - ] - }, - "attempts": { - "type": "array", - "items": { - "allOf": [ - { - "$ref": "event-payloads.schema.json" - }, - { - "properties": { - "event_type": { - "enum": [ - "call.status" - ] - } - } - } - ] - } - }, - "transcript": { - "type": "object", - "additionalProperties": false, - "required": [ - "events" - ], - "properties": { - "events": { - "type": "array", - "items": { - "allOf": [ - { - "$ref": "event-payloads.schema.json" - }, - { - "properties": { - "event_type": { - "enum": [ - "transcript.updated", - "transcript.failed" - ] - } - } - } - ] - } - } - } - }, - "recordings": { - "type": "array", - "items": { - "allOf": [ - { - "$ref": "event-payloads.schema.json" - }, - { - "properties": { - "event_type": { - "enum": [ - "recording.uploaded", - "recording.failed" - ] - } - } - } - ] - } - }, - "delivery": { - "type": "object", - "additionalProperties": false, - "required": [ - "pending", - "retry", - "dispatching", - "published" - ], - "properties": { - "pending": { - "type": "integer", - "minimum": 0 - }, - "retry": { - "type": "integer", - "minimum": 0 - }, - "dispatching": { - "type": "integer", - "minimum": 0 - }, - "published": { - "type": "integer", - "minimum": 0 - } - } - }, - "snapshot_at": { - "type": "string", - "format": "date-time" - } - }, - "additionalProperties": false - }, - "executor_Command": { - "type": "object", - "required": [ - "command_id", - "command_type", - "tenant_id", - "tenant_key", - "status", - "aggregate_version" - ], - "properties": { - "command_id": { - "$ref": "#/$defs/executor_Id" - }, - "command_type": { - "type": "string" - }, - "tenant_id": { - "type": "string" - }, - "tenant_key": { - "type": "string" - }, - "task_id": { - "type": [ - "string", - "null" - ] - }, - "execution_id": { - "type": [ - "string", - "null" - ] - }, - "call_id": { - "type": [ - "string", - "null" - ] - }, - "status": { - "type": "string" - }, - "reason_code": { - "type": [ - "string", - "null" - ] - }, - "wait_reason_code": { - "type": [ - "string", - "null" - ] - }, - "accepted_at": { - "type": [ - "string", - "null" - ], - "format": "date-time" - }, - "waiting_since": { - "type": [ - "string", - "null" - ], - "format": "date-time" - }, - "admission_deadline": { - "type": [ - "string", - "null" - ], - "format": "date-time" - }, - "requested_task_revision": { - "type": [ - "integer", - "null" - ] - }, - "applied_task_revision": { - "type": [ - "integer", - "null" - ] - }, - "task_state": { - "type": [ - "string", - "null" - ] - }, - "updated_at": { - "type": "string", - "format": "date-time" - }, - "aggregate_version": { - "type": "integer", - "minimum": 1 - } - }, - "additionalProperties": false - }, - "executor_Id": { - "type": "string", - "minLength": 1, - "maxLength": 128, - "pattern": "^[^\\s/\\\\]+$" - }, - "id": { - "type": "string", - "minLength": 1, - "maxLength": 128, - "pattern": "^[^\\s/\\\\]+$" - }, - "request": { - "type": "object", - "additionalProperties": false, - "required": [ - "schema_version", - "message_type", - "message_id", - "dispatcher_id", - "tenant_id", - "tenant_key", - "trace_id", - "issued_at", - "not_after", - "payload" - ], - "properties": { - "schema_version": { - "const": "2.0" - }, - "message_type": { - "enum": [ - "command.query", - "call.query", - "ai.config.request" - ] - }, - "message_id": { - "$ref": "#/$defs/id" - }, - "dispatcher_id": { - "$ref": "#/$defs/dispatcherId" - }, - "tenant_id": { - "$ref": "#/$defs/id" - }, - "tenant_key": { - "$ref": "#/$defs/tenantKey" - }, - "trace_id": { - "$ref": "#/$defs/id" - }, - "issued_at": { - "type": "string", - "format": "date-time" - }, - "not_after": { - "type": "string", - "format": "date-time" - }, - "payload": { - "type": "object" - } - }, - "allOf": [ - { - "if": { - "properties": { - "message_type": { - "const": "command.query" - } - } - }, - "then": { - "properties": { - "payload": { - "type": "object", - "additionalProperties": false, - "required": [ - "command_id" - ], - "properties": { - "command_id": { - "$ref": "#/$defs/id" - } - } - } - } - } - }, - { - "if": { - "properties": { - "message_type": { - "const": "call.query" - } - } - }, - "then": { - "properties": { - "payload": { - "type": "object", - "additionalProperties": false, - "required": [ - "call_id" - ], - "properties": { - "call_id": { - "$ref": "#/$defs/id" - } - } - } - } - } - }, - { - "if": { - "properties": { - "message_type": { - "const": "ai.config.request" - } - } - }, - "then": { - "properties": { - "payload": { - "type": "object", - "additionalProperties": false, - "required": [ - "agent_version_id" - ], - "properties": { - "agent_version_id": { - "$ref": "#/$defs/id" - } - } - } - } - } - } - ] - }, - "response": { - "type": "object", - "additionalProperties": false, - "required": [ - "schema_version", - "message_type", - "message_id", - "dispatcher_id", - "tenant_id", - "tenant_key", - "trace_id", - "issued_at", - "correlation_id", - "status", - "reason_code", - "payload" - ], - "properties": { - "schema_version": { - "const": "2.0" - }, - "message_type": { - "enum": [ - "command.query.result", - "call.query.result", - "ai.config.result" - ] - }, - "message_id": { - "$ref": "#/$defs/id" - }, - "dispatcher_id": { - "$ref": "#/$defs/dispatcherId" - }, - "tenant_id": { - "$ref": "#/$defs/id" - }, - "tenant_key": { - "$ref": "#/$defs/tenantKey" - }, - "trace_id": { - "$ref": "#/$defs/id" - }, - "issued_at": { - "type": "string", - "format": "date-time" - }, - "correlation_id": { - "$ref": "#/$defs/id" - }, - "status": { - "enum": [ - "ok", - "pending", - "rejected" - ] - }, - "reason_code": { - "type": "string" - }, - "payload": { - "type": "object" - } - }, - "allOf": [ - { - "if": { - "properties": { - "status": { - "const": "pending" - } - } - }, - "then": { - "properties": { - "reason_code": { - "const": "waiting" - }, - "payload": { - "type": "object", - "additionalProperties": false, - "required": [], - "properties": {} - } - } - } - }, - { - "if": { - "properties": { - "status": { - "const": "rejected" - } - } - }, - "then": { - "properties": { - "reason_code": { - "enum": [ - "invalid_request", - "not_found", - "conflict", - "expired", - "not_authorized", - "unavailable", - "unsupported" - ] - }, - "payload": { - "type": "object", - "additionalProperties": false, - "required": [ - "detail", - "retryable" - ], - "properties": { - "detail": { - "type": "string", - "maxLength": 1024 - }, - "retryable": { - "type": "boolean" - } - } - } - } - } - }, - { - "if": { - "properties": { - "status": { - "const": "ok" - }, - "message_type": { - "const": "command.query.result" - } - } - }, - "then": { - "properties": { - "reason_code": { - "const": "ok" - }, - "payload": { - "$ref": "#/$defs/executor_Command" - } - } - } - }, - { - "if": { - "properties": { - "status": { - "const": "ok" - }, - "message_type": { - "const": "call.query.result" - } - } - }, - "then": { - "properties": { - "reason_code": { - "const": "ok" - }, - "payload": { - "$ref": "#/$defs/executor_Call" - } - } - } - }, - { - "if": { - "properties": { - "status": { - "const": "ok" - }, - "message_type": { - "const": "ai.config.result" - } - } - }, - "then": { - "properties": { - "reason_code": { - "const": "ok" - }, - "payload": { - "$ref": "#/$defs/aiConfigResult" - } - } - } - } - ] - }, - "taskControl": { - "type": "object", - "additionalProperties": false, - "required": [ - "action", - "expected_task_revision", - "reason", - "task_id" - ], - "properties": { - "action": { - "type": "string", - "enum": [ - "pause", - "resume", - "stop" - ] - }, - "expected_task_revision": { - "type": "integer", - "minimum": 1 - }, - "active_call_policy": { - "type": "string", - "enum": [ - "drain", - "hangup" - ] - }, - "reason": { - "type": "string", - "minLength": 1, - "maxLength": 512 - }, - "task_id": { - "$ref": "#/$defs/id" - } - } - }, - "tenantKey": { - "type": "string", - "minLength": 1, - "maxLength": 196, - "not": { - "pattern": "(^|\\.)[*#](\\.|$)" - }, - "$comment": "Runtime also enforces 196 UTF-8 bytes and each AMQP resource's 255-byte budget." - }, - "time": { - "type": "string", - "format": "date-time" - } - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/oss-upload.schema.json b/contracts/archive/upstream/2026-09-21-p1-v2/oss-upload.schema.json deleted file mode 100644 index 8b2ada1..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/oss-upload.schema.json +++ /dev/null @@ -1,205 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://go-sip.local/contracts/2026-09-21-p1-v2/oss-upload.schema.json", - "title": "Recording upload control-plane messages", - "type": "object", - "required": [ - "kind" - ], - "properties": { - "kind": { - "type": "string" - } - }, - "oneOf": [ - { - "additionalProperties": false, - "properties": { - "kind": { - "const": "request" - }, - "upload_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "recording_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "call_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "size_bytes": { - "type": "integer", - "minimum": 1 - }, - "checksum_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "format": { - "enum": [ - "wav", - "raw_pcm", - "pcma" - ] - }, - "channels": { - "const": 1 - }, - "sample_rate_hz": { - "type": "integer", - "minimum": 8000 - }, - "duration_ms": { - "type": "integer", - "minimum": 1 - } - }, - "required": [ - "upload_id", - "recording_id", - "call_id", - "size_bytes", - "checksum_sha256", - "format", - "channels", - "sample_rate_hz", - "duration_ms" - ] - }, - { - "additionalProperties": false, - "properties": { - "kind": { - "const": "grant" - }, - "upload_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "recording_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "upload_url": { - "type": "string", - "format": "uri", - "pattern": "^https://" - }, - "required_headers": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "expires_at": { - "type": "string", - "format": "date-time" - }, - "max_bytes": { - "type": "integer", - "minimum": 1 - }, - "object_binding": { - "type": "string", - "minLength": 1, - "maxLength": 256 - } - }, - "required": [ - "upload_id", - "recording_id", - "upload_url", - "required_headers", - "expires_at", - "max_bytes", - "object_binding" - ] - }, - { - "additionalProperties": false, - "properties": { - "kind": { - "const": "complete" - }, - "upload_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "recording_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "size_bytes": { - "type": "integer", - "minimum": 1 - }, - "checksum_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "etag": { - "type": [ - "string", - "null" - ], - "maxLength": 256 - } - }, - "required": [ - "upload_id", - "recording_id", - "size_bytes", - "checksum_sha256", - "etag" - ] - }, - { - "additionalProperties": false, - "properties": { - "kind": { - "const": "verified" - }, - "upload_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "recording_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "oss_id": { - "type": "string", - "minLength": 1, - "maxLength": 512 - }, - "verified_at": { - "type": "string", - "format": "date-time" - }, - "checksum_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - } - }, - "required": [ - "upload_id", - "recording_id", - "oss_id", - "verified_at", - "checksum_sha256" - ] - } - ] -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/p1-development-profile.schema.json b/contracts/archive/upstream/2026-09-21-p1-v2/p1-development-profile.schema.json deleted file mode 100644 index 1f3526b..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/p1-development-profile.schema.json +++ /dev/null @@ -1,156 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://go-sip.local/contracts/2026-09-21-p1-v2/p1-development-profile.schema.json", - "title": "P1 isolated development profile", - "type": "object", - "additionalProperties": false, - "required": [ - "profile_id", - "profile_version", - "environment", - "external_calls", - "real_authorization", - "topology", - "limits", - "modes", - "retention", - "status" - ], - "properties": { - "profile_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "profile_version": { - "type": "string", - "minLength": 1, - "maxLength": 32 - }, - "environment": { - "const": "mock" - }, - "external_calls": { - "const": false - }, - "real_authorization": { - "const": "blocked" - }, - "topology": { - "type": "object", - "additionalProperties": false, - "required": [ - "dispatcher_count", - "agent_count", - "cell_count", - "tenant_count" - ], - "properties": { - "dispatcher_count": { - "const": 1 - }, - "agent_count": { - "const": 2 - }, - "cell_count": { - "const": 2 - }, - "tenant_count": { - "type": "integer", - "minimum": 1 - } - } - }, - "limits": { - "type": "object", - "additionalProperties": false, - "required": [ - "global_concurrency", - "global_cps", - "tenant_concurrency", - "tenant_cps", - "pending_window_global", - "pending_window_per_tenant", - "lease_ttl_ms", - "final_permit_ttl_ms" - ], - "properties": { - "global_concurrency": { - "type": "integer", - "minimum": 1 - }, - "global_cps": { - "type": "integer", - "minimum": 1 - }, - "tenant_concurrency": { - "type": "integer", - "minimum": 1 - }, - "tenant_cps": { - "type": "integer", - "minimum": 1 - }, - "pending_window_global": { - "type": "integer", - "minimum": 1 - }, - "pending_window_per_tenant": { - "type": "integer", - "minimum": 1 - }, - "lease_ttl_ms": { - "const": 10000 - }, - "final_permit_ttl_ms": { - "type": "integer", - "minimum": 1, - "maximum": 1000 - } - } - }, - "modes": { - "type": "array", - "minItems": 2, - "uniqueItems": true, - "items": { - "enum": [ - "full_ai", - "asr_only" - ] - } - }, - "retention": { - "type": "object", - "additionalProperties": false, - "required": [ - "keep_unverified_assets", - "delete_only_after_verified", - "backup_kind" - ], - "properties": { - "keep_unverified_assets": { - "const": true - }, - "delete_only_after_verified": { - "const": true - }, - "backup_kind": { - "enum": [ - "local-sqlite-wal-consistent", - "not-configured" - ] - } - } - }, - "status": { - "const": "development-only-not-production-approval" - }, - "real_budget": { - "const": "unknown" - }, - "operator_approval": { - "const": "not-granted" - } - } -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v2/static-cell-artifact.schema.json b/contracts/archive/upstream/2026-09-21-p1-v2/static-cell-artifact.schema.json deleted file mode 100644 index 0dba3eb..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v2/static-cell-artifact.schema.json +++ /dev/null @@ -1,369 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://go-sip.local/contracts/2026-09-21-p1-v2/static-cell-artifact.schema.json", - "title": "Project-owned v1 static Cell/SIP hand-off artifact", - "type": "object", - "additionalProperties": false, - "required": [ - "artifact_id", - "source_release", - "source_digest", - "approval_reference", - "cell_id", - "revision", - "config_sha256", - "mode", - "allowed_targets", - "trunks" - ], - "properties": { - "artifact_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "source_release": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "source_digest": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "approval_reference": { - "type": "string", - "minLength": 1, - "maxLength": 256 - }, - "cell_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "revision": { - "type": "integer", - "minimum": 1 - }, - "config_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "mode": { - "enum": [ - "mock", - "mixed", - "real" - ] - }, - "allowed_targets": { - "type": "array", - "minItems": 1, - "maxItems": 1000, - "uniqueItems": true, - "items": { - "type": "string", - "pattern": "^[0-9]{11,15}$" - } - }, - "trunks": { - "type": "array", - "minItems": 1, - "maxItems": 32, - "items": { - "type": "object", - "additionalProperties": false, - "required": [ - "trunk_id", - "provider_id", - "egress_pool_id", - "codec", - "caller_profile_ids", - "dial_prefix", - "enabled", - "media_profile_id" - ], - "properties": { - "trunk_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "provider_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "egress_pool_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "codec": { - "const": "PCMA" - }, - "caller_profile_ids": { - "type": "array", - "minItems": 1, - "uniqueItems": true, - "items": { - "type": "string", - "minLength": 1, - "maxLength": 128 - } - }, - "dial_prefix": { - "type": "string", - "maxLength": 32 - }, - "enabled": { - "type": "boolean" - }, - "sip_endpoint_ref": { - "type": "string", - "maxLength": 128 - }, - "credential_ref": { - "type": [ - "string", - "null" - ], - "maxLength": 128 - }, - "media_profile_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - } - } - } - }, - "ari": { - "type": "object", - "additionalProperties": false, - "required": [ - "base_url", - "websocket_url", - "application", - "credential_ref" - ], - "properties": { - "base_url": { - "type": "string", - "format": "uri", - "pattern": "^https?://" - }, - "websocket_url": { - "type": "string", - "format": "uri", - "pattern": "^wss?://" - }, - "application": { - "type": "string", - "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$" - }, - "credential_ref": { - "type": "string", - "minLength": 1, - "maxLength": 128 - } - } - }, - "media_profiles": { - "type": "object", - "minProperties": 1, - "maxProperties": 16, - "additionalProperties": { - "type": "object", - "additionalProperties": false, - "required": [ - "format", - "sample_rate_hz", - "channels", - "payload_type" - ], - "properties": { - "format": { - "enum": [ - "slin16", - "alaw" - ] - }, - "sample_rate_hz": { - "enum": [ - 8000, - 16000 - ] - }, - "channels": { - "const": 1 - }, - "payload_type": { - "type": "integer", - "minimum": 0, - "maximum": 127 - } - }, - "allOf": [ - { - "if": { - "properties": { - "format": { - "const": "alaw" - } - } - }, - "then": { - "properties": { - "sample_rate_hz": { - "const": 8000 - }, - "payload_type": { - "const": 8 - } - } - } - }, - { - "if": { - "properties": { - "format": { - "const": "slin16" - } - } - }, - "then": { - "properties": { - "sample_rate_hz": { - "const": 16000 - }, - "payload_type": { - "type": "integer", - "minimum": 96, - "maximum": 127 - } - } - } - } - ] - } - }, - "media": { - "type": "object", - "additionalProperties": false, - "required": [ - "bind_address", - "port", - "format", - "sample_rate_hz", - "channels", - "payload_type" - ], - "properties": { - "bind_address": { - "type": "string", - "minLength": 1, - "maxLength": 255 - }, - "port": { - "type": "integer", - "minimum": 1024, - "maximum": 65535 - }, - "format": { - "enum": [ - "slin16", - "alaw" - ] - }, - "sample_rate_hz": { - "enum": [ - 8000, - 16000 - ] - }, - "channels": { - "const": 1 - }, - "payload_type": { - "type": "integer", - "minimum": 0, - "maximum": 127 - } - } - }, - "recording": { - "type": "object", - "additionalProperties": false, - "required": [ - "enabled", - "format", - "directory", - "max_bytes" - ], - "properties": { - "enabled": { - "const": true - }, - "format": { - "const": "wav" - }, - "directory": { - "type": "string", - "minLength": 1, - "maxLength": 512 - }, - "max_bytes": { - "type": "integer", - "minimum": 16000, - "maximum": 1073741824 - } - } - }, - "load_evidence": { - "type": [ - "object", - "null" - ], - "additionalProperties": false, - "properties": { - "asterisk_config_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "loaded_at": { - "type": "string", - "format": "date-time" - }, - "status": { - "enum": [ - "not-yet-loaded", - "loaded" - ] - } - } - } - }, - "allOf": [ - { - "if": { - "properties": { - "mode": { - "enum": [ - "mixed", - "real" - ] - } - } - }, - "then": { - "required": [ - "ari", - "media", - "media_profiles", - "recording" - ] - } - } - ] -} diff --git a/contracts/archive/upstream/2026-09-21-p1-v3-unused-ai-digest.json b/contracts/archive/upstream/2026-09-21-p1-v3-unused-ai-digest.json deleted file mode 100644 index 05e9cc7..0000000 --- a/contracts/archive/upstream/2026-09-21-p1-v3-unused-ai-digest.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "scope": "AI snapshot.config and authorization config_sha256 only", - "canonicalization": "RFC 8785 (JCS)", - "digest": "SHA-256", - "encoding": "lowercase hex", - "implementation": "github.com/cyberphone/json-canonicalization", - "revision": "v0.0.0-20241213102144-19d51d7fe467", - "external_acceptance": false, - "invariants": [ - "No Unicode normalization", - "Reject invalid UTF-8 and duplicate object keys", - "Preserve explicit zero/false versus absent fields", - "No old-digest fallback" - ] -} diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/ai-config.openapi.yaml b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/ai-config.openapi.yaml deleted file mode 100644 index e310606..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/ai-config.openapi.yaml +++ /dev/null @@ -1,145 +0,0 @@ -openapi: 3.1.0 -info: - title: agent-call immutable AI configuration API - version: 1.0.0 - description: >- - Internal configuration publication/read surface. The call.execute business - command remains RabbitMQ-only; secrets, URLs, and provider credentials are - resolved by the execution environment and never enter MQ messages. -servers: - - url: / -paths: - /internal/v1/ai/agent-versions: - post: - operationId: publishAgentVersion - security: - - aiConfigPublish: [] - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionPublishRequest' - responses: - '200': - description: Identical immutable content already exists - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionReceipt' - '201': - description: Immutable version published - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersionReceipt' - '400': - $ref: '#/components/responses/BadRequest' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '409': - description: Existing version has different content - /internal/v1/ai/agent-versions/{agent_version_id}: - get: - operationId: getAgentVersion - security: - - aiConfigRead: [] - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - name: agent_version_id - in: path - required: true - schema: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$' - responses: - '200': - description: Trusted immutable snapshot - content: - application/json: - schema: - $ref: '#/components/schemas/AgentVersion' - '401': - $ref: '#/components/responses/Unauthorized' - '403': - $ref: '#/components/responses/Forbidden' - '404': - description: Agent version not found -components: - parameters: - TenantId: - name: X-Tenant-Id - in: header - required: true - schema: {type: string, minLength: 1} - RequestId: - name: X-Request-Id - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - securitySchemes: - aiConfigPublish: - type: http - scheme: bearer - bearerFormat: JWT - description: >- - Requires scope ai.config.publish and the AI-config issuer/audience. - aiConfigRead: - type: http - scheme: bearer - bearerFormat: JWT - description: >- - Requires scope ai.config.read and the AI-config issuer/audience. - schemas: - AgentVersionPublishRequest: - type: object - additionalProperties: false - required: [agent_version_id, config] - properties: - agent_version_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$' - config: - $ref: 'ai-config.schema.json' - AgentVersionReceipt: - type: object - required: [tenant_id, agent_version_id, status, immutable, content_sha256] - properties: - tenant_id: {type: string} - agent_version_id: {type: string} - status: {enum: [published, reused]} - immutable: {const: true} - content_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - AgentVersion: - allOf: - - $ref: '#/components/schemas/AgentVersionReceipt' - - type: object - required: [config] - properties: - config: - $ref: 'ai-config.schema.json' - created_at: {type: string, format: date-time} - published_at: {type: string, format: date-time} - created_by: {type: string} - Error: - type: object - required: [error] - properties: - error: {type: string} - message: {type: string} - responses: - BadRequest: - description: Invalid configuration - content: - application/json: - schema: {$ref: '#/components/schemas/Error'} - Unauthorized: - description: Missing or invalid AI-config token - Forbidden: - description: Token lacks the AI-config permission diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/ai-config.schema.json b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/ai-config.schema.json deleted file mode 100644 index e4d2797..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/ai-config.schema.json +++ /dev/null @@ -1,101 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.local/contracts/ai-config.schema.json", - "title": "Immutable AI agent version", - "type": "object", - "additionalProperties": false, - "required": ["agent_version_id", "immutable", "llm", "prompt", "tts", "asr", "conversation"], - "properties": { - "agent_version_id": {"type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"}, - "immutable": {"const": true}, - "llm": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "model"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "temperature": {"type": "number", "minimum": 0, "maximum": 2}, - "max_tokens": {"type": "integer", "minimum": 1}, - "timeout_ms": {"type": "integer", "minimum": 1} - } - }, - "prompt": { - "type": "object", - "additionalProperties": false, - "required": ["text", "allowed_variables"], - "properties": { - "text": {"type": "string", "minLength": 1, "maxLength": 32768}, - "allowed_variables": { - "type": "array", - "maxItems": 32, - "items": {"type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$"} - }, - "max_bytes": {"type": "integer", "minimum": 1, "maximum": 32768} - } - }, - "tts": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "model", "voice", "format"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "voice": {"type": "string", "minLength": 1, "maxLength": 128}, - "speed": {"type": "number", "minimum": 0.25, "maximum": 3}, - "timeout_ms": {"type": "integer", "minimum": 1}, - "format": { - "type": "object", - "additionalProperties": false, - "required": ["encoding", "sample_rate_hz", "channels"], - "properties": { - "encoding": {"enum": ["pcm_s16le", "pcma"]}, - "sample_rate_hz": {"type": "integer", "minimum": 8000, "maximum": 48000}, - "channels": {"const": 1} - } - } - } - }, - "asr": { - "type": "object", - "additionalProperties": false, - "required": ["provider_ref", "language", "input"], - "properties": { - "provider_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "credential_ref": {"type": "string", "minLength": 1, "maxLength": 128}, - "model": {"type": "string", "minLength": 1, "maxLength": 128}, - "language": {"type": "string", "minLength": 1, "maxLength": 32}, - "interim": {"type": "boolean"}, - "timeout_ms": {"type": "integer", "minimum": 1}, - "input": { - "type": "object", - "additionalProperties": false, - "required": ["encoding", "sample_rate_hz", "channels", "sample_width_bytes"], - "properties": { - "encoding": {"const": "pcm_s16le"}, - "sample_rate_hz": {"type": "integer", "minimum": 8000, "maximum": 48000}, - "channels": {"const": 1}, - "sample_width_bytes": {"const": 2} - } - } - } - }, - "conversation": { - "type": "object", - "additionalProperties": false, - "required": ["opening", "allow_interrupt", "silence_timeout_ms", "max_duration_ms", "max_turns", "sentence_max_chars", "max_pending_audio_chunks"], - "properties": { - "opening": {"type": "string", "maxLength": 32768}, - "allow_interrupt": {"type": "boolean"}, - "silence_timeout_ms": {"type": "integer", "minimum": 1}, - "max_duration_ms": {"type": "integer", "minimum": 1, "maximum": 3600000}, - "max_turns": {"type": "integer", "minimum": 1, "maximum": 1000}, - "sentence_max_chars": {"type": "integer", "minimum": 1}, - "max_pending_audio_chunks": {"type": "integer", "minimum": 1} - } - }, - "metadata": {"type": "object", "additionalProperties": true} - } -} diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/cell-agent.openapi.yaml b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/cell-agent.openapi.yaml deleted file mode 100644 index f929a1b..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/cell-agent.openapi.yaml +++ /dev/null @@ -1,225 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Cell Agent API - version: 1.0.0 - description: >- - Restricted mTLS API used by the SIP management backend to deliver a - versioned Trunk snapshot to one voice Cell. The Cell validates the SHA-256 - snapshot, applies it with an atomic file replacement, reloads Asterisk, - restores the previous file on reload failure, and returns applied only - after the reload succeeds. A disabled snapshot removes the Cell-local - Trunk fragment and reloads Asterisk. -servers: - - url: https://cell.internal:9443 - description: Cell management network only -tags: - - name: health - - name: trunk-apply -paths: - /healthz/live: - get: - tags: [health] - operationId: live - responses: - '200': - description: Cell Agent is alive - content: - application/json: - schema: {$ref: '#/components/schemas/Health'} - /v1/sip/trunks/{trunk_id}/apply: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [trunk-apply] - operationId: applyTrunk - security: [{CellManagementMtls: []}] - parameters: - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/Publication'} - responses: - '200': - description: Asterisk has loaded the exact snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Acknowledgement'} - '400': {$ref: '#/components/responses/BadRequest'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': - description: Revision is stale or has a gap - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - '502': - description: Asterisk rejected the apply or reload - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - /v1/sip/trunks/{trunk_id}/state: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [trunk-apply] - operationId: getTrunkState - security: [{CellManagementMtls: []}] - responses: - '200': - description: Durable Cell apply state - content: - application/json: - schema: {$ref: '#/components/schemas/State'} - '404': {$ref: '#/components/responses/NotFound'} -components: - securitySchemes: - CellManagementMtls: - type: mutualTLS - description: Management backend client certificate signed by the Cell CA. - parameters: - TrunkId: - name: trunk_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - schemas: - Health: - type: object - additionalProperties: false - required: [status, mode, cell_id] - properties: - status: {type: string, const: ok} - mode: {type: string, const: real} - cell_id: {type: string} - CodecProfile: - type: object - additionalProperties: false - required: [allowed, preferred] - properties: - allowed: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - preferred: {type: string, enum: [PCMA, PCMU]} - SipConfig: - type: object - additionalProperties: false - required: [host, port, transport, auth_mode, register, credential_ref] - properties: - host: {type: string, minLength: 1, maxLength: 253} - port: {type: integer, minimum: 1, maximum: 65535} - transport: {type: string, enum: [udp, tcp, tls]} - auth_mode: {type: string, enum: [ip, digest]} - register: {type: boolean} - credential_ref: - type: [string, 'null'] - description: Secret-store reference only; plaintext is forbidden. - TrunkConfig: - type: object - additionalProperties: false - required: - - display_name - - enabled - - sip - - codec_profile - - caller_ids - - dial_prefix - - egress_pool_id - - max_concurrency - - max_cps - properties: - display_name: {type: string, minLength: 1, maxLength: 256} - enabled: {type: boolean} - sip: {$ref: '#/components/schemas/SipConfig'} - codec_profile: {$ref: '#/components/schemas/CodecProfile'} - caller_ids: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, minLength: 1, maxLength: 128} - dial_prefix: {type: string, maxLength: 32} - egress_pool_id: {type: string} - max_concurrency: {type: integer, minimum: 1} - max_cps: {type: integer, minimum: 1} - Publication: - type: object - additionalProperties: false - required: [mode, cell_id, trunk_id, revision, config, config_sha256] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - config: {$ref: '#/components/schemas/TrunkConfig'} - config_sha256: - type: string - pattern: '^[0-9a-f]{64}$' - Acknowledgement: - type: object - additionalProperties: false - required: - [mode, cell_id, trunk_id, revision, config_sha256, status, idempotent] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - config_sha256: {type: string, pattern: '^[0-9a-f]{64}$'} - status: {type: string, const: applied} - idempotent: {type: boolean} - State: - type: object - additionalProperties: false - required: - [ - mode, - cell_id, - trunk_id, - desired_revision, - applied_revision, - status, - updated_at, - ] - properties: - mode: {type: string, const: real} - cell_id: {type: string} - trunk_id: {type: string} - desired_revision: {type: integer, minimum: 1} - applied_revision: {type: integer, minimum: 0} - status: {type: string, enum: [applying, applied, failed]} - last_error: {type: [string, 'null']} - updated_at: {type: string, format: date-time} - ErrorResponse: - type: object - required: [error] - properties: - error: - type: object - required: [code, message] - properties: - code: {type: string} - message: {type: string} - responses: - BadRequest: - description: Invalid publication or hash - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Forbidden: - description: Certificate or Cell identity is not authorized - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - NotFound: - description: State does not exist - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/README.md b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/README.md deleted file mode 100644 index 02f9c1a..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Contract fixtures - -`call.execute.json` is the canonical valid command fixture. Runtime tests generate the remaining event fixtures from persisted facts so replay assertions compare original bytes and IDs rather than synthesized history. Invalid cases include unknown schema versions, missing required fields, cross-tenant bindings, conflicting idempotency bodies, and tenant routing keys over 224 UTF-8 bytes. - -All fixtures are synthetic. The profile is `mock`; it is never a production provider configuration. diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/agent-version.json b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/agent-version.json deleted file mode 100644 index 61851cd..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/agent-version.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "agent_version_id": "agent_v1", - "immutable": true, - "llm": { - "provider_ref": "mock", - "model": "mock-chat-v1", - "temperature": 0.2, - "max_tokens": 256, - "timeout_ms": 5000 - }, - "prompt": { - "text": "You are a concise telephone assistant. Answer the caller's last statement.", - "allowed_variables": [], - "max_bytes": 32768 - }, - "tts": { - "provider_ref": "mock", - "model": "mock-tts-v1", - "voice": "mock-neutral", - "speed": 1.0, - "format": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1 - }, - "timeout_ms": 5000 - }, - "asr": { - "provider_ref": "mock", - "language": "zh-CN", - "input": { - "encoding": "pcm_s16le", - "sample_rate_hz": 16000, - "channels": 1, - "sample_width_bytes": 2 - }, - "interim": true, - "timeout_ms": 5000 - }, - "conversation": { - "opening": "", - "allow_interrupt": true, - "silence_timeout_ms": 3000, - "max_duration_ms": 120000, - "max_turns": 20, - "sentence_max_chars": 80, - "max_pending_audio_chunks": 32 - } -} diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/call.execute.json b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/call.execute.json deleted file mode 100644 index 23f9fdc..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/examples/call.execute.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "schema_version": "1.0", - "command_type": "call.execute", - "command_id": "cmd_demo_001", - "tenant_id": "tenant-demo", - "tenant_key": "tenant-demo-key", - "trace_id": "trace_demo_001", - "issued_at": "2026-09-11T08:00:00Z", - "not_after": "2099-09-11T08:05:00Z", - "payload": { - "execution_id": "exec_demo_001", - "task_id": "task-demo", - "task_item_id": "item_demo", - "task_revision": 1, - "callee": "18601013734", - "route_policy_id": "route_policy_test", - "caller_profile_id": "caller_profile_test", - "agent_version_id": "agent_v1", - "variables": {}, - "ring_timeout_ms": 30000, - "max_call_duration_ms": 180000 - } -} diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/executor.openapi.yaml b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/executor.openapi.yaml deleted file mode 100644 index a9f02fb..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/executor.openapi.yaml +++ /dev/null @@ -1,303 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Executor Control API - version: 1.0.0 - description: >- - Internal control, query, replay, and recording hand-off API. Call execution - enters through RabbitMQ, not HTTP. -servers: - - url: https://executor.internal -security: - - bearerAuth: [] -paths: - /internal/v1/outbound/tasks/{task_id}/controls: - post: - operationId: controlTask - summary: Persist a pause, resume, or stop barrier - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/TaskId' - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/ControlRequest' - responses: - '202': - description: Reliably persisted, not yet necessarily applied - headers: - Location: - schema: {type: string} - content: - application/json: - schema: {$ref: '#/components/schemas/ControlAccepted'} - '409': {$ref: '#/components/responses/Conflict'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/commands/{command_id}: - get: - operationId: getCommand - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/CommandId' - responses: - '200': - description: Command snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Command'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/calls/{call_id}: - get: - operationId: getCall - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/CallId' - responses: - '200': - description: Call snapshot - content: - application/json: - schema: {$ref: '#/components/schemas/Call'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /internal/v1/outbound/calls/{call_id}/replays: - post: - operationId: replayCall - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/CallId' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayRequest'} - responses: - '202': - description: Replay persisted for bounded broker delivery - headers: - Location: {schema: {type: string}} - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayAccepted'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - '410': {$ref: '#/components/responses/ReplayExpired'} - /internal/v1/outbound/commands/{source_command_id}/replays: - post: - operationId: replayCommand - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/SourceCommandId' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayRequest'} - responses: - '202': - description: Replay persisted for bounded broker delivery - headers: - Location: {schema: {type: string}} - content: - application/json: - schema: {$ref: '#/components/schemas/ReplayAccepted'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - '410': {$ref: '#/components/responses/ReplayExpired'} -components: - securitySchemes: - bearerAuth: - type: http - scheme: bearer - parameters: - TenantId: - name: X-Tenant-ID - in: header - required: true - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string} - IdempotencyKey: - name: Idempotency-Key - in: header - required: true - schema: {type: string} - TaskId: - name: task_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - CommandId: - name: command_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - SourceCommandId: - name: source_command_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - CallId: - name: call_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - schemas: - Id: - type: string - minLength: 1 - maxLength: 128 - pattern: '^[^\s/\\]+$' - ControlRequest: - type: object - additionalProperties: false - required: [command_id, action, expected_task_revision, reason] - properties: - command_id: {$ref: '#/components/schemas/Id'} - action: {type: string, enum: [pause, resume, stop]} - expected_task_revision: {type: integer, minimum: 1} - active_call_policy: {type: string, enum: [drain, hangup]} - reason: {type: string, minLength: 1, maxLength: 512} - ControlAccepted: - type: object - required: - - command_id - - tenant_id - - tenant_key - - task_id - - status - - requested_task_revision - - accepted_at - properties: - command_id: {$ref: '#/components/schemas/Id'} - tenant_id: {type: string} - tenant_key: {type: string} - task_id: {$ref: '#/components/schemas/Id'} - status: {const: accepted} - requested_task_revision: {type: integer} - accepted_at: {type: string, format: date-time} - ReplayRequest: - type: object - additionalProperties: false - required: [command_id, reason] - properties: - command_id: {$ref: '#/components/schemas/Id'} - reason: {type: string, minLength: 1, maxLength: 512} - ReplayAccepted: - type: object - required: [command_id, status, snapshot_cutoff] - properties: - command_id: {$ref: '#/components/schemas/Id'} - status: {const: accepted} - snapshot_cutoff: {type: string, format: date-time} - Command: - type: object - required: - - command_id - - command_type - - tenant_id - - tenant_key - - status - - aggregate_version - properties: - command_id: {$ref: '#/components/schemas/Id'} - command_type: {type: string} - tenant_id: {type: string} - tenant_key: {type: string} - task_id: {type: [string, 'null']} - execution_id: {type: [string, 'null']} - call_id: {type: [string, 'null']} - status: {type: string} - reason_code: {type: [string, 'null']} - wait_reason_code: {type: [string, 'null']} - accepted_at: {type: [string, 'null'], format: date-time} - waiting_since: {type: [string, 'null'], format: date-time} - admission_deadline: {type: [string, 'null'], format: date-time} - requested_task_revision: {type: [integer, 'null']} - applied_task_revision: {type: [integer, 'null']} - task_state: {type: [string, 'null']} - updated_at: {type: string, format: date-time} - aggregate_version: {type: integer, minimum: 1} - Call: - type: object - required: - - call_id - - execution_id - - call_state - - call_version - - attempts - - transcript - - recordings - - delivery - - snapshot_at - properties: - call_id: {type: string} - execution_id: {type: string} - task_id: {type: string} - task_item_id: {type: string} - call_state: {type: string} - call_version: {type: integer} - reason_code: {type: [string, 'null']} - outcome: {type: [string, 'null']} - started_at: {type: [string, 'null'], format: date-time} - ended_at: {type: [string, 'null'], format: date-time} - duration_ms: {type: [integer, 'null']} - attempts: {type: array, items: {type: object}} - transcript: {type: object} - recordings: {type: array, items: {type: object}} - delivery: {type: object} - snapshot_at: {type: string, format: date-time} - Problem: - type: object - additionalProperties: false - required: [type, title, status, code, detail, request_id, retryable] - properties: - type: {type: string, format: uri-reference} - title: {type: string} - status: {type: integer} - code: {type: string} - detail: {type: string} - request_id: {type: string} - retryable: {type: boolean} - responses: - Unauthorized: - description: Unauthorized - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - Forbidden: - description: Forbidden - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - NotFound: - description: Not found without cross-tenant enumeration - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - Conflict: - description: Idempotency or revision conflict - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} - ReplayExpired: - description: Retention window expired - content: - application/problem+json: - schema: {$ref: '#/components/schemas/Problem'} diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mock-profile.json b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mock-profile.json deleted file mode 100644 index 4a79b80..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mock-profile.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "profile_version": "1.0.0", - "mode": "mock", - "provider_modes": { - "saas": "mock", - "database": "sqlite", - "rabbitmq": "memory", - "sip": "mock", - "asterisk": "mock", - "asr": "mock", - "llm": "mock", - "tts": "mock", - "oss": "mock", - "cloud": "fake-cli" - }, - "versions": {"schema": "1.0", "service": "0.1.0", "seed": "mock-2026-09-11"}, - "limits": { - "admission_window_s": 30, - "ring_timeout_ms": 30000, - "max_call_duration_ms": 180000, - "max_mq_bytes": 262144, - "max_queue_messages": 1000, - "max_queue_bytes": 16777216, - "disk_warn_pct": 0.70, - "disk_stop_pct": 0.80, - "max_http_bytes": 65536, - "recording_max_bytes": 16777216, - "max_recording_bytes": 16777216, - "replay_retention_s": 604800, - "upload_ttl_s": 300, - "global_concurrency": 6, - "global_cps": 3, - "tenant_concurrency": 2, - "tenant_cps": 1, - "tenant_publish_rate": 10, - "scheduler_lease_ttl_s": 10, - "pending_window_per_tenant": 16, - "pending_window_global": 64, - "max_unacked_per_tenant": 4, - "max_replay_attempts": 6, - "cell_capacity": 4, - "turns": 2, - "hold_ms": 0 - }, - "random_seed": 7, - "tenants": [ - {"tenant_id": "tenant-demo", "tenant_key": "tenant-demo-key", "enabled": true}, - {"tenant_id": "tenant-b", "tenant_key": "tenant.b", "enabled": true}, - {"tenant_id": "tenant-c", "tenant_key": "tenant#c", "enabled": true} - ], - "tasks": [ - {"task_id": "task-demo", "tenant_id": "tenant-demo", "state": "running", "revision": 1}, - {"task_id": "task-b", "tenant_id": "tenant-b", "state": "running", "revision": 1}, - {"task_id": "task-c", "tenant_id": "tenant-c", "state": "running", "revision": 1} - ], - "routes": [{"route_policy_id": "route_policy_test", "trunk_id": "trunk-mock", "egress_pool_id": "egress-mock", "dial_prefix": "7089", "allowed": true}], - "caller_profiles": [{"caller_profile_id": "caller_profile_test", "display": "BD93205882", "allowed": true}], - "agents": [{"agent_version_id": "agent_v1", "immutable": true, "llm": "mock", "tts": "mock", "asr": "mock"}], - "cells": [ - {"cell_id": "cell-a", "capacity": 4, "media_capacity": 4, "ai_capacity": 4, "egress_pool_id": "egress-mock", "ari_mode": "mock"}, - {"cell_id": "cell-b", "capacity": 4, "media_capacity": 4, "ai_capacity": 4, "egress_pool_id": "egress-mock", "ari_mode": "mock"} - ], - "failure_scenarios": ["success", "busy", "no_answer", "ai_timeout", "customer_silent", "ari_disconnect", "upload_missing", "upload_bad_checksum", "broker_outage", "clock_jump"] -} diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mq-topology.md b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mq-topology.md deleted file mode 100644 index 60f8501..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mq-topology.md +++ /dev/null @@ -1,40 +0,0 @@ -# agent-call MQ topology v1.0 - -This file is an implementation companion to the field authority in -`SaaS交互_OpenAPI与MQ契约规划_v0.1.md`. - -| Element | Value | -| --- | --- | -| Namespace | `agent-call` | -| Command exchange | `agent-call.commands.v1`, durable `direct` | -| Tenant command queue | `agent-call.executor.{tenant_key}.v1`, durable, one exact binding | -| Command routing key | `agent-call.tenant.{tenant_key}.call.execute` | -| Event exchange | `agent-call.events.v1`, durable `topic` | -| SaaS result queue | `agent-call.saas.events.v1`, durable, binding `agent-call.#` | -| Event routing key | `agent-call.{event_type}` | -| Body limit | `262144` UTF-8 bytes in the Mock profile | -| Tenant route budget | Broker limit `255` bytes; fixed prefix/suffix consume `31`, leaving `224` UTF-8 bytes | - -## Delivery rules - -1. SaaS persists the command publication record before publishing. A mandatory - publisher confirmation is required; an unroutable/full queue leaves the - original record retained for bounded retry. -2. The executor consumes only its trusted tenant queue. RabbitMQ messages are - acknowledged after durable SQLite acceptance or durable dead-lettering, not - when they are fetched. -3. Executor business events are written to the same database transaction as - the state transition. The outbox dispatcher publishes them durably and the - SaaS inbox applies each `event_id` once. `saas_applied` may remain unknown - after broker confirmation; it does not trigger unbounded republishing. -4. `tenant_key` is copied byte-for-byte into the body, queue name, binding and - routing key. It is not normalized, encoded, truncated or cleaned. A route - over the byte budget is retained and not sent. -5. Replay publishes the original event body and original `event_id` from a - fixed retention cutoff. It never creates a new business fact and never - includes events written after that cutoff. -6. HTTP has no call execution or redial endpoint. Control, query, replay and - recording metadata paths require bearer scope and tenant scope. - -The in-process broker is only for deterministic tests. Docker Compose uses the -same topology through the `pika` adapter and RabbitMQ durable queues. diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mq.schema.json b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mq.schema.json deleted file mode 100644 index b5ab065..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/mq.schema.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "$schema": "https://json-schema.org/draft/2020-12/schema", - "$id": "https://agent-call.invalid/contracts/mq.schema.json", - "title": "agent-call MQ command and event envelope", - "oneOf": [{"$ref": "#/$defs/executeCommand"}, {"$ref": "#/$defs/event"}], - "$defs": { - "id": {"type": "string", "minLength": 1, "maxLength": 128, "pattern": "^[^\\s/\\\\]+$"}, - "tenantKey": {"type": "string", "minLength": 1}, - "time": {"type": "string", "format": "date-time"}, - "executeCommand": { - "type": "object", "additionalProperties": false, - "required": ["schema_version", "command_type", "command_id", "tenant_id", "tenant_key", "trace_id", "issued_at", "not_after", "payload"], - "properties": { - "schema_version": {"const": "1.0"}, "command_type": {"const": "call.execute"}, "command_id": {"$ref": "#/$defs/id"}, - "tenant_id": {"$ref": "#/$defs/id"}, "tenant_key": {"$ref": "#/$defs/tenantKey"}, "trace_id": {"$ref": "#/$defs/id"}, - "issued_at": {"$ref": "#/$defs/time"}, "not_after": {"$ref": "#/$defs/time"}, "payload": {"$ref": "#/$defs/executePayload"} - } - }, - "executePayload": { - "type": "object", "additionalProperties": false, - "required": ["execution_id", "task_id", "task_item_id", "task_revision", "callee", "route_policy_id", "caller_profile_id", "agent_version_id", "variables", "ring_timeout_ms", "max_call_duration_ms"], - "properties": { - "execution_id": {"$ref": "#/$defs/id"}, "task_id": {"$ref": "#/$defs/id"}, "task_item_id": {"$ref": "#/$defs/id"}, - "task_revision": {"type": "integer", "minimum": 1}, "callee": {"type": "string", "minLength": 1, "maxLength": 256}, - "route_policy_id": {"$ref": "#/$defs/id"}, "caller_profile_id": {"$ref": "#/$defs/id"}, "agent_version_id": {"$ref": "#/$defs/id"}, - "variables": {"type": "object", "additionalProperties": true}, "ring_timeout_ms": {"type": "integer", "minimum": 1}, "max_call_duration_ms": {"type": "integer", "minimum": 1} - } - }, - "event": { - "type": "object", "additionalProperties": false, - "required": ["schema_version", "event_id", "event_type", "tenant_id", "tenant_key", "trace_id", "occurred_at", "aggregate_type", "aggregate_id", "aggregate_version", "payload"], - "properties": { - "schema_version": {"const": "1.0"}, "event_id": {"$ref": "#/$defs/id"}, - "event_type": {"enum": ["command.result", "call.status", "transcript.updated", "call.finished", "recording.ready", "recording.failed", "transcript.failed", "contact.opt_out"]}, - "tenant_id": {"$ref": "#/$defs/id"}, "tenant_key": {"$ref": "#/$defs/tenantKey"}, "trace_id": {"$ref": "#/$defs/id"}, "occurred_at": {"$ref": "#/$defs/time"}, - "aggregate_type": {"enum": ["command", "call", "transcript_segment", "recording"]}, "aggregate_id": {"$ref": "#/$defs/id"}, "aggregate_version": {"type": "integer", "minimum": 1}, "payload": {"type": "object"} - } - } - } -} diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/saas.openapi.yaml b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/saas.openapi.yaml deleted file mode 100644 index e3f47c2..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/saas.openapi.yaml +++ /dev/null @@ -1,169 +0,0 @@ -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call SaaS Recording Handoff API - version: 1.0.0 - description: >- - Internal storage handshake. Business results still return through RabbitMQ. -servers: - - url: https://saas.internal -security: - - bearerAuth: [] -paths: - /internal/v1/outbound/recording-uploads: - post: - operationId: createRecordingUpload - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/UploadRequest'} - responses: - '201': - description: Upload session created or existing session returned - headers: {Cache-Control: {schema: {const: no-store}}} - content: - application/json: - schema: {$ref: '#/components/schemas/UploadSession'} - '200': - description: Existing upload session - content: - application/json: - schema: {$ref: '#/components/schemas/UploadSession'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': {$ref: '#/components/responses/Conflict'} - /internal/v1/outbound/recording-uploads/{upload_id}/complete: - post: - operationId: completeRecordingUpload - parameters: - - $ref: '#/components/parameters/TenantId' - - $ref: '#/components/parameters/RequestId' - - $ref: '#/components/parameters/IdempotencyKey' - - name: upload_id - in: path - required: true - schema: {$ref: '#/components/schemas/Id'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/CompleteRequest'} - responses: - '200': - description: Object independently verified - content: - application/json: - schema: {$ref: '#/components/schemas/VerifiedUpload'} - '409': {$ref: '#/components/responses/Conflict'} - '410': {$ref: '#/components/responses/Expired'} - '422': {$ref: '#/components/responses/Unprocessable'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} -components: - securitySchemes: - bearerAuth: {type: http, scheme: bearer} - parameters: - TenantId: - name: X-Tenant-ID - in: header - required: true - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string} - IdempotencyKey: - name: Idempotency-Key - in: header - required: true - schema: {type: string} - schemas: - Id: - type: string - minLength: 1 - maxLength: 128 - pattern: '^[^\s/\\]+$' - UploadRequest: - type: object - additionalProperties: false - required: - - recording_id - - call_id - - content_type - - size_bytes - - checksum_algorithm - - checksum - - channels - - sample_rate_hz - - duration_ms - properties: - recording_id: {$ref: '#/components/schemas/Id'} - call_id: {$ref: '#/components/schemas/Id'} - content_type: {type: string, const: audio/wav} - size_bytes: {type: integer, minimum: 1} - checksum_algorithm: {type: string, const: SHA-256} - checksum: {type: string, pattern: '^[0-9a-f]{64}$'} - channels: {type: integer, const: 1} - sample_rate_hz: {type: integer, minimum: 8000} - duration_ms: {type: integer, minimum: 1} - UploadSession: - type: object - required: - - upload_id - - recording_id - - expires_at - - upload_method - - upload_url - - required_headers - - constraints - properties: - upload_id: {$ref: '#/components/schemas/Id'} - recording_id: {$ref: '#/components/schemas/Id'} - expires_at: {type: string, format: date-time} - upload_method: {const: PUT} - upload_url: {type: string, format: uri} - required_headers: {type: object} - constraints: {type: object} - oss_id: {type: [string, 'null']} - CompleteRequest: - type: object - additionalProperties: false - required: [recording_id, size_bytes, checksum_algorithm, checksum] - properties: - recording_id: {$ref: '#/components/schemas/Id'} - size_bytes: {type: integer, minimum: 1} - checksum_algorithm: {const: SHA-256} - checksum: {type: string, pattern: '^[0-9a-f]{64}$'} - etag: {type: [string, 'null']} - VerifiedUpload: - type: object - required: [upload_id, recording_id, status, oss_id, verified_at] - properties: - upload_id: {$ref: '#/components/schemas/Id'} - recording_id: {$ref: '#/components/schemas/Id'} - status: {const: verified} - oss_id: {type: string} - verified_at: {type: string, format: date-time} - Problem: - type: object - required: [type, title, status, code, detail, request_id, retryable] - properties: - type: {type: string} - title: {type: string} - status: {type: integer} - code: {type: string} - detail: {type: string} - request_id: {type: string} - retryable: {type: boolean} - responses: - Unauthorized: {description: Unauthorized} - Forbidden: {description: Forbidden} - Conflict: {description: Idempotency conflict} - Expired: {description: Upload expired} - Unprocessable: {description: Object failed independent verification} diff --git a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/sip-management.openapi.yaml b/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/sip-management.openapi.yaml deleted file mode 100644 index 28fee2b..0000000 --- a/contracts/archive/upstream/758c0a29e632cfbaaf12b9f6a7242ed130e62807/sip-management.openapi.yaml +++ /dev/null @@ -1,1125 +0,0 @@ ---- -# yaml-language-server: $schema=https://json-schema.org/draft/2020-12/schema -openapi: 3.1.0 -info: - title: agent-call Asterisk/SIP Management API - version: 1.0.0 - description: >- - Independent Asterisk/SIP management backend. Admin write operations are - separate from the SaaS read-only Trunk directory and from ordinary - scheduling APIs. In mock mode publication records are intents only. In - real mode a publication is successful only after every selected Cell Agent - returns a matching mTLS acknowledgement. -servers: - - url: https://sip-admin.internal - description: Restricted operator management network - - url: https://sip-read.internal - description: SaaS read-only service network -tags: - - name: health - - name: admin-providers - - name: admin-trunks - - name: admin-cells - - name: admin-status - - name: admin-statistics - - name: admin-audit - - name: saas-readonly -paths: - /healthz/live: - get: - tags: [health] - operationId: live - responses: - '200': - description: Service is alive - content: - application/json: - schema: - $ref: '#/components/schemas/Health' - /admin/v1/providers: - get: - tags: [admin-providers] - operationId: listProviders - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider directory - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderList'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/providers/{provider_id}: - parameters: - - {$ref: '#/components/parameters/ProviderId'} - get: - tags: [admin-providers] - operationId: getProvider - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-providers] - operationId: upsertProvider - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderInput'} - responses: - '200': - description: Updated provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '201': - description: Created provider - content: - application/json: - schema: {$ref: '#/components/schemas/ProviderResponse'} - '400': {$ref: '#/components/responses/BadRequest'} - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks: - get: - tags: [admin-trunks] - operationId: listAdminTrunks - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/TrunkStatusFilter'} - responses: - '200': - description: All Trunks, including unpublished revisions - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTrunkList' - '401': {$ref: '#/components/responses/Unauthorized'} - '403': {$ref: '#/components/responses/Forbidden'} - /admin/v1/trunks/{trunk_id}: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: getAdminTrunk - security: [{SipAdminBearer: []}] - responses: - '200': - description: Trunk configuration and revisions - content: - application/json: - schema: - $ref: '#/components/schemas/AdminTrunk' - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-trunks] - operationId: createTrunkRevision - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/TrunkConfig' - responses: - '200': - description: New draft revision for an existing Trunk - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '201': - description: New Trunk with its first draft revision - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '400': {$ref: '#/components/responses/BadRequest'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/validate: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: validateTrunk - security: [{SipAdminBearer: []}] - requestBody: - required: false - content: - application/json: - schema: - type: object - additionalProperties: false - properties: - revision: {type: integer, minimum: 1} - responses: - '200': - description: Validation issues, compatible Cells, and impact preview - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/trunks/{trunk_id}/verifications: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: addTrunkVerification - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/VerificationRequest' - responses: - '200': - description: Versioned verification record - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/publish: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: publishTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - responses: - '200': - description: >- - Published revision after all selected Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/disable: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: disableTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - responses: - '200': - description: Trunk disabled after selected Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/rollback: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - post: - tags: [admin-trunks] - operationId: rollbackTrunk - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: - type: object - additionalProperties: false - required: [target_revision] - properties: - target_revision: {type: integer, minimum: 1} - responses: - '200': - description: >- - New revision copied from the target after Cell acknowledgements - content: - application/json: - schema: {$ref: '#/components/schemas/AdminTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/trunks/{trunk_id}/publications: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: listTrunkPublications - security: [{SipAdminBearer: []}] - responses: - '200': - description: Per-Cell publication intents - content: - application/json: - schema: - type: object - required: [mode, publications] - properties: - mode: {$ref: '#/components/schemas/Mode'} - publications: - type: array - items: {$ref: '#/components/schemas/Publication'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/trunks/{trunk_id}/audit: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [admin-trunks] - operationId: listTrunkAudit - security: [{SipAdminBearer: []}] - responses: - '200': - description: Immutable management audit entries - content: - application/json: - schema: - type: object - required: [mode, audit] - properties: - mode: {$ref: '#/components/schemas/Mode'} - audit: - type: array - items: {$ref: '#/components/schemas/AuditEntry'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/cells: - get: - tags: [admin-cells] - operationId: listCells - security: [{SipAdminBearer: []}] - responses: - '200': - description: Registered multi-machine voice Cells - content: - application/json: - schema: - type: object - required: [mode, cells] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cells: - type: array - items: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/cells/{cell_id}: - parameters: - - {$ref: '#/components/parameters/CellId'} - get: - tags: [admin-cells] - operationId: getCell - security: [{SipAdminBearer: []}] - responses: - '200': - description: Registered Cell - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - put: - tags: [admin-cells] - operationId: registerCell - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/IfMatch'} - - {$ref: '#/components/parameters/RequestId'} - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/CellConfig'} - responses: - '200': - description: Updated Cell revision - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '201': - description: Registered Cell - content: - application/json: - schema: {$ref: '#/components/schemas/Cell'} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/cells/{cell_id}/observations: - parameters: - - {$ref: '#/components/parameters/CellId'} - post: - tags: [admin-cells] - operationId: ingestCellObservation - security: [{SipAdminBearer: []}] - requestBody: - required: true - content: - application/json: - schema: {$ref: '#/components/schemas/ObservationInput'} - responses: - '201': - description: >- - Observation accepted for the current boot and monotonic sequence - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '409': {$ref: '#/components/responses/Conflict'} - /admin/v1/egress-pools: - get: - tags: [admin-cells] - operationId: listEgressPools - security: [{SipAdminBearer: []}] - responses: - '200': - description: Fixed egress pool directory - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/sip-status: - get: - tags: [admin-status] - operationId: getSipStatus - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/CellIdsFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/ProviderFilter'} - responses: - '200': - description: >- - Cell/trunk status matrix with freshness and missing sources - content: - application/json: - schema: {$ref: '#/components/schemas/StatusResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/cells/{cell_id}/sip-status: - parameters: - - {$ref: '#/components/parameters/CellId'} - get: - tags: [admin-status] - operationId: getCellSipStatus - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/TrunkFilter'} - responses: - '200': - description: One Cell status - content: - application/json: - schema: {$ref: '#/components/schemas/StatusItem'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/providers/{provider_id}/status: - parameters: - - {$ref: '#/components/parameters/ProviderId'} - get: - tags: [admin-status] - operationId: getProviderStatus - security: [{SipAdminBearer: []}] - responses: - '200': - description: Provider status matrix - content: - application/json: - schema: {$ref: '#/components/schemas/StatusResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/statistics/outbound/summary: - get: - tags: [admin-statistics] - operationId: getOutboundSummary - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Cohort and interval metrics with completeness metadata - content: - application/json: - schema: {$ref: '#/components/schemas/StatisticsSummary'} - '401': {$ref: '#/components/responses/Unauthorized'} - '422': {$ref: '#/components/responses/BadRequest'} - /admin/v1/statistics/outbound/timeseries: - get: - tags: [admin-statistics] - operationId: getOutboundTimeseries - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/Granularity'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Bounded UTC time series - content: - application/json: - schema: {$ref: '#/components/schemas/TimeseriesResponse'} - '401': {$ref: '#/components/responses/Unauthorized'} - '422': {$ref: '#/components/responses/BadRequest'} - /admin/v1/call-attempts: - get: - tags: [admin-statistics] - operationId: listCallAttempts - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/From'} - - {$ref: '#/components/parameters/To'} - - {$ref: '#/components/parameters/StatsMode'} - - {$ref: '#/components/parameters/ProviderFilter'} - - {$ref: '#/components/parameters/TrunkFilter'} - - {$ref: '#/components/parameters/CellIdFilter'} - - {$ref: '#/components/parameters/Limit'} - - {$ref: '#/components/parameters/Cursor'} - - {$ref: '#/components/parameters/EgressFilter'} - responses: - '200': - description: Redacted raw attempt facts - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/call-attempts/{attempt_id}: - parameters: - - name: attempt_id - in: path - required: true - schema: {type: string} - get: - tags: [admin-statistics] - operationId: getCallAttempt - security: [{SipAdminBearer: []}] - responses: - '200': - description: One redacted attempt fact - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /admin/v1/audit: - get: - tags: [admin-audit] - operationId: listAudit - security: [{SipAdminBearer: []}] - parameters: - - {$ref: '#/components/parameters/Limit'} - - {$ref: '#/components/parameters/ResourceFilter'} - - {$ref: '#/components/parameters/RequestFilter'} - - {$ref: '#/components/parameters/ActorFilter'} - responses: - '200': - description: Immutable audit entries - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - /admin/v1/operations/{operation_id}: - parameters: - - name: operation_id - in: path - required: true - schema: {type: string} - get: - tags: [admin-audit] - operationId: getOperation - security: [{SipAdminBearer: []}] - responses: - '200': - description: Durable operation state for retry/recovery - content: - application/json: - schema: {type: object} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} - /readonly/v1/sip/trunks: - get: - tags: [saas-readonly] - operationId: listAuthorizedTrunks - security: [{SaasTrunkReadBearer: []}] - responses: - '200': - description: Published Trunks authorized for this SaaS principal - content: - application/json: - schema: - $ref: '#/components/schemas/ReadonlyTrunkList' - '401': {$ref: '#/components/responses/Unauthorized'} - /readonly/v1/sip/trunks/{trunk_id}: - parameters: - - {$ref: '#/components/parameters/TrunkId'} - get: - tags: [saas-readonly] - operationId: getAuthorizedTrunk - security: [{SaasTrunkReadBearer: []}] - responses: - '200': - description: Published, sanitized Trunk metadata - content: - application/json: - schema: {$ref: '#/components/schemas/ReadonlyTrunk'} - '401': {$ref: '#/components/responses/Unauthorized'} - '404': {$ref: '#/components/responses/NotFound'} -components: - securitySchemes: - SipAdminBearer: - type: http - scheme: bearer - bearerFormat: opaque - description: >- - Dedicated operator/backend credential for SIP management writes. It is - not accepted by the SaaS read-only API or ordinary scheduling API. - SaasTrunkReadBearer: - type: http - scheme: bearer - bearerFormat: opaque - description: >- - Dedicated SaaS read-only credential. It cannot publish, modify, disable, - rollback, or access Cell management. - parameters: - ProviderId: - name: provider_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - TrunkId: - name: trunk_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - CellId: - name: cell_id - in: path - required: true - schema: {type: string, pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$'} - IfMatch: - name: If-Match - in: header - required: true - description: Exact latest revision required for CAS; quotes are accepted. - schema: {type: integer, minimum: 0} - CellIdsFilter: - name: cell_ids - in: query - required: false - schema: {type: string} - CellIdFilter: - name: cell_id - in: query - required: false - schema: {type: string} - ProviderFilter: - name: provider_id - in: query - required: false - schema: {type: string} - TrunkFilter: - name: trunk_id - in: query - required: false - schema: {type: string} - TrunkStatusFilter: - name: status - in: query - required: false - schema: {type: string} - ResourceFilter: - name: resource_id - in: query - required: false - schema: {type: string} - ActorFilter: - name: actor - in: query - required: false - schema: {type: string} - From: - name: from - in: query - required: false - schema: {type: string, format: date-time} - To: - name: to - in: query - required: false - schema: {type: string, format: date-time} - StatsMode: - name: mode - in: query - required: false - schema: {type: string, enum: [mock, mixed, real]} - EgressFilter: - name: egress_pool_id - in: query - required: false - schema: {type: string} - Granularity: - name: granularity - in: query - required: false - schema: {type: string, enum: [minute, hour, day]} - Limit: - name: limit - in: query - required: false - schema: {type: integer, minimum: 1, maximum: 200} - Cursor: - name: cursor - in: query - required: false - schema: {type: string} - RequestFilter: - name: request_id - in: query - required: false - schema: {type: string} - RequestId: - name: X-Request-ID - in: header - required: true - schema: {type: string, minLength: 1, maxLength: 128} - responses: - BadRequest: - description: Invalid configuration or request - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Unauthorized: - description: Missing or wrong authentication domain - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Forbidden: - description: Credential lacks the required scope - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - Conflict: - description: CAS conflict or no compatible Cell - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - NotFound: - description: Resource is not visible or does not exist - content: - application/json: - schema: {$ref: '#/components/schemas/ErrorResponse'} - schemas: - Mode: - type: string - enum: [mock, real] - StatsMode: - type: string - enum: [mock, mixed, real] - Health: - type: object - additionalProperties: false - required: [status, mode] - properties: - status: {type: string, const: ok} - mode: {$ref: '#/components/schemas/Mode'} - CodecProfile: - type: object - additionalProperties: false - required: [allowed, preferred] - properties: - allowed: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - preferred: {type: string, enum: [PCMA, PCMU]} - SipConfig: - type: object - additionalProperties: false - required: [host, port, transport, auth_mode, register] - properties: - host: {type: string, minLength: 1, maxLength: 253} - port: {type: integer, minimum: 1, maximum: 65535} - transport: {type: string, enum: [udp, tcp, tls]} - auth_mode: {type: string, enum: [ip, digest]} - register: {type: boolean} - credential_ref: - type: string - writeOnly: true - description: >- - Secret-store reference only; plaintext credentials are forbidden. - VerificationRequest: - type: object - additionalProperties: false - required: [revision, check_name, result] - properties: - revision: {type: integer, minimum: 1} - check_name: - type: string - enum: - - transport - - registration_auth - - caller_id_rules - - codec - - capacity - - whitelist - result: - type: string - enum: [confirmed, failed, unknown, not_applicable] - evidence_ref: {type: string, maxLength: 512} - checked_by: {type: string, maxLength: 128} - TrunkConfig: - type: object - additionalProperties: false - required: - - provider_id - - display_name - - enabled - - sip - - codec_profile - - caller_ids - - dial_prefix - - egress_pool_id - - max_concurrency - - max_cps - properties: - provider_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - display_name: {type: string, minLength: 1, maxLength: 256} - enabled: {type: boolean} - sip: {$ref: '#/components/schemas/SipConfig'} - codec_profile: {$ref: '#/components/schemas/CodecProfile'} - caller_ids: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, minLength: 1, maxLength: 128} - dial_prefix: {type: string, maxLength: 32} - egress_pool_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - max_concurrency: {type: integer, minimum: 1} - max_cps: {type: integer, minimum: 1} - CellConfig: - type: object - additionalProperties: false - required: [egress_pool_id, codec_capabilities, status, max_concurrency] - properties: - egress_pool_id: - type: string - pattern: '^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$' - codec_capabilities: - type: array - minItems: 1 - uniqueItems: true - items: {type: string, enum: [PCMA, PCMU]} - status: {type: string, enum: [healthy, draining, disabled]} - max_concurrency: {type: integer, minimum: 1} - management_url: - type: string - format: uri - pattern: '^https://' - description: >- - mTLS Cell Agent endpoint. Required when mode=real; credentials and - query strings are not allowed. - RevisionInfo: - type: object - additionalProperties: false - required: [revision, state, created_at, created_by] - properties: - revision: {type: integer, minimum: 1} - state: {type: string, enum: [draft, publishing, published, superseded]} - config_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - created_at: {type: string, format: date-time} - created_by: {type: string} - AdminTrunk: - type: object - required: - - mode - - trunk_id - - provider_id - - latest_revision - - active_revision - - active_status - - status - - compatible_cell_ids - - latest - - active - - versions - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunk_id: {type: string} - provider_id: {type: string} - latest_revision: {type: integer, minimum: 1} - active_revision: {type: integer, minimum: 0} - active_status: {type: string, enum: [draft, published, disabled]} - status: {type: string, enum: [draft, published, disabled]} - updated_at: {type: string, format: date-time} - compatible_cell_ids: {type: array, items: {type: string}} - latest: {$ref: '#/components/schemas/TrunkView'} - active: {$ref: '#/components/schemas/TrunkView'} - versions: - type: array - items: - $ref: '#/components/schemas/RevisionInfo' - TrunkView: - allOf: - - {$ref: '#/components/schemas/TrunkConfig'} - - type: object - properties: - trunk_id: {type: string} - credential_configured: {type: boolean} - asterisk_allow: - type: array - items: {type: string, enum: [alaw, ulaw]} - config_sha256: {type: string, pattern: '^[a-f0-9]{64}$'} - ReadonlyTrunk: - type: object - required: - - mode - - trunk_id - - provider_id - - revision - - status - - config - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunk_id: {type: string} - provider_id: {type: string} - revision: {type: integer, minimum: 1} - status: {type: string, const: published} - updated_at: {type: string, format: date-time} - config: {$ref: '#/components/schemas/TrunkView'} - AdminTrunkList: - type: object - required: [mode, trunks] - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunks: {type: array, items: {$ref: '#/components/schemas/AdminTrunk'}} - ReadonlyTrunkList: - type: object - required: [mode, trunks] - properties: - mode: {$ref: '#/components/schemas/Mode'} - trunks: - type: array - items: - $ref: '#/components/schemas/ReadonlyTrunk' - Cell: - type: object - required: [mode, cell_id, revision, config, updated_at, updated_by] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cell_id: {type: string} - revision: {type: integer, minimum: 1} - config: {$ref: '#/components/schemas/CellConfig'} - cloud_instance_id: {type: string} - instance_name: {type: string} - region: {type: string} - boot_id: {type: string} - updated_at: {type: string, format: date-time} - updated_by: {type: string} - Publication: - type: object - required: [trunk_id, revision, cell_id, status, updated_at] - properties: - trunk_id: {type: string} - revision: {type: integer, minimum: 1} - cell_id: {type: string} - status: {type: string, enum: [pending, applied, failed]} - error_code: {type: [string, 'null']} - applied_at: {type: [string, 'null'], format: date-time} - target_digest: {type: string} - local_revision: {type: integer, minimum: 0} - local_digest: {type: string} - operation_id: {type: string} - updated_at: {type: string, format: date-time} - AuditEntry: - type: object - required: - - audit_id - - resource_type - - resource_id - - action - - revision - - actor - - details_json - - created_at - properties: - audit_id: {type: string} - resource_type: {type: string, const: trunk} - resource_id: {type: string} - action: - type: string - enum: - [ - upsert, - publish, - publish_failed, - disable, - disable_failed, - rollback, - rollback_failed, - ] - revision: {type: integer, minimum: 0} - actor: {type: string} - request_id: {type: [string, 'null']} - details_json: {type: string} - created_at: {type: string, format: date-time} - ProviderInput: - type: object - additionalProperties: false - required: [display_name, lifecycle] - properties: - display_name: {type: string, minLength: 1, maxLength: 256} - notes: {type: string, maxLength: 2000} - lifecycle: {type: string, enum: [active, archived]} - Provider: - allOf: - - {$ref: '#/components/schemas/ProviderInput'} - - type: object - required: [provider_id, revision, trunk_count, created_at, updated_at] - properties: - provider_id: {type: string} - revision: {type: integer, minimum: 1} - trunk_count: {type: integer, minimum: 0} - created_at: {type: string, format: date-time} - updated_at: {type: string, format: date-time} - updated_by: {type: string} - ProviderList: - type: object - required: [mode, providers] - properties: - mode: {$ref: '#/components/schemas/Mode'} - providers: {type: array, items: {$ref: '#/components/schemas/Provider'}} - ProviderResponse: - type: object - required: [mode, provider] - properties: - mode: {$ref: '#/components/schemas/Mode'} - provider: {$ref: '#/components/schemas/Provider'} - ObservationInput: - type: object - additionalProperties: false - required: [cell_id, boot_id, sequence, observed_at, source, states] - properties: - observation_id: {type: string} - cell_id: {type: string} - trunk_id: {type: string} - boot_id: {type: string, minLength: 1} - sequence: {type: integer, minimum: 1} - observed_at: {type: string, format: date-time} - source: {type: string} - config_revision: {type: integer, minimum: 0} - states: {type: object} - occupancy: {type: object} - sample_id: {type: string} - StatusItem: - type: object - required: [mode, cell_id, availability, complete, missing_sources] - properties: - mode: {$ref: '#/components/schemas/Mode'} - cell_id: {type: string} - availability: {type: string, enum: [healthy, stale, unknown, disabled]} - complete: {type: boolean} - observed_at: {type: [string, 'null'], format: date-time} - received_at: {type: [string, 'null'], format: date-time} - observation_age_seconds: {type: [integer, 'null'], minimum: 0} - clock_skew: {type: boolean} - reason: {type: string} - boot_id: {type: string} - sequence: {type: integer, minimum: 1} - config_revision: {type: integer, minimum: 1} - config_status: {type: string} - egress_pool_id: {type: string} - eligibility: {type: string} - missing_sources: {type: array, items: {type: string}} - states: {type: object} - occupancy: {type: object} - trunks: {type: array, items: {type: object}} - publication: {type: object} - StatusResponse: - type: object - required: [mode, complete, cells] - properties: - mode: {$ref: '#/components/schemas/Mode'} - complete: {type: boolean} - generated_at: {type: string, format: date-time} - data_as_of: {type: [string, 'null'], format: date-time} - coverage: {type: object} - cells: {type: array, items: {$ref: '#/components/schemas/StatusItem'}} - StatisticsSummary: - type: object - required: [mode, from, to, complete, metrics] - properties: - mode: {$ref: '#/components/schemas/StatsMode'} - from: {type: string, format: date-time} - to: {type: string, format: date-time} - timezone: {type: string} - definition_version: {type: string} - filters: {type: object} - complete: {type: boolean} - missing_sources: {type: array, items: {type: string}} - unresolved_count: {type: integer, minimum: 0} - data_as_of: {type: [string, 'null'], format: date-time} - metrics: {type: object} - failure_reasons: {type: array, items: {type: object}} - realtime: {type: object} - TimeseriesResponse: - type: object - required: [mode, from, to, granularity, complete, series] - properties: - mode: {$ref: '#/components/schemas/StatsMode'} - from: {type: string, format: date-time} - to: {type: string, format: date-time} - timezone: {type: string} - definition_version: {type: string} - filters: {type: object} - granularity: {type: string, enum: [minute, hour, day]} - complete: {type: boolean} - series: {type: array, items: {type: object}} - ErrorResponse: - type: object - required: [error] - properties: - error: - type: object - required: [code, message] - properties: - code: {type: string} - message: {type: string} - fields: {type: object} - request_id: {type: string} diff --git a/contracts/upstream/manifest.txt b/contracts/upstream/manifest.txt index ec376e3..007f4a3 100644 --- a/contracts/upstream/manifest.txt +++ b/contracts/upstream/manifest.txt @@ -49,7 +49,7 @@ sha256=103ff072caafeb8a0399dccb27bc0619068e9b35baf738054fdfb3c225135c78 contract sha256=371ee1ddc2f8626215f90b9e64de79d932b757f79b84ad1a55ccdd713d9e1812 contracts/upstream/v1/jcs-golden.json sha256=ade0f2dcf4247351db82ca7498941b925c832ef1ee6d546c5bf34a4921011c68 contracts/upstream/v1/mq-topology.json sha256=d566899abbc8f0f8404cfe79ea58b0d1e7bf7e9fc663b09b282c15d5c74f505d contracts/upstream/v1/mq.schema.json -sha256=79192cfb7838a42fcb373347080ca08429083b4c3ed1f867f587a9e0e195a4a1 contracts/upstream/v1/oss-upload.schema.json -sha256=2aa7cd3f4fa07f7e1a3037107fa7a56183f28370ea06a2a9b8dc18c8790eee2d contracts/upstream/v1/p1-development-profile.json -sha256=e0f3ec455bb7fcaff4416ac4d8e3ccddb8f838b85485c85719e594d1f8896d20 contracts/upstream/v1/p1-development-profile.schema.json +sha256=b8f0d0fa9fbdd5bfa47e1b3bdb995cf0d26de4a5267414fc6c4ec3a2b0982b02 contracts/upstream/v1/oss-upload.schema.json +sha256=bbb0a9da7f5493ccc0bc6a9f18fd164dc222a380623ae8e03f955786ac0ccaad contracts/upstream/v1/p1-development-profile.json +sha256=21740f2119f2793d93db5f5d794ec455840442ec7eec9d2d0f105a09c7820ecf contracts/upstream/v1/p1-development-profile.schema.json sha256=bcdeb2e5152efe23a9eeca04eca7effbfbf7a897f66079d68fb23aa87ede64be contracts/upstream/v1/static-cell-artifact.schema.json diff --git a/contracts/upstream/v1/manifest.json b/contracts/upstream/v1/manifest.json index 36e77d4..67e5989 100644 --- a/contracts/upstream/v1/manifest.json +++ b/contracts/upstream/v1/manifest.json @@ -48,9 +48,9 @@ "jcs-golden.json": "371ee1ddc2f8626215f90b9e64de79d932b757f79b84ad1a55ccdd713d9e1812", "mq-topology.json": "ade0f2dcf4247351db82ca7498941b925c832ef1ee6d546c5bf34a4921011c68", "mq.schema.json": "d566899abbc8f0f8404cfe79ea58b0d1e7bf7e9fc663b09b282c15d5c74f505d", - "oss-upload.schema.json": "79192cfb7838a42fcb373347080ca08429083b4c3ed1f867f587a9e0e195a4a1", - "p1-development-profile.json": "2aa7cd3f4fa07f7e1a3037107fa7a56183f28370ea06a2a9b8dc18c8790eee2d", - "p1-development-profile.schema.json": "e0f3ec455bb7fcaff4416ac4d8e3ccddb8f838b85485c85719e594d1f8896d20", + "oss-upload.schema.json": "b8f0d0fa9fbdd5bfa47e1b3bdb995cf0d26de4a5267414fc6c4ec3a2b0982b02", + "p1-development-profile.json": "bbb0a9da7f5493ccc0bc6a9f18fd164dc222a380623ae8e03f955786ac0ccaad", + "p1-development-profile.schema.json": "21740f2119f2793d93db5f5d794ec455840442ec7eec9d2d0f105a09c7820ecf", "static-cell-artifact.schema.json": "bcdeb2e5152efe23a9eeca04eca7effbfbf7a897f66079d68fb23aa87ede64be" } } diff --git a/contracts/upstream/v1/oss-upload.schema.json b/contracts/upstream/v1/oss-upload.schema.json index 86b3132..595b0a1 100644 --- a/contracts/upstream/v1/oss-upload.schema.json +++ b/contracts/upstream/v1/oss-upload.schema.json @@ -1,205 +1,56 @@ { "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://go-sip.local/contracts/v1/oss-upload.schema.json", - "title": "Recording upload control-plane messages", + "title": "Dispatcher-issued recording upload grant", "type": "object", - "required": [ - "kind" - ], + "additionalProperties": false, "properties": { "kind": { - "type": "string" + "const": "grant" + }, + "upload_id": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "recording_id": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "upload_url": { + "type": "string", + "format": "uri", + "pattern": "^https://" + }, + "required_headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "expires_at": { + "type": "string", + "format": "date-time" + }, + "max_bytes": { + "type": "integer", + "minimum": 1 + }, + "object_binding": { + "type": "string", + "minLength": 1, + "maxLength": 256 } }, - "oneOf": [ - { - "additionalProperties": false, - "properties": { - "kind": { - "const": "request" - }, - "upload_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "recording_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "call_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "size_bytes": { - "type": "integer", - "minimum": 1 - }, - "checksum_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "format": { - "enum": [ - "wav", - "raw_pcm", - "pcma" - ] - }, - "channels": { - "const": 1 - }, - "sample_rate_hz": { - "type": "integer", - "minimum": 8000 - }, - "duration_ms": { - "type": "integer", - "minimum": 1 - } - }, - "required": [ - "upload_id", - "recording_id", - "call_id", - "size_bytes", - "checksum_sha256", - "format", - "channels", - "sample_rate_hz", - "duration_ms" - ] - }, - { - "additionalProperties": false, - "properties": { - "kind": { - "const": "grant" - }, - "upload_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "recording_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "upload_url": { - "type": "string", - "format": "uri", - "pattern": "^https://" - }, - "required_headers": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "expires_at": { - "type": "string", - "format": "date-time" - }, - "max_bytes": { - "type": "integer", - "minimum": 1 - }, - "object_binding": { - "type": "string", - "minLength": 1, - "maxLength": 256 - } - }, - "required": [ - "upload_id", - "recording_id", - "upload_url", - "required_headers", - "expires_at", - "max_bytes", - "object_binding" - ] - }, - { - "additionalProperties": false, - "properties": { - "kind": { - "const": "complete" - }, - "upload_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "recording_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "size_bytes": { - "type": "integer", - "minimum": 1 - }, - "checksum_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - }, - "etag": { - "type": [ - "string", - "null" - ], - "maxLength": 256 - } - }, - "required": [ - "upload_id", - "recording_id", - "size_bytes", - "checksum_sha256", - "etag" - ] - }, - { - "additionalProperties": false, - "properties": { - "kind": { - "const": "verified" - }, - "upload_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "recording_id": { - "type": "string", - "minLength": 1, - "maxLength": 128 - }, - "oss_id": { - "type": "string", - "minLength": 1, - "maxLength": 512 - }, - "verified_at": { - "type": "string", - "format": "date-time" - }, - "checksum_sha256": { - "type": "string", - "pattern": "^[a-f0-9]{64}$" - } - }, - "required": [ - "upload_id", - "recording_id", - "oss_id", - "verified_at", - "checksum_sha256" - ] - } + "required": [ + "kind", + "upload_id", + "recording_id", + "upload_url", + "required_headers", + "expires_at", + "max_bytes", + "object_binding" ] } diff --git a/contracts/upstream/v1/p1-development-profile.json b/contracts/upstream/v1/p1-development-profile.json index 21b0db6..ef2a9f8 100644 --- a/contracts/upstream/v1/p1-development-profile.json +++ b/contracts/upstream/v1/p1-development-profile.json @@ -16,7 +16,6 @@ "final_permit_ttl_ms": 1000 }, "modes": ["full_ai", "asr_only"], - "retention": {"keep_unverified_assets": true, "delete_only_after_verified": true, "backup_kind": "local-sqlite-wal-consistent"}, "status": "development-only-not-production-approval", "real_budget": "unknown", "operator_approval": "not-granted" diff --git a/contracts/upstream/v1/p1-development-profile.schema.json b/contracts/upstream/v1/p1-development-profile.schema.json index b7c9be8..bcf9d4d 100644 --- a/contracts/upstream/v1/p1-development-profile.schema.json +++ b/contracts/upstream/v1/p1-development-profile.schema.json @@ -13,7 +13,6 @@ "topology", "limits", "modes", - "retention", "status" ], "properties": { @@ -120,29 +119,6 @@ ] } }, - "retention": { - "type": "object", - "additionalProperties": false, - "required": [ - "keep_unverified_assets", - "delete_only_after_verified", - "backup_kind" - ], - "properties": { - "keep_unverified_assets": { - "const": true - }, - "delete_only_after_verified": { - "const": true - }, - "backup_kind": { - "enum": [ - "local-sqlite-wal-consistent", - "not-configured" - ] - } - } - }, "status": { "const": "development-only-not-production-approval" }, diff --git a/docs/contracts/dispatcher-agent.md b/docs/contracts/dispatcher-agent.md index 99aa6fd..abc4311 100644 --- a/docs/contracts/dispatcher-agent.md +++ b/docs/contracts/dispatcher-agent.md @@ -166,7 +166,7 @@ Dispatcher 从已校验的 `call.execute` 构造 binding;Agent 回报不能改 响应:`ResponseMeta`、`state`、`runtime_configs[]`、`UploadPolicy`: - `ConfigReference`:`kind`、`version`、`sha256`、`source`; -- `UploadPolicy`:`enabled`、`max_asset_bytes`、`min_retention_ms`、`allowed_hosts[]`。 +- `UploadPolicy`:`enabled`、`max_asset_bytes`、`allowed_hosts[]`。 当前 Dispatcher 启动绑定流程只执行 status + activate,没有调用 bootstrap。 @@ -284,7 +284,7 @@ Dispatcher 侧额外要求: - 同upload ID、同operation ID及原请求正文返回原grant,包括原到期时间;绑定或正文不同返回冲突; - 重新签发必须使用显式新请求身份,保持原资产及对象绑定;不因原请求重放自动续期,不向SaaS申请TOKEN。 -新请求当前返回 `UPLOAD_STATE_REQUESTED`;持久层状态为 `granted`。`UPLOADING` 枚举存在,但当前 Dispatcher handler 不把 Agent 的 PUT 过程映射为该状态。 +新请求当前返回 `UPLOAD_STATE_REQUESTED`;持久层状态为 `granted`。上传通知可靠入队后返回 `UPLOAD_STATE_COMPLETED`,失败返回 `UPLOAD_STATE_FAILED`。 目标流程为 **D 依据自身配置文件向 A 提供临时上传 TOKEN,不向 SaaS 申请 OSS 配置/TOKEN**。D 侧配置缺失/无效时明确失败,不切换配置源;长期凭据不交给 A,不写入示例、日志或证据。当前TOKEN形态为官方SDK生成的受限预签名PUT信息,映射到UploadGrant;它不是OSS原生强制一次性凭据,Agent通过持久尝试状态保证每次授权尝试最多一次PUT。 diff --git a/docs/contracts/saas-dispatcher.md b/docs/contracts/saas-dispatcher.md index 89b7781..27d83a0 100644 --- a/docs/contracts/saas-dispatcher.md +++ b/docs/contracts/saas-dispatcher.md @@ -143,7 +143,7 @@ P1 仍只运行一个单活 Dispatcher。现在必须在合同及本地路由测 } ``` -源枚举为 `command.result`、`call.status`、`transcript.updated`、`call.finished`、`recording.ready`、`recording.failed`、`transcript.failed`、`contact.opt_out`。它们不自动覆盖新增的配置/查询/上传响应消息。 +源枚举为 `command.result`、`call.status`、`transcript.updated`、`call.finished`、`recording.uploaded`、`recording.failed`、`transcript.failed`、`contact.opt_out`。它们不自动覆盖新增的配置/查询/上传响应消息。 事件同时通过 `mq.schema.json` 和 `event-payloads.schema.json`;`EventBuilder` 拒绝未知字段。旧实现由 SQLite 按 `aggregate_type + aggregate_id` 递增版本,Agent 不能指定版本;新基线仍须验证租户/Dispatcher 归属,不将旧实现等同完整隔离。 @@ -171,12 +171,12 @@ P1 仍只运行一个单活 Dispatcher。现在必须在合同及本地路由测 | `call.status` | `call_id`, `execution_id`, `call_state`, `call_version`, `attempt_id`, `attempt_state` | | `transcript.updated` | `call_id`, `turn_id`, `segment_id`, `role`, `revision`, `text`, `is_final`, `start_ms`, `end_ms`, `playback_state` | | `call.finished` | `call_id`, `execution_id`, `call_version`, `outcome`, `started_at`, `ended_at`, `duration_ms`, `reason_code` | -| `recording.ready` | `call_id`, `recording_id`, `oss_id`, `format`, `channels`, `sample_rate_hz`, `duration_ms`, `size_bytes`, `checksum_sha256` | +| `recording.uploaded` | `call_id`, `recording_id`, `upload_id`, `bucket`, `object_key`, `format`, `channels`, `sample_rate_hz`, `duration_ms`, `size_bytes`, `checksum_sha256` | | `recording.failed` | `call_id`, `recording_id`, `stage`, `reason_code`, `retryable` | | `transcript.failed` | `call_id`, `reason_code`, `retryable` | | `contact.opt_out` | `call_id`, `task_id`, `task_item_id`, `requested_at` | -v2已用`recording.uploaded`取代本项目的`recording.ready`;不得返回虚构OSS ID或等待SaaS verified。新字段与可靠入队边界见§6.1,旧表不作为v2校验依据。 +`recording.uploaded`只表示上传事实已可靠进入指定持久队列,不表示SaaS已消费或处理;字段与可靠入队边界见§6.1。 ### 4.4 Outbox 交付 diff --git a/docs/evidence/20260918-acceptance-matrix.md b/docs/evidence/20260918-acceptance-matrix.md index 202be1b..c30a968 100644 --- a/docs/evidence/20260918-acceptance-matrix.md +++ b/docs/evidence/20260918-acceptance-matrix.md @@ -6,7 +6,7 @@ | 门禁 | 本地结果 | 证据/未决项 | | --- | --- | --- | -| G0 / W01 契约发布 | **本地通过 / 外部阻塞** | 项目内 `contracts/archive/upstream/2026-09-18-p1-baseline` 已完成严格事件/双模式 AI/授权/OSS/静态制品/profile Schema、正反例与哈希;明确继承 dirty source 且非外部权威,真实预算/授权仍未签收。 | +| G0 / W01 契约发布 | **本地通过 / 外部阻塞** | 项目内早期 W01 契约快照已完成严格事件/双模式 AI/授权/OSS/静态制品/profile Schema、正反例与哈希;该历史快照已从当前工作树移除,明确继承 dirty source 且非外部权威,真实预算/授权仍未签收。 | | W02 Unary Proto/会话 | **本地通过 / 集成待验证** | `agent.v1.AgentControlService` Proto、生成 stubs、`proto/ERRORS.md`、Buf manifest 和生成/handler 测试通过;Dispatcher/Agent部署级运行会话仍需联测。 | | W03-a 工具链/依赖 | **本地通过** | `go.mod` Go 1.27.1、Cobra 双子命令、`go mod verify`、依赖许可证清单和 `govulncheck@v1.7.0` 无漏洞扫描;ARI/LLM/ASR/TTS 隔离 API/协议 Mock PoC 已记录,正式锁版和真实供应商仍未验收。 | | W03-c SQLite/MQ PoC | **本地通过 / 外部未验收** | inbox、幂等、outbox、publisher-confirm 边界、租户队列/版本化 exchange、lease、配额和控制 CAS 有 race 单测;`make mq-integration-local` 以 disposable RabbitMQ 4.1.8 验证 adapter confirm/ACK/permanent reject→DLQ/consumer cancellation,并验证 Dispatcher tenant consume→SQLite inbox/task/outbox→event publish;当前候选二进制另在 owner-authorized ECS 通过隔离 RabbitMQ 完成 `routed=true`、`inbox=1/task=1/outbox=1`,再由候选 Dispatcher flush 为 `task_status=accepted/outbox_status=published`(证据:`docs/evidence/20260918-rabbitmq-integration.md`);SaaS 侧使用版本化 contract/fixture Mock,边界记录在 `docs/evidence/20260919-local-saas-contract-mock.md`;没有批准 broker 版本/ACL/崩溃注入/SaaS application receipt。 | diff --git a/docs/evidence/20260918-contract-input-blocker.md b/docs/evidence/20260918-contract-input-blocker.md index ce83529..d8727ff 100644 --- a/docs/evidence/20260918-contract-input-blocker.md +++ b/docs/evidence/20260918-contract-input-blocker.md @@ -2,7 +2,7 @@ The user selected **provide formal W01/W02 artifacts and continue**. The only new candidate found in the parent worktree was copied read-only into -`contracts/archive/upstream/2026-09-17-snapshot/` and verified against its recorded +the pre-v1 contract snapshot from the repository history and verified against its recorded file hashes. It is not yet a formal release: diff --git a/docs/evidence/20260918-g0-status.md b/docs/evidence/20260918-g0-status.md index edaf950..7e7c6cb 100644 --- a/docs/evidence/20260918-g0-status.md +++ b/docs/evidence/20260918-g0-status.md @@ -49,7 +49,7 @@ repository is `go-sip`; local release manifests preserve the historical fact. ## References -- Project baseline: `contracts/archive/upstream/2026-09-18-p1-baseline/` +- Project baseline: the historical pre-v1 contract snapshot (removed from the current work tree) - Local evidence: `docs/evidence/20260918-local-development.json` - W05 SQLite restart evidence: `docs/evidence/20260918-w05-restart.md` - W06/W12 targeted local evidence: `docs/evidence/20260918-w06-w12-local.md` diff --git a/docs/evidence/20260918-local-development.json b/docs/evidence/20260918-local-development.json index ad44c05..510191d 100644 --- a/docs/evidence/20260918-local-development.json +++ b/docs/evidence/20260918-local-development.json @@ -3,7 +3,7 @@ "scope": "go-sip local development only", "working_tree": "dirty-project-worktree", "source_contract": { - "active_bundle": "contracts/archive/upstream/2026-09-18-p1-baseline", + "active_bundle": "contracts/upstream/v1", "release_kind": "project-owned-development-baseline", "external_authority": false, "source_bundle": "2026-09-17-snapshot", diff --git a/docs/plan-0918.md b/docs/plan-0918.md index 1641b6f..4e89cd5 100644 --- a/docs/plan-0918.md +++ b/docs/plan-0918.md @@ -22,7 +22,7 @@ 需求依据顺序: 1. 当前适用的用户确认和 [项目约束](../AGENTS.md)。已确认方向不重复索要审批;缺失字段、预算及偏离方案的变更不能自行补成“已批准”。 -2. 外部字段/路径/状态在外部权威闭包可用时来自上游版本化契约包;早期项目内 W01 基线已归档至 `contracts/archive/upstream/2026-09-18-p1-baseline`,当前代码只使用项目内唯一的 `contracts/upstream/v1` 契约包;未发生契约迁移前不新增或合并契约。内部接口来自项目内 `agent.v1` Proto;不能将未进入当前契约包的说明文字当作 Schema。 +2. 外部字段/路径/状态在外部权威闭包可用时来自上游版本化契约包;早期项目内 W01 基线不再属于当前工作树,当前代码只使用项目内唯一的 `contracts/upstream/v1` 契约包;未发生契约迁移前不新增或合并契约。内部接口来自项目内 `agent.v1` Proto;不能将未进入当前契约包的说明文字当作 Schema。 3. [G0确认方案](G0开发准备与契约冻结提案_v0.1.md)记录最新确认和待交付门禁;总体、通信、组件和验收文档补充实施细则。 4. 本计划只编排任务和阅读入口。若发现来源冲突,列明两个出处并暂停受影响部分;不得用计划、旧实现或 SDK 默认值覆盖权威合同。 @@ -32,7 +32,7 @@ 2. **每个 Dispatcher 有全局唯一、不重复的 ID 和独立接收 Topic/队列**。消息必须定向到指定 D,响应回原 D,来源可追溯;不能多个 D 共用一条队列竞争消费或广播后过滤。Dispatcher 身份不等于 tenant/Agent/Cell ID 或 `dispatcher_epoch`,租户独立队列与原值 `tenant_key` 仍保留。 3. 精确 ID 生成/持久化/重复身份处理、Topic/队列/绑定命名、信封关联/错误/超时以及新 routing key 的完整字节预算须由 W01 冻结;方向已经确认,但不能自行往严格旧 Schema 加字段。P1仍是单活 D,D1/D2 路由隔离只作本地契约/消息 fixture,不新增多 D 调度、HA、共享额度或生产资源。 4. **D↔A 仍为 Unary,A→OSS 仍直传**。MQ-only 不禁止 OSS/ARI/供应商 HTTP(S) 或 gRPC HTTP/2。OSS 配置由 D 配置文件提供,临时 TOKEN 由 D 向 A 提供,不再由 SaaS 下发;保留 D 签发能力。R12 提供原请求绑定的临时授权;R13 持久保存上传事实及原通知身份,并以指定队列可靠入队作为本项目完成条件。不等待 SaaS 处理,也不把本地 outbox 写入等同 MQ 入队。 -5. 旧 AI GET、控制/查询/补传 HTTP 和上传 HTTP 方案被本修订替代;`contracts/upstream/v1/` 是当前代码唯一使用的项目内 V1 合同包;未使用的旧快照和 OpenAPI 已移至 `contracts/archive/upstream/`,不能在包外另造兼容合同或绕过其哈希。未发生契约迁移前不新增或合并契约;禁止先实现猜测消息再补合同。 +5. 旧 AI GET、控制/查询/补传 HTTP 和上传 HTTP 方案被本修订替代;`contracts/upstream/v1/` 是当前代码唯一使用的项目内 V1 合同包;未使用的旧快照和 OpenAPI 不属于当前工作树,不能在包外另造兼容合同或绕过其哈希。未发生契约迁移前不新增或合并契约;禁止先实现猜测消息再补合同。 6. 文档修订阶段已结束;当前目标已获批准实施本项目契约、代码、配置和测试,由当前Agent独立执行,不启动子Agent。已确认细节见[MQ-only V1冻结方案](contracts/mq-only-v1-freeze-proposal.md),不重开已批准方向;仍不访问真实SaaS/供应商/云/拨号,本地隔离broker可用于合同测试。文档或局部代码完成不关闭§8.2联合门禁。 目标语义见 R8,当前内部实现事实与差异见 R9,完整 MQ 目标时序见 R10。R1–R6 或历史证据中与本修订冲突的旧传输、路由及通过结论,不得继续作为新接入依据;只读来源包的变更必须走新版本发布。 diff --git a/gen/agent/v1/agent.pb.go b/gen/agent/v1/agent.pb.go index 125cc38..a9e25a1 100644 --- a/gen/agent/v1/agent.pb.go +++ b/gen/agent/v1/agent.pb.go @@ -478,10 +478,8 @@ type UploadState int32 const ( UploadState_UPLOAD_STATE_UNSPECIFIED UploadState = 0 UploadState_UPLOAD_STATE_REQUESTED UploadState = 1 - UploadState_UPLOAD_STATE_UPLOADING UploadState = 2 UploadState_UPLOAD_STATE_COMPLETED UploadState = 3 UploadState_UPLOAD_STATE_FAILED UploadState = 4 - UploadState_UPLOAD_STATE_EXPIRED UploadState = 5 ) // Enum value maps for UploadState. @@ -489,18 +487,14 @@ var ( UploadState_name = map[int32]string{ 0: "UPLOAD_STATE_UNSPECIFIED", 1: "UPLOAD_STATE_REQUESTED", - 2: "UPLOAD_STATE_UPLOADING", 3: "UPLOAD_STATE_COMPLETED", 4: "UPLOAD_STATE_FAILED", - 5: "UPLOAD_STATE_EXPIRED", } UploadState_value = map[string]int32{ "UPLOAD_STATE_UNSPECIFIED": 0, "UPLOAD_STATE_REQUESTED": 1, - "UPLOAD_STATE_UPLOADING": 2, "UPLOAD_STATE_COMPLETED": 3, "UPLOAD_STATE_FAILED": 4, - "UPLOAD_STATE_EXPIRED": 5, } ) @@ -1608,13 +1602,12 @@ func (x *ConfigReference) GetSource() string { } type UploadPolicy struct { - state protoimpl.MessageState `protogen:"open.v1"` - Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` - MaxAssetBytes int64 `protobuf:"varint,2,opt,name=max_asset_bytes,json=maxAssetBytes,proto3" json:"max_asset_bytes,omitempty"` - MinRetentionMs int64 `protobuf:"varint,3,opt,name=min_retention_ms,json=minRetentionMs,proto3" json:"min_retention_ms,omitempty"` - AllowedHosts []string `protobuf:"bytes,4,rep,name=allowed_hosts,json=allowedHosts,proto3" json:"allowed_hosts,omitempty"` - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Enabled bool `protobuf:"varint,1,opt,name=enabled,proto3" json:"enabled,omitempty"` + MaxAssetBytes int64 `protobuf:"varint,2,opt,name=max_asset_bytes,json=maxAssetBytes,proto3" json:"max_asset_bytes,omitempty"` + AllowedHosts []string `protobuf:"bytes,4,rep,name=allowed_hosts,json=allowedHosts,proto3" json:"allowed_hosts,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *UploadPolicy) Reset() { @@ -1661,13 +1654,6 @@ func (x *UploadPolicy) GetMaxAssetBytes() int64 { return 0 } -func (x *UploadPolicy) GetMinRetentionMs() int64 { - if x != nil { - return x.MinRetentionMs - } - return 0 -} - func (x *UploadPolicy) GetAllowedHosts() []string { if x != nil { return x.AllowedHosts @@ -3899,12 +3885,11 @@ const file_agent_v1_agent_proto_rawDesc = "" + "\x04kind\x18\x01 \x01(\tR\x04kind\x12\x18\n" + "\aversion\x18\x02 \x01(\tR\aversion\x12\x16\n" + "\x06sha256\x18\x03 \x01(\tR\x06sha256\x12\x16\n" + - "\x06source\x18\x04 \x01(\tR\x06source\"\x9f\x01\n" + + "\x06source\x18\x04 \x01(\tR\x06source\"\x8d\x01\n" + "\fUploadPolicy\x12\x18\n" + "\aenabled\x18\x01 \x01(\bR\aenabled\x12&\n" + - "\x0fmax_asset_bytes\x18\x02 \x01(\x03R\rmaxAssetBytes\x12(\n" + - "\x10min_retention_ms\x18\x03 \x01(\x03R\x0eminRetentionMs\x12#\n" + - "\rallowed_hosts\x18\x04 \x03(\tR\fallowedHosts\"\x87\x03\n" + + "\x0fmax_asset_bytes\x18\x02 \x01(\x03R\rmaxAssetBytes\x12#\n" + + "\rallowed_hosts\x18\x04 \x03(\tR\fallowedHostsJ\x04\b\x03\x10\x04R\x10min_retention_ms\"\x87\x03\n" + "\x10ExecutionBinding\x12\x1b\n" + "\ttenant_id\x18\x01 \x01(\tR\btenantId\x12\x1d\n" + "\n" + @@ -4135,14 +4120,12 @@ const file_agent_v1_agent_proto_rawDesc = "" + "\tAssetKind\x12\x1a\n" + "\x16ASSET_KIND_UNSPECIFIED\x10\x00\x12\x18\n" + "\x14ASSET_KIND_RECORDING\x10\x01\x12\x19\n" + - "\x15ASSET_KIND_TRANSCRIPT\x10\x02*\xb2\x01\n" + + "\x15ASSET_KIND_TRANSCRIPT\x10\x02*\xb6\x01\n" + "\vUploadState\x12\x1c\n" + "\x18UPLOAD_STATE_UNSPECIFIED\x10\x00\x12\x1a\n" + "\x16UPLOAD_STATE_REQUESTED\x10\x01\x12\x1a\n" + - "\x16UPLOAD_STATE_UPLOADING\x10\x02\x12\x1a\n" + "\x16UPLOAD_STATE_COMPLETED\x10\x03\x12\x17\n" + - "\x13UPLOAD_STATE_FAILED\x10\x04\x12\x18\n" + - "\x14UPLOAD_STATE_EXPIRED\x10\x05*\x83\x02\n" + + "\x13UPLOAD_STATE_FAILED\x10\x04\"\x04\b\x02\x10\x02\"\x04\b\x05\x10\x05*\x16UPLOAD_STATE_UPLOADING*\x14UPLOAD_STATE_EXPIRED*\x83\x02\n" + "\bFactKind\x12\x19\n" + "\x15FACT_KIND_UNSPECIFIED\x10\x00\x12 \n" + "\x1cFACT_KIND_EXECUTION_ACCEPTED\x10\x01\x12\x19\n" + diff --git a/internal/store/migrations/003_uploads.sql b/internal/store/migrations/003_uploads.sql index 3c802f3..8859ffc 100644 --- a/internal/store/migrations/003_uploads.sql +++ b/internal/store/migrations/003_uploads.sql @@ -5,7 +5,6 @@ CREATE TABLE IF NOT EXISTS uploads ( grant BLOB NOT NULL, object_key TEXT NOT NULL, state TEXT NOT NULL CHECK (state IN ('granted', 'completed', 'failed')), - oss_id TEXT, created_at TEXT NOT NULL, completed_at TEXT ); diff --git a/internal/store/upload_notification_test.go b/internal/store/upload_notification_test.go index ba45d5e..21e2882 100644 --- a/internal/store/upload_notification_test.go +++ b/internal/store/upload_notification_test.go @@ -18,7 +18,7 @@ func TestUploadCompletionRequiresPublishedOriginalNotice(t *testing.T) { if err := s.BindDispatcherID(identityA); err != nil { t.Fatal(err) } - if err := s.InsertUpload(UploadRecord{UploadID: "upload-a", Binding: []byte("binding"), Asset: []byte("asset"), Grant: []byte("grant"), ObjectKey: "recordings/recording-a.wav", Bucket: "example-bucket", State: "granted", CreatedAt: now}); err != nil { + if _, err := s.IssueUploadGrant(UploadRecord{UploadID: "upload-a", Binding: []byte("binding"), Asset: []byte("asset"), Grant: []byte("grant"), ObjectKey: "recordings/recording-a.wav", Bucket: "example-bucket", State: "granted", CreatedAt: now}, "request-a", "request-hash-a"); err != nil { t.Fatal(err) } raw, err := contracts.Files.ReadFile("upstream/v1/examples/event-recording-uploaded.json") diff --git a/internal/store/uploads.go b/internal/store/uploads.go index 539cc92..54eec0a 100644 --- a/internal/store/uploads.go +++ b/internal/store/uploads.go @@ -47,28 +47,3 @@ func (s *Store) LoadUpload(uploadID string) (UploadRecord, error) { } return record, nil } - -func (s *Store) InsertUpload(record UploadRecord) error { - if record.UploadID == "" || len(record.Binding) == 0 || len(record.Asset) == 0 || len(record.Grant) == 0 || record.ObjectKey == "" || record.Bucket == "" || record.State != "granted" { - return errors.New("complete granted upload record is required") - } - if record.CreatedAt.IsZero() { - record.CreatedAt = s.now().UTC() - } - s.mu.Lock() - defer s.mu.Unlock() - tx, err := s.db.Begin() - if err != nil { - return err - } - defer tx.Rollback() - _, err = tx.Exec(`INSERT INTO uploads(upload_id,binding,asset,grant,object_key,state,created_at,completed_at) - VALUES(?,?,?,?,?,?,?,NULL)`, record.UploadID, record.Binding, record.Asset, record.Grant, record.ObjectKey, record.State, record.CreatedAt.UTC().Format(time.RFC3339Nano)) - if err != nil { - return fmt.Errorf("insert upload: %w", err) - } - if _, err := tx.Exec(`INSERT INTO upload_destinations(upload_id,bucket) VALUES(?,?)`, record.UploadID, record.Bucket); err != nil { - return err - } - return tx.Commit() -} diff --git a/proto/ERRORS.md b/proto/ERRORS.md index d03dd18..3d8e34b 100644 --- a/proto/ERRORS.md +++ b/proto/ERRORS.md @@ -50,8 +50,8 @@ request. An identical duplicate returns the original receipt; a digest mismatch is a conflict. - `RequestUpload`/`CompleteUpload`: `upload_id` and the asset checksum are - retained. Completion is returned only after the OSS/SaaS verification state - is known; a local PUT success is not `recording.ready`. + retained. Completion is returned only after the `recording.uploaded` fact is + durably queued; a local PUT success alone is not `recording.uploaded`. Read-only methods may be retried, but callers still preserve the original request and trace identity: `GetAgentStatus`, `GetBootstrap`, and diff --git a/proto/agent/v1/agent.proto b/proto/agent/v1/agent.proto index 2c55984..8a215e4 100644 --- a/proto/agent/v1/agent.proto +++ b/proto/agent/v1/agent.proto @@ -92,10 +92,10 @@ enum AssetKind { enum UploadState { UPLOAD_STATE_UNSPECIFIED = 0; UPLOAD_STATE_REQUESTED = 1; - UPLOAD_STATE_UPLOADING = 2; UPLOAD_STATE_COMPLETED = 3; UPLOAD_STATE_FAILED = 4; - UPLOAD_STATE_EXPIRED = 5; + reserved 2, 5; + reserved "UPLOAD_STATE_UPLOADING", "UPLOAD_STATE_EXPIRED"; } enum FactKind { @@ -222,8 +222,9 @@ message ConfigReference { message UploadPolicy { bool enabled = 1; int64 max_asset_bytes = 2; - int64 min_retention_ms = 3; repeated string allowed_hosts = 4; + reserved 3; + reserved "min_retention_ms"; } message ExecutionBinding { diff --git a/proto/manifest.json b/proto/manifest.json index 137a257..d4f98e6 100644 --- a/proto/manifest.json +++ b/proto/manifest.json @@ -24,8 +24,8 @@ }, { "path": "proto/ERRORS.md", - "bytes": 4706, - "sha256": "0fb4ae7a41c3e7127645e393ee175b660f2aba9f9d27b8c8c033f1f6c334d163" + "bytes": 4722, + "sha256": "794c2b5f901803a0d8f7febfda3295781b612270fcce64b4b7361106228a9295" }, { "path": "proto/README.md", @@ -34,13 +34,13 @@ }, { "path": "proto/agent/v1/agent.proto", - "bytes": 10681, - "sha256": "7eec2489bc7e18dfd6ea5a11f4eebfc27fe02431cbf6c6f123924b0e91c58d72" + "bytes": 10730, + "sha256": "81e2b9b89e0eea8fef0ca583acf83b1e314b3d4ac681f6164f5895060e4cf731" }, { "path": "gen/agent/v1/agent.pb.go", - "bytes": 144947, - "sha256": "af13ba8a2a6a5c8b0f7c66aa7c8a6d2a09829be6bc3a38dd4ab5ca79730fca0e" + "bytes": 144174, + "sha256": "18e870af711d7890ff80fe9095c82203d76c81402b7e333b76b37171ce5dfaaf" }, { "path": "gen/agent/v1/agent_grpc.pb.go", diff --git a/scripts/archive/publish-mq-v2.py b/scripts/archive/publish-mq-v2.py deleted file mode 100644 index 8fccbac..0000000 --- a/scripts/archive/publish-mq-v2.py +++ /dev/null @@ -1,278 +0,0 @@ -#!/usr/bin/env python3 -"""Reproduce the project-local v2 draft from approved rules and pinned v1 inputs. - -The v1 input is never changed. Upload delivery ends at the designated durable -MQ queue: no upload-session request, verified response or SaaS OSS ID protocol. -""" -import copy -import hashlib -import json -from pathlib import Path -from typing import Any - -import yaml - -ROOT = Path(__file__).resolve().parent.parent -OLD = ROOT / "contracts/upstream/2026-09-19-p1-v1" -NEW = ROOT / "contracts/upstream/2026-09-21-p1-v2" -BASE = "https://go-sip.local/contracts/2026-09-21-p1-v2/" -DID = "c046b893-8628-4589-ae50-619d049248a6" -AT = "2026-09-21T00:00:00Z" -SCHEMA = "https://json-schema.org/draft/2020-12/schema" -WRITTEN = set() - - -def emit_text(name, text): - path = NEW / name - path.parent.mkdir(parents=True, exist_ok=True) - path.write_text(text) - WRITTEN.add(name) - - -def emit(name, value): - emit_text(name, json.dumps(value, ensure_ascii=False, indent=2) + "\n") - - -def load_json(path): - try: - return json.loads(path.read_text()) - except (OSError, json.JSONDecodeError) as exc: - raise RuntimeError(f"Cannot load pinned source schema {path}") from exc - - -def ref(name): - return {"$ref": "#/$defs/" + name} - - -def obj(properties, required=None): - return {"type": "object", "additionalProperties": False, - "required": list(properties) if required is None else required, - "properties": properties} - - -def rewrite_refs(value, prefix): - if isinstance(value, list): - return [rewrite_refs(v, prefix) for v in value] - if not isinstance(value, dict): - return value - result = {k: rewrite_refs(v, prefix) for k, v in value.items()} - r = result.get("$ref", "") - if r.startswith("#/components/schemas/"): - result["$ref"] = "#/$defs/" + prefix + r.split("/")[-1] - return result - - -def uploaded_event_schema(value: Any) -> Any: - if isinstance(value, list): - return [uploaded_event_schema(v) for v in value] - if isinstance(value, dict): - return {k: uploaded_event_schema(v) for k, v in value.items()} - if value == "recording.ready": - return "recording.uploaded" - if value == "#/$defs/recording_ready": - return "#/$defs/recording_uploaded" - return value - - -# Preserve unrelated business schemas; the old package and its IDs stay intact. -for path in sorted(OLD.glob("*.schema.json")): - schema = load_json(path) - schema["$id"] = BASE + path.name - emit(path.name, schema) - -mq = load_json(OLD / "mq.schema.json") -events = load_json(OLD / "event-payloads.schema.json") -defs = mq["$defs"] -dispatcher_id = {"type": "string", "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"} -tenant_key = {"type": "string", "minLength": 1, "maxLength": 196, - "not": {"pattern": "(^|\\.)[*#](\\.|$)"}, - "$comment": "Runtime also enforces 196 UTF-8 bytes and each AMQP resource's 255-byte budget."} -command_types = ["call.execute", "task.control", "call.replay", "command.replay"] - -# Replace ready, rather than falsely reporting SaaS processing or an OSS ID. -uploaded = events["$defs"].pop("recording_ready") -uploaded["properties"].pop("oss_id") -uploaded["required"].remove("oss_id") -for name, schema in {"upload_id": ref("id"), "bucket": {"type": "string", "minLength": 1, "maxLength": 63}, "object_key": {"type": "string", "minLength": 1, "maxLength": 1024}}.items(): - uploaded["properties"][name] = schema - uploaded["required"].append(name) -events["$defs"]["recording_uploaded"] = uploaded -events = uploaded_event_schema(events) -if not isinstance(events, dict): - raise TypeError("event schema transformation must produce an object") -events["$id"] = BASE + "event-payloads.schema.json" -events["properties"]["schema_version"] = {"const": "2.0"} -events["properties"]["dispatcher_id"] = dispatcher_id -events["properties"]["tenant_key"] = tenant_key -events["required"].append("dispatcher_id") -events["$defs"]["command_result"]["properties"]["command_type"]["enum"] = command_types -emit("event-payloads.schema.json", events) - -defs["dispatcherId"] = dispatcher_id -defs["tenantKey"] = tenant_key -for filename, prefix in [("executor.openapi.yaml", "executor_"), ("ai-config.openapi.yaml", "ai_")]: - document = yaml.safe_load((OLD / filename).read_text()) - for name, schema in document["components"]["schemas"].items(): - defs[prefix + name] = rewrite_refs(schema, prefix) - - -def event_collection(kinds): - return {"type": "array", "items": { - "allOf": [{"$ref": "event-payloads.schema.json"}, - {"properties": {"event_type": {"enum": kinds}}}]}} - - -# Approved query gap closure: typed event collections and outbox counts. -defs["executor_Command"]["additionalProperties"] = False -call = defs["executor_Call"] -call["additionalProperties"] = False -call["properties"]["attempts"] = event_collection(["call.status"]) -call["properties"]["transcript"] = obj({"events": event_collection(["transcript.updated", "transcript.failed"])}) -call["properties"]["recordings"] = event_collection(["recording.uploaded", "recording.failed"]) -call["properties"]["delivery"] = obj({k: {"type": "integer", "minimum": 0} for k in ["pending", "retry", "dispatching", "published"]}) - -command = copy.deepcopy(defs.pop("executeCommand")) -command["properties"].update({"schema_version": {"const": "2.0"}, "dispatcher_id": ref("dispatcherId"), "tenant_key": ref("tenantKey"), "command_type": {"enum": command_types}, "payload": {"type": "object"}}) -command["required"].append("dispatcher_id") -control = copy.deepcopy(defs["executor_ControlRequest"]) -# The existing MQ envelope is the sole command_id authority, not a second body ID. -control["properties"].pop("command_id") -control["required"].remove("command_id") -control["properties"]["task_id"] = ref("id") -control["required"].append("task_id") -defs["taskControl"] = control -for name, target in [("callReplay", "call_id"), ("commandReplay", "source_command_id")]: - value = copy.deepcopy(defs["executor_ReplayRequest"]) - value["properties"].pop("command_id") - value["required"].remove("command_id") - value["properties"][target] = ref("id") - value["required"].append(target) - defs[name] = value -command["allOf"] = [{"if": {"properties": {"command_type": {"const": kind}}}, "then": {"properties": {"payload": ref(payload)}}} for kind, payload in zip(command_types, ["executePayload", "taskControl", "callReplay", "commandReplay"], strict=True)] -defs["command"] = command -defs["event"] = {"$ref": "event-payloads.schema.json"} - -# Flatten allOf so the source receipt's closed object permits the known config. -version = copy.deepcopy(defs["ai_AgentVersionReceipt"]) -version["properties"]["config"] = {"$ref": "ai-config.schema.json"} -version["required"].append("config") -defs["ai_AgentVersion"] = version -defs["aiConfigResult"] = obj({"snapshot": ref("ai_AgentVersion"), "authorization": {"$ref": "ai-authorization.schema.json"}}) -request_payloads = {"command.query": obj({"command_id": ref("id")}), "call.query": obj({"call_id": ref("id")}), "ai.config.request": obj({"agent_version_id": ref("id")})} -response_payloads = {"command.query.result": ref("executor_Command"), "call.query.result": ref("executor_Call"), "ai.config.result": ref("aiConfigResult")} -common = {"schema_version": {"const": "2.0"}, "message_type": {"type": "string"}, "message_id": ref("id"), "dispatcher_id": ref("dispatcherId"), "tenant_id": ref("id"), "tenant_key": ref("tenantKey"), "trace_id": ref("id"), "issued_at": {"type": "string", "format": "date-time"}} -request = obj({**common, "not_after": {"type": "string", "format": "date-time"}, "payload": {"type": "object"}}) -request["properties"]["message_type"] = {"enum": list(request_payloads)} -request["allOf"] = [{"if": {"properties": {"message_type": {"const": kind}}}, "then": {"properties": {"payload": payload}}} for kind, payload in request_payloads.items()] -defs["request"] = request -reasons = ["invalid_request", "not_found", "conflict", "expired", "not_authorized", "unavailable", "unsupported"] -response = obj({**common, "correlation_id": ref("id"), "status": {"enum": ["ok", "pending", "rejected"]}, "reason_code": {"type": "string"}, "payload": {"type": "object"}}) -response["properties"]["message_type"] = {"enum": list(response_payloads)} -response["allOf"] = [ - {"if": {"properties": {"status": {"const": "pending"}}}, "then": {"properties": {"reason_code": {"const": "waiting"}, "payload": obj({})}}}, - {"if": {"properties": {"status": {"const": "rejected"}}}, "then": {"properties": {"reason_code": {"enum": reasons}, "payload": obj({"detail": {"type": "string", "maxLength": 1024}, "retryable": {"type": "boolean"}})}}}, -] -for kind, payload in response_payloads.items(): - response["allOf"].append({"if": {"properties": {"status": {"const": "ok"}, "message_type": {"const": kind}}}, "then": {"properties": {"reason_code": {"const": "ok"}, "payload": payload}}}) -defs["response"] = response -mq["$id"] = BASE + "mq.schema.json" -mq["oneOf"] = [ref(k) for k in ["command", "event", "request", "response"]] - - -def local_refs(value): - if isinstance(value, list): - return set().union(*(local_refs(v) for v in value)) - if not isinstance(value, dict): - return set() - found = set() - if value.get("$ref", "").startswith("#/$defs/"): - found.add(value["$ref"].split("/")[2]) - for k, v in value.items(): - if k != "$defs": - found.update(local_refs(v)) - return found - - -# Do not publish unused HTTP-specific definitions as a second supported contract. -pending, reachable = local_refs(mq), set() -while pending: - name = pending.pop() - if name not in reachable: - reachable.add(name) - pending.update(local_refs(defs[name]) - reachable) -mq["$defs"] = {name: defs[name] for name in sorted(reachable)} -emit("mq.schema.json", mq) - -config = obj({"schema_version": {"const": "1.0"}, "dispatcher_id": dispatcher_id, "oss": obj({k: {"type": "string", "minLength": 1} for k in ["endpoint", "region", "bucket", "object_prefix", "access_key_id_env", "access_key_secret_env"]})}) -config.update({"$schema": SCHEMA, "$id": BASE + "dispatcher-config.schema.json"}) -config["properties"]["oss"]["properties"]["endpoint"].update({"format": "uri", "pattern": "^https?://"}) -for key in ["access_key_id_env", "access_key_secret_env"]: - config["properties"]["oss"]["properties"][key]["pattern"] = "^[A-Za-z_][A-Za-z0-9_]*$" -emit("dispatcher-config.schema.json", config) -emit("mq-topology.json", {"version": "2.0", "exchanges": {name: {"type": "topic", "durable": True} for name in ["agent-call.dispatchers.v2", "agent-call.saas.v2", "agent-call.dead-letter.v2"]}, "inbox_queue": "agent-call.d..t..v2", "dead_letter_queue": "agent-call.d..t..dlq.v2", "inbound_key": "d..t..in", "outbound_key": "d..t..out", "saas_queue": "agent-call.saas.events.v2", "owner_queue": "agent-call.d..owner.v2", "owner_exclusive": True, "business_queues_durable": True, "message_persistent": True, "publish_mandatory": True, "publisher_confirms": True, "tenant_key_max_utf8_bytes": 196, "message_max_bytes": 262144, "service_request_deadline_seconds": 30, "upload_token_seconds": 900}) - -cases = [] - - -def fixture(name, value, valid=True, schema="mq.schema.json"): - filename = "examples/" + name + ".json" - emit(filename, value) - cases.append({"file": filename, "schema": schema, "valid": valid}) - - -base = {"schema_version": "2.0", "dispatcher_id": DID, "tenant_id": "tenant-a", "tenant_key": "tenant-a", "trace_id": "trace-v2", "issued_at": AT} -execute = {**base, "command_id": "command-a", "command_type": "call.execute", "not_after": "2026-09-21T00:00:30Z", "payload": {"execution_id": "execution-a", "task_id": "task-a", "task_item_id": "item-a", "task_revision": 1, "callee": "15003164745", "route_policy_id": "route-a", "caller_profile_id": "caller-a", "agent_version_id": "version-a", "variables": {}, "ring_timeout_ms": 1000, "max_call_duration_ms": 10000}} -fixture("call-execute", execute) -for kind, payload in [("task.control", {"task_id": "task-a", "action": "pause", "expected_task_revision": 1, "active_call_policy": "drain", "reason": "local-test"}), ("call.replay", {"call_id": "call-a", "reason": "local-test"}), ("command.replay", {"source_command_id": "command-a", "reason": "local-test"})]: - fixture(kind.replace(".", "-"), {**execute, "command_id": kind + "-a", "command_type": kind, "payload": payload}) -for kind, payload in [("command.query", {"command_id": "command-a"}), ("call.query", {"call_id": "call-a"}), ("ai.config.request", {"agent_version_id": "version-a"})]: - fixture(kind.replace(".", "-"), {**base, "message_id": kind + "-a", "message_type": kind, "not_after": "2026-09-21T00:00:30Z", "payload": payload}) -reply = {**base, "message_id": "query-reply-a", "message_type": "command.query.result", "correlation_id": "command.query-a", "status": "ok", "reason_code": "ok"} -fixture("query-pending", {**reply, "status": "pending", "reason_code": "waiting", "payload": {}}) -fixture("query-rejected", {**reply, "status": "rejected", "reason_code": "not_found", "payload": {"detail": "command not found", "retryable": False}}) -fixture("dispatcher-config", {"schema_version": "1.0", "dispatcher_id": DID, "oss": {"endpoint": "https://oss.example.invalid", "region": "example-region", "bucket": "example-bucket", "object_prefix": "recordings", "access_key_id_env": "DISPATCHER_OSS_ACCESS_KEY_ID", "access_key_secret_env": "DISPATCHER_OSS_ACCESS_KEY_SECRET"}}, schema="dispatcher-config.schema.json") -fixture("invalid-v1", {**execute, "schema_version": "1.0"}, False) -fixture("invalid-wildcard", {**execute, "tenant_key": "tenant.#"}, False) -fixture("invalid-dispatcher", {**execute, "dispatcher_id": "dispatcher-a"}, False) - -# Every event and successful response has a fixture, not just a compilable schema. -event_examples = {} -for path in sorted((OLD / "examples").glob("event-*.json")): - event = load_json(path) - event.update({"schema_version": "2.0", "dispatcher_id": DID, "tenant_id": "tenant-a", "tenant_key": "tenant-a"}) - if "call_id" in event["payload"]: - event["payload"]["call_id"] = "call-a" - if event["aggregate_type"] == "call": - event["aggregate_id"] = "call-a" - name = path.stem - if event["event_type"] == "recording.ready": - event["event_type"] = "recording.uploaded" - event["payload"].pop("oss_id") - event["payload"].update({"upload_id": "upload-a", "bucket": "example-bucket", "object_key": "recordings/recording-a.wav"}) - name = "event-recording-uploaded" - event["event_id"] = event["event_type"] + "-event-a" - event_examples[event["event_type"]] = event - fixture(name, event, schema="event-payloads.schema.json") -command_result = {"command_id": "command-a", "command_type": "call.execute", "tenant_id": "tenant-a", "tenant_key": "tenant-a", "status": "accepted", "aggregate_version": 1} -fixture("command-query-result", {**reply, "payload": command_result}) -fixture("invalid-correlation", {k: v for k, v in {**reply, "payload": command_result}.items() if k != "correlation_id"}, False) -call_result = {"call_id": "call-a", "execution_id": event_examples["call.status"]["payload"]["execution_id"], "call_state": event_examples["call.status"]["payload"]["call_state"], "call_version": 1, "attempts": [event_examples["call.status"]], "transcript": {"events": [event_examples["transcript.updated"], event_examples["transcript.failed"]]}, "recordings": [event_examples["recording.uploaded"], event_examples["recording.failed"]], "delivery": {"pending": 1, "retry": 0, "dispatching": 0, "published": 0}, "snapshot_at": AT} -fixture("call-query-result", {**reply, "message_id": "call-query-reply-a", "message_type": "call.query.result", "correlation_id": "call.query-a", "payload": call_result}) -invalid_query = copy.deepcopy(call_result) -invalid_query["delivery"]["raw"] = {} -fixture("invalid-call-query-extra", {**reply, "message_type": "call.query.result", "payload": invalid_query}, False) -ai_config = load_json(OLD / "examples/agent-version-full-explicit.json") -ai_config["agent_version_id"] = "version-a" -config_digest = hashlib.sha256(json.dumps(ai_config, ensure_ascii=False, sort_keys=True, separators=(",", ":")).encode()).hexdigest() -snapshot = {"tenant_id": "tenant-a", "agent_version_id": "version-a", "status": "published", "immutable": True, "content_sha256": config_digest, "config": ai_config} -authorization = load_json(OLD / "examples/ai-authorization.json") -authorization.update({"tenant_id": "tenant-a", "tenant_key": "tenant-a", "agent_version_id": "version-a", "config_sha256": config_digest, "mode": ai_config["mode"]}) -fixture("ai-config-result", {**reply, "message_id": "ai-config-reply-a", "message_type": "ai.config.result", "correlation_id": "ai.config.request-a", "payload": {"snapshot": snapshot, "authorization": authorization}}) -emit("fixtures.json", cases) -emit_text("README.md", "# Project-local MQ-only v2\n\nApproved design: docs/contracts/mq-only-v2-freeze-proposal.md, amended by the enqueue-only upload goal.\nThis is a local project contract, not external SaaS acceptance. Old v1 files are untouched.\nPublisher: scripts/publish-mq-v2.py. Validator: go test ./contracts -run TestV2.\n\nUpload notification: recording.uploaded, no recording.ready, upload session or verified reply. Completion means persistent delivery to the designated durable MQ queue, mandatory routing and publisher confirm; not SaaS consumption.\nPayload: call_id, recording_id, upload_id, bucket, object_key, format, channels, sample_rate_hz, duration_ms, size_bytes, checksum_sha256. No TOKEN, credentials, signed URL or SaaS OSS ID.\n\nControl/replay command_id belongs solely to the envelope. Query nested structures reuse typed events and delivery counts. AI receipt/config composition is flattened without widening fields.\nSchema limits characters; runtime also checks UTF-8 bytes and aggregate response size. Oversized snapshots fail explicitly, never silently truncate.\n") -actual = {str(p.relative_to(NEW)) for p in NEW.rglob("*") if p.is_file() and p.name != "manifest.json"} -if extra := actual - WRITTEN: - raise RuntimeError(f"Unpublished/stale files remain in draft bundle; inspect explicitly: {sorted(extra)}") -files = {name: hashlib.sha256((NEW / name).read_bytes()).hexdigest() for name in sorted(WRITTEN)} -emit("manifest.json", {"version": "2026-09-21-p1-v2", "source": "project-approved-mq-only-v2", "derived_from": "2026-09-19-p1-v1", "source_files": {str(p.relative_to(OLD)): hashlib.sha256(p.read_bytes()).hexdigest() for p in sorted(OLD.rglob("*")) if p.is_file()}, "files": files}) -print(f"Published {len(files)} pinned project-local draft files in {NEW.relative_to(ROOT)}") diff --git a/scripts/archive/publish-mq-v3.py b/scripts/archive/publish-mq-v3.py deleted file mode 100644 index 69ab9fb..0000000 --- a/scripts/archive/publish-mq-v3.py +++ /dev/null @@ -1,111 +0,0 @@ -#!/usr/bin/env python3 -"""Publish the approved JCS digest revision without modifying older bundles.""" -import hashlib -import importlib -import json -import os -from pathlib import Path -import subprocess -import sys -import tempfile - -import jsonschema -from referencing import Registry, Resource - -ROOT = Path(__file__).resolve().parent.parent -OLD_VERSION = "2026-09-21-p1-v2" -VERSION = "2026-09-21-p1-v3" -OLD = ROOT / "contracts/upstream" / OLD_VERSION -NEW = OLD.parent / VERSION -MODULE = "github.com/cyberphone/json-canonicalization" -REVISION = "v0.0.0-20241213102144-19d51d7fe467" -info = json.loads(subprocess.check_output(["go", "mod", "download", "-json", MODULE + "@" + REVISION], cwd=ROOT)) -if info.get("Error") or info.get("Version") != REVISION: - raise RuntimeError("pinned JCS implementation unavailable") -sys.path.insert(0, str(Path(info["Dir"]) / "python3/src")) -canonicalize = importlib.import_module("org.webpki.json.Canonicalize").canonicalize - - -def encoded(value): - return (json.dumps(value, ensure_ascii=False, indent=2) + "\n").encode() - - -def digest(value): - return hashlib.sha256(canonicalize(value)).hexdigest() - - -manifest = json.loads((OLD / "manifest.json").read_text()) -files = {} -for name, expected in manifest["files"].items(): - raw = (OLD / name).read_bytes() - if hashlib.sha256(raw).hexdigest() != expected: - raise RuntimeError("source bundle hash mismatch: " + name) - files[name] = raw.replace(OLD_VERSION.encode(), VERSION.encode()) - -result = json.loads(files["examples/ai-config-result.json"]) -result["payload"]["snapshot"]["content_sha256"] = digest(result["payload"]["snapshot"]["config"]) -files["examples/ai-config-result.json"] = encoded(result) -oldest = ROOT / "contracts/upstream/2026-09-19-p1-v1/examples" -for name in ("agent-version.json", "agent-version-asr-only.json", "agent-version-full-explicit.json"): - files["examples/" + name] = (oldest / name).read_bytes() -authorization = json.loads((oldest / "ai-authorization.json").read_text()) -authorization["config_sha256"] = digest(json.loads(files["examples/agent-version-asr-only.json"])) -files["examples/ai-authorization.json"] = encoded(authorization) - -vectors = [ - {"name": "numbers", "input": '{"b":1.0,"a":[-0.0,1e30,4.50,2e-3]}'}, - {"name": "utf16-key-order", "input": '{"\\ue000":1,"\\ud800\\udc00":2}'}, - {"name": "strings", "input": '{"s":"\\u20ac/\\n","flag":false,"zero":0}'}, -] -for vector in vectors: - value = json.loads(vector["input"]) - vector["canonical"] = canonicalize(value).decode() - vector["sha256"] = digest(value) -files["jcs-golden.json"] = encoded(vectors) -files["ai-digest.json"] = encoded({ - "scope": "AI snapshot.config and authorization config_sha256 only", - "canonicalization": "RFC 8785 (JCS)", "digest": "SHA-256", "encoding": "lowercase hex", - "implementation": MODULE, "revision": REVISION, - "external_acceptance": False, - "invariants": ["No Unicode normalization", "Reject invalid UTF-8 and duplicate object keys", - "Preserve explicit zero/false versus absent fields", "No old-digest fallback"], -}) -files["README.md"] = (f"# {VERSION}\n\nProject-local JCS/SHA-256 revision approved by the user. " - f"Derived from {OLD_VERSION}; older packages are unchanged. Wire schema_version remains 2.0.\n\n" - "AI digests use RFC 8785 canonical UTF-8 bytes followed by SHA-256, lowercase hexadecimal. " - "This does not change file checksums, upload facts, command-body identity, or other hashes. " - "Numbers follow JCS IEEE-754 rules; no Unicode normalization is performed. " - "Explicit zero/false remain distinct from absent fields. No legacy digest fallback.\n\n" - "Local agreement and generated fixtures are not external SaaS acceptance.\n").encode() -# Validate positive and negative fixtures against an entirely offline registry -# before the directory becomes an immutable published bundle. -schemas = {name: json.loads(raw) for name, raw in files.items() if name.endswith(".schema.json")} -registry = Registry().with_resources((value["$id"], Resource.from_contents(value)) for value in schemas.values()) -for fixture in json.loads(files["fixtures.json"]): - validator = jsonschema.Draft202012Validator(schemas[fixture["schema"]], registry=registry, - format_checker=jsonschema.Draft202012Validator.FORMAT_CHECKER) - valid = validator.is_valid(json.loads(files[fixture["file"]])) - if valid != fixture["valid"]: - raise RuntimeError("fixture validation mismatch: " + fixture["file"]) -for name in ("agent-version.json", "agent-version-asr-only.json", "agent-version-full-explicit.json"): - jsonschema.Draft202012Validator(schemas["ai-config.schema.json"], registry=registry).validate(json.loads(files["examples/" + name])) -jsonschema.Draft202012Validator(schemas["ai-authorization.schema.json"], registry=registry).validate(authorization) - -files["manifest.json"] = encoded({ - "version": VERSION, "source": "project-approved-jcs-sha256", "derived_from": OLD_VERSION, - "source_manifest_sha256": hashlib.sha256((OLD / "manifest.json").read_bytes()).hexdigest(), - "files": {name: hashlib.sha256(raw).hexdigest() for name, raw in sorted(files.items())}, -}) -if NEW.exists(): - existing = {str(p.relative_to(NEW)): p.read_bytes() for p in NEW.rglob("*") if p.is_file()} - if existing != files: - raise RuntimeError("immutable destination differs; publish a new version instead") -else: - with tempfile.TemporaryDirectory(prefix=".jcs-publish-", dir=OLD.parent) as temporary: - stage = Path(temporary) / VERSION - for name, raw in files.items(): - target = stage / name - target.parent.mkdir(parents=True, exist_ok=True) - target.write_bytes(raw) - os.rename(stage, NEW) -print(VERSION, hashlib.sha256(files["manifest.json"]).hexdigest())