@7h3/protocol 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -323
- package/agentAdapter.d.ts +26 -0
- package/auditLog.d.ts +54 -0
- package/capability.d.ts +67 -0
- package/cborCodec.d.ts +34 -0
- package/conformanceVectors.d.ts +20 -0
- package/encryption.d.ts +85 -0
- package/envelopeCbor.d.ts +33 -0
- package/frameworkAdapters.d.ts +72 -0
- package/gateway.d.ts +53 -0
- package/grpcBinding.d.ts +29 -0
- package/httpBinding.d.ts +50 -0
- package/index.d.ts +39 -0
- package/index.js +3662 -0
- package/keyInfra.d.ts +64 -0
- package/keyRegistry.d.ts +9 -0
- package/keyRotation.d.ts +20 -0
- package/mcpGateway.d.ts +37 -0
- package/mcpTransports.d.ts +62 -0
- package/mcpWrapper.d.ts +83 -0
- package/otel.d.ts +65 -0
- package/package.json +13 -79
- package/policyEnforcer.d.ts +50 -0
- package/policyTelemetryFeedback.d.ts +11 -0
- package/protocol.d.ts +66 -0
- package/protocolAgent.d.ts +58 -0
- package/protocolBinary.d.ts +8 -0
- package/protocolCapabilities.d.ts +24 -0
- package/protocolReplay.d.ts +35 -0
- package/protocolTransport.d.ts +73 -0
- package/queueBinding.d.ts +43 -0
- package/rateLimiter.d.ts +18 -0
- package/{src/redisClient.ts → redisClient.d.ts} +25 -75
- package/replayStores.d.ts +98 -0
- package/revocation.d.ts +71 -0
- package/routePolicy.d.ts +30 -0
- package/runtimePolicy.d.ts +24 -0
- package/runtimePolicyManager.d.ts +15 -0
- package/runtimePolicyPresets.d.ts +11 -0
- package/signedResponse.d.ts +21 -0
- package/stream.d.ts +59 -0
- package/telemetry.d.ts +79 -0
- package/webhookBinding.d.ts +30 -0
- package/wsBinding.d.ts +52 -0
- package/.dockerignore +0 -19
- package/.github/dependabot.yml +0 -32
- package/.github/workflows/ci.yml +0 -31
- package/.github/workflows/publish.yml +0 -59
- package/.github/workflows/scorecard.yml +0 -37
- package/7h3.example.yaml +0 -125
- package/CHANGELOG.md +0 -92
- package/CONTRIBUTING.md +0 -82
- package/Dockerfile +0 -73
- package/GOVERNANCE.md +0 -62
- package/SECURITY.md +0 -70
- package/bench-results/replay-cache-full-1777891033256.json +0 -10
- package/bench-results/replay-cache-full-1777896317488.json +0 -10
- package/bench-results/replay-cache-full-1777900993184.json +0 -10
- package/bench-results/replay-cache-full-1777901019285.json +0 -10
- package/bench-results/replay-cache-quick-1777870170126.json +0 -10
- package/bench-results/signature-profiles-quick-1775875160079.json +0 -85
- package/bench-results/signature-profiles-quick-1775983539716.json +0 -85
- package/bench-results/signature-profiles-quick-1776237913190.json +0 -85
- package/bench-results/wire-codecs-full-1777891019803.json +0 -93
- package/bench-results/wire-codecs-full-1777896260964.json +0 -93
- package/bench-results/wire-codecs-full-1777901004247.json +0 -93
- package/bench-results/wire-codecs-quick-1775972879056.json +0 -93
- package/bench-results/wire-codecs-quick-1775983541111.json +0 -93
- package/bench-results/wire-codecs-quick-1776237914299.json +0 -93
- package/bench-results/wire-codecs-quick-1777841285236.json +0 -93
- package/bench-results/wire-codecs-quick-1777841321772.json +0 -93
- package/bench-results/wire-codecs-quick-1777841330408.json +0 -93
- package/bench-results/wire-codecs-quick-1777852886082.json +0 -93
- package/bench-results/wire-codecs-quick-1777852988773.json +0 -93
- package/bench-results/wire-codecs-quick-1777870188095.json +0 -93
- package/bench-results/wire-codecs-quick-1777870263918.json +0 -93
- package/bench-results/wire-codecs-quick-1777870455034.json +0 -93
- package/bench-results/wire-codecs-quick-1778816163081.json +0 -93
- package/bench-results/wire-codecs-quick-1778843936130.json +0 -93
- package/bin/7h3.ts +0 -385
- package/conformance/7h3_v0_1.json +0 -77
- package/conformance/7h3_v0_1_binary.json +0 -20
- package/conformance/aip_v0_1_binary.json +0 -20
- package/docker-compose.yaml +0 -77
- package/docs/ADOPTION_PLAN.md +0 -120
- package/docs/AGENTS.md +0 -77
- package/docs/AIP_RFC_v0.1.md +0 -97
- package/docs/AI_DECISION_CARD.md +0 -122
- package/docs/AI_RUNTIME_POLICY.json +0 -126
- package/docs/AI_RUNTIME_POLICY.yaml +0 -110
- package/docs/BACKPRESSURE_TUNING.md +0 -65
- package/docs/BENCHMARK_CLAIM_MATRIX.md +0 -42
- package/docs/BENCHMARK_REPORT_TEMPLATE.md +0 -169
- package/docs/BINARY_CODEC_BENCH.md +0 -23
- package/docs/CLEAN_CLONE_RUNBOOK.md +0 -36
- package/docs/CLOCK_SKEW_POLICY.md +0 -30
- package/docs/DISTRIBUTED_REPLAY.md +0 -142
- package/docs/FUZZ_CAMPAIGN.md +0 -121
- package/docs/GATEWAY.md +0 -195
- package/docs/KEY_MANAGEMENT_POLICY.md +0 -53
- package/docs/KEY_REVOCATION.md +0 -69
- package/docs/MCP_WRAPPER.md +0 -159
- package/docs/MIGRATION_GUIDE.md +0 -40
- package/docs/OPERATORS.md +0 -184
- package/docs/PERF_REGRESSION_POLICY.md +0 -34
- package/docs/PROJECT_EXAMINATION_2026-05-31.md +0 -219
- package/docs/RELEASE_BENCHMARK_REPORT_2026-05-15.md +0 -135
- package/docs/RELEASE_GATE.md +0 -25
- package/docs/RELEASE_NOTES_v0.1.0.md +0 -54
- package/docs/SECURITY_REVIEW_2026-06-05.md +0 -165
- package/docs/TELEMETRY.md +0 -41
- package/docs/THREAT_MODEL.md +0 -89
- package/docs/VERSIONING_POLICY.md +0 -30
- package/docs/assets/banner.png +0 -0
- package/eslint.config.js +0 -15
- package/fuzz/ts/harness-decode.ts +0 -136
- package/fuzz/ts/harness-verify.ts +0 -121
- package/fuzz/ts/run.ts +0 -35
- package/mcp-server/README.md +0 -38
- package/mcp-server/package-lock.json +0 -1187
- package/mcp-server/package.json +0 -35
- package/mcp-server/src/index.ts +0 -236
- package/mcp-server/tsconfig.json +0 -14
- package/scripts/aip-framework-quickstart.ts +0 -110
- package/scripts/aip-mcp-gateway.ts +0 -38
- package/scripts/aip-mcp-wrap-demo.ts +0 -72
- package/scripts/aip-quickstart.ts +0 -60
- package/scripts/bench-diff.ts +0 -118
- package/scripts/bench-protocol-e2e.ts +0 -937
- package/scripts/bench-protocol-openloop.ts +0 -1397
- package/scripts/bench-replay-cache.ts +0 -76
- package/scripts/bench-signature-profiles.ts +0 -180
- package/scripts/bench-wire-codecs.ts +0 -161
- package/scripts/build-binary-conformance.ts +0 -36
- package/scripts/build-release-dashboard.ts +0 -175
- package/scripts/canary-rollout.ts +0 -38
- package/scripts/mcpGatewayCli.test.ts +0 -116
- package/scripts/prepare-aip-package.ts +0 -88
- package/scripts/regen-conformance-sigs.ts +0 -18
- package/scripts/release-gate.ts +0 -19
- package/scripts/validate-runtime-policy.ts +0 -18
- package/sdk/browser/index.test.ts +0 -162
- package/sdk/browser/index.ts +0 -257
- package/sdk/browser/package.json +0 -13
- package/sdk/go/go.mod +0 -3
- package/sdk/go/http.go +0 -135
- package/sdk/go/protocol.go +0 -324
- package/sdk/go/protocol_test.go +0 -334
- package/sdk/go/webhook.go +0 -136
- package/sdk/python/README.md +0 -18
- package/sdk/python/protocol_7h3/__init__.py +0 -46
- package/sdk/python/protocol_7h3/http.py +0 -212
- package/sdk/python/protocol_7h3/keys.py +0 -149
- package/sdk/python/protocol_7h3/protocol.py +0 -525
- package/sdk/python/protocol_7h3/queue.py +0 -118
- package/sdk/python/protocol_7h3/webhook.py +0 -116
- package/sdk/python/pyproject.toml +0 -40
- package/sdk/python/tests/test_conformance.py +0 -110
- package/sdk/python/tests/test_http.py +0 -305
- package/sdk/python/tests/test_keys.py +0 -417
- package/sdk/python/tests/test_queue.py +0 -120
- package/sdk/python/tests/test_webhook.py +0 -345
- package/sdk/rust/Cargo.lock +0 -371
- package/sdk/rust/Cargo.toml +0 -25
- package/sdk/rust/README.md +0 -31
- package/sdk/rust/fuzz/Cargo.toml +0 -29
- package/sdk/rust/fuzz/fuzz_targets/fuzz_canonicalize.rs +0 -46
- package/sdk/rust/fuzz/fuzz_targets/fuzz_decode.rs +0 -11
- package/sdk/rust/src/bin/aip_mcp_gateway.rs +0 -59
- package/sdk/rust/src/http.rs +0 -145
- package/sdk/rust/src/keys.rs +0 -161
- package/sdk/rust/src/lib.rs +0 -688
- package/sdk/rust/src/queue.rs +0 -79
- package/sdk/rust/src/webhook.rs +0 -86
- package/sdk/rust/tests/conformance.rs +0 -148
- package/sdk/rust/tests/gateway.rs +0 -130
- package/sdk/rust/tests/http_webhook_queue.rs +0 -201
- package/sdk/rust/tests/keys.rs +0 -189
- package/src/agentAdapter.test.ts +0 -48
- package/src/agentAdapter.ts +0 -56
- package/src/auditLog.test.ts +0 -145
- package/src/auditLog.ts +0 -147
- package/src/conformance.test.ts +0 -136
- package/src/conformanceVectors.ts +0 -99
- package/src/frameworkAdapters.test.ts +0 -290
- package/src/frameworkAdapters.ts +0 -261
- package/src/gateway.test.ts +0 -343
- package/src/gateway.ts +0 -171
- package/src/grpcBinding.test.ts +0 -211
- package/src/grpcBinding.ts +0 -103
- package/src/httpBinding.test.ts +0 -376
- package/src/httpBinding.ts +0 -163
- package/src/index.ts +0 -32
- package/src/keyInfra.test.ts +0 -278
- package/src/keyInfra.ts +0 -228
- package/src/keyRegistry.ts +0 -59
- package/src/keyRotation.test.ts +0 -78
- package/src/keyRotation.ts +0 -72
- package/src/mcpGateway.test.ts +0 -129
- package/src/mcpGateway.ts +0 -250
- package/src/mcpTransports.test.ts +0 -92
- package/src/mcpTransports.ts +0 -169
- package/src/mcpWrapper.test.ts +0 -179
- package/src/mcpWrapper.ts +0 -206
- package/src/policyEnforcer.test.ts +0 -99
- package/src/policyEnforcer.ts +0 -169
- package/src/policyTelemetryFeedback.test.ts +0 -25
- package/src/policyTelemetryFeedback.ts +0 -38
- package/src/protocol.bench.ts +0 -37
- package/src/protocol.test.ts +0 -155
- package/src/protocol.ts +0 -413
- package/src/protocolAgent.test.ts +0 -105
- package/src/protocolAgent.ts +0 -169
- package/src/protocolBinary.test.ts +0 -165
- package/src/protocolBinary.ts +0 -312
- package/src/protocolCapabilities.ts +0 -70
- package/src/protocolFuzz.advanced.test.ts +0 -235
- package/src/protocolFuzz.test.ts +0 -111
- package/src/protocolNegative.test.ts +0 -97
- package/src/protocolReplay.test.ts +0 -71
- package/src/protocolReplay.ts +0 -194
- package/src/protocolTransport.test.ts +0 -556
- package/src/protocolTransport.ts +0 -483
- package/src/queueBinding.test.ts +0 -130
- package/src/queueBinding.ts +0 -102
- package/src/rateLimiter.test.ts +0 -96
- package/src/rateLimiter.ts +0 -46
- package/src/redisIntegration.test.ts +0 -134
- package/src/replayStores.test.ts +0 -141
- package/src/replayStores.ts +0 -82
- package/src/revocation.test.ts +0 -98
- package/src/revocation.ts +0 -0
- package/src/routePolicy.test.ts +0 -87
- package/src/routePolicy.ts +0 -72
- package/src/runtimePolicy.test.ts +0 -49
- package/src/runtimePolicy.ts +0 -81
- package/src/runtimePolicyManager.test.ts +0 -29
- package/src/runtimePolicyManager.ts +0 -50
- package/src/runtimePolicyPresets.ts +0 -43
- package/src/signedResponse.test.ts +0 -111
- package/src/signedResponse.ts +0 -83
- package/src/webhookBinding.test.ts +0 -144
- package/src/webhookBinding.ts +0 -115
- package/src/wsBinding.test.ts +0 -221
- package/src/wsBinding.ts +0 -100
- package/tsconfig.json +0 -15
- package/tsconfig.lib.json +0 -23
- package/vite.lib.config.ts +0 -16
package/docs/GATEWAY.md
DELETED
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
# 7h3 Protocol — Gateway Quick-Start
|
|
2
|
-
|
|
3
|
-
The 7h3 gateway is a verifying HTTP reverse proxy. It sits in front of your
|
|
4
|
-
service, intercepts every request, checks that the AIP envelope header carries
|
|
5
|
-
a valid Ed25519 (or HMAC) signature from a known sender, enforces per-route
|
|
6
|
-
policies and rate limits, optionally signs upstream responses, then forwards
|
|
7
|
-
clean HTTP to your application.
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## 1. Install
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npm install @7h3/protocol
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
`tsx` is required to run the CLI from source. It is listed as a dev
|
|
18
|
-
dependency and is also installed globally in the Docker image.
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
npm install -g tsx # if running outside Docker
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
## 2. In-Process Middleware
|
|
27
|
-
|
|
28
|
-
Drop the gateway into an existing Express (or any Node.js `http`) server in
|
|
29
|
-
three lines:
|
|
30
|
-
|
|
31
|
-
```ts
|
|
32
|
-
import express from 'express'
|
|
33
|
-
import { createGateway } from '@7h3/protocol/gateway'
|
|
34
|
-
import { createStaticKeyRegistry } from '@7h3/protocol/key-registry'
|
|
35
|
-
|
|
36
|
-
const app = express()
|
|
37
|
-
|
|
38
|
-
const registry = createStaticKeyRegistry({
|
|
39
|
-
'agent@example.com': process.env.AGENT_PUBLIC_KEY!,
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
const gateway = createGateway({
|
|
43
|
-
upstream: 'http://internal-api:3000',
|
|
44
|
-
keyRegistry: registry,
|
|
45
|
-
defaultPolicy: 'deny',
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
// Verify every request before it reaches your routes
|
|
49
|
-
app.use(async (req, res, next) => {
|
|
50
|
-
const headers: Record<string, string> = {}
|
|
51
|
-
for (const [k, v] of Object.entries(req.headers)) {
|
|
52
|
-
if (typeof v === 'string') headers[k] = v
|
|
53
|
-
else if (Array.isArray(v)) headers[k] = v[0]
|
|
54
|
-
}
|
|
55
|
-
const outcome = await gateway.verify({ method: req.method, path: req.path, headers })
|
|
56
|
-
if (!outcome.ok) return res.status(outcome.status).json({ error: outcome.reason })
|
|
57
|
-
res.locals.sender = outcome.sender
|
|
58
|
-
next()
|
|
59
|
-
})
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
---
|
|
63
|
-
|
|
64
|
-
## 3. Gateway Mode (CLI / Standalone Proxy)
|
|
65
|
-
|
|
66
|
-
### 3a. Generate a keypair
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
7h3 keygen --output keys.json
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
This writes a JSON file with `publicKey` and `privateKey` (both base64url-encoded
|
|
73
|
-
Ed25519 SPKI/PKCS8). Store `privateKey` in a secret; share `publicKey` with
|
|
74
|
-
the agents that will call your service.
|
|
75
|
-
|
|
76
|
-
### 3b. Start the gateway
|
|
77
|
-
|
|
78
|
-
```bash
|
|
79
|
-
7h3 gateway \
|
|
80
|
-
--upstream http://localhost:3000 \
|
|
81
|
-
--public-key <base64url-SPKI> \
|
|
82
|
-
--port 8080 \
|
|
83
|
-
--require ed25519
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
Full options:
|
|
87
|
-
|
|
88
|
-
| Flag | Default | Description |
|
|
89
|
-
|---|---|---|
|
|
90
|
-
| `--upstream <url>` | _(required)_ | Upstream service URL |
|
|
91
|
-
| `--port <n>` | `8080` | Port to listen on |
|
|
92
|
-
| `--require ed25519\|none` | `ed25519` if `--public-key` is set, else `none` | Signature mode |
|
|
93
|
-
| `--public-key <key>` | — | Ed25519 SPKI public key (base64url) |
|
|
94
|
-
| `--sign-responses` | `false` | Sign every proxied response |
|
|
95
|
-
| `--private-key <key>` | — | Private key for response signing |
|
|
96
|
-
| `--sender <id>` | — | Sender ID attached to signed responses |
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## 4. Docker
|
|
101
|
-
|
|
102
|
-
```bash
|
|
103
|
-
# Bring up the gateway + example upstream
|
|
104
|
-
docker compose up --build
|
|
105
|
-
|
|
106
|
-
# Test with a health probe (no signature required)
|
|
107
|
-
curl http://localhost:8080/health
|
|
108
|
-
|
|
109
|
-
# Generate keys, then call a signed route
|
|
110
|
-
7h3 keygen --output keys.json
|
|
111
|
-
PRIV=$(jq -r .privateKey keys.json)
|
|
112
|
-
PUB=$(jq -r .publicKey keys.json)
|
|
113
|
-
|
|
114
|
-
ENVELOPE=$(7h3 sign --private-key "$PRIV" --sender agent@example.com --payload '{"q":"hello"}')
|
|
115
|
-
curl -H "x-7h3-envelope: $ENVELOPE" http://localhost:8080/api/hello
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
To enable response signing, pass environment variables to the gateway service
|
|
119
|
-
in `docker-compose.yaml`:
|
|
120
|
-
|
|
121
|
-
```yaml
|
|
122
|
-
environment:
|
|
123
|
-
GATEWAY_PRIVATE_KEY: <your-private-key>
|
|
124
|
-
GATEWAY_SENDER: gateway@my-service.example.com
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
---
|
|
128
|
-
|
|
129
|
-
## 5. Config Reference (YAML)
|
|
130
|
-
|
|
131
|
-
See `7h3.example.yaml` for a fully-annotated configuration file.
|
|
132
|
-
|
|
133
|
-
| Field | Type | Default | Description |
|
|
134
|
-
|---|---|---|---|
|
|
135
|
-
| `upstream` | string | _(required)_ | Upstream base URL |
|
|
136
|
-
| `port` | number | `8080` | Listening port |
|
|
137
|
-
| `sender` | string | — | Gateway sender identity for signed responses |
|
|
138
|
-
| `sign_responses` | boolean | `false` | Sign every proxied response |
|
|
139
|
-
| `default_policy` | `allow` \| `deny` | `allow` | Behaviour when no route policy matches |
|
|
140
|
-
| `keys.private_key` | string | — | Gateway Ed25519 private key (base64url PKCS8) |
|
|
141
|
-
| `keys.registry` | map | `{}` | `senderID → publicKey` (base64url SPKI) |
|
|
142
|
-
| `policies[].path` | glob string | _(required)_ | Route glob (`**` crosses slashes) |
|
|
143
|
-
| `policies[].require` | `ed25519` \| `hmac` \| `any` \| `none` | _(required)_ | Signature algorithm |
|
|
144
|
-
| `policies[].allowed_senders` | string[] | _(all)_ | Allowlist of sender IDs |
|
|
145
|
-
| `policies[].rate_limit.requests` | number | — | Max requests in window |
|
|
146
|
-
| `policies[].rate_limit.window_ms` | number | — | Sliding window in ms |
|
|
147
|
-
| `policies[].sign_response` | boolean | — | Per-route response signing override |
|
|
148
|
-
|
|
149
|
-
---
|
|
150
|
-
|
|
151
|
-
## 6. Client-Side Signing
|
|
152
|
-
|
|
153
|
-
Agents calling a 7h3-protected gateway must attach a signed AIP envelope to
|
|
154
|
-
every request. Use the TypeScript SDK:
|
|
155
|
-
|
|
156
|
-
```ts
|
|
157
|
-
import { createEnvelope, signEnvelopeEd25519 } from '@7h3/protocol'
|
|
158
|
-
import { attachEnvelopeToHeaders } from '@7h3/protocol/http'
|
|
159
|
-
|
|
160
|
-
async function signedFetch(url: string, body: string, privateKey: string) {
|
|
161
|
-
const envelope = createEnvelope({
|
|
162
|
-
sender: 'agent@example.com',
|
|
163
|
-
recipient: 'gateway@my-service.example.com',
|
|
164
|
-
intent: 'REQUEST',
|
|
165
|
-
content: body,
|
|
166
|
-
ttlMs: 60_000,
|
|
167
|
-
})
|
|
168
|
-
|
|
169
|
-
const signed = await signEnvelopeEd25519(envelope, privateKey)
|
|
170
|
-
const headers = attachEnvelopeToHeaders(signed, {}) // adds x-7h3-envelope
|
|
171
|
-
|
|
172
|
-
return fetch(url, {
|
|
173
|
-
method: 'POST',
|
|
174
|
-
headers: { 'content-type': 'application/json', ...headers },
|
|
175
|
-
body,
|
|
176
|
-
})
|
|
177
|
-
}
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
The gateway validates the envelope header, verifies the Ed25519 signature
|
|
181
|
-
against the sender's registered public key, checks replay protection, and only
|
|
182
|
-
then forwards the request to the upstream service.
|
|
183
|
-
|
|
184
|
-
---
|
|
185
|
-
|
|
186
|
-
## 7. Policy Examples
|
|
187
|
-
|
|
188
|
-
| Use Case | `path` | `require` | `allowed_senders` | `rate_limit` |
|
|
189
|
-
|---|---|---|---|---|
|
|
190
|
-
| Public health probe | `/health` | `none` | — | — |
|
|
191
|
-
| Open public API | `/public/**` | `none` | — | — |
|
|
192
|
-
| Any authenticated agent | `/api/**` | `ed25519` | — | 1 000 req / 60 s |
|
|
193
|
-
| Named admin agents only | `/api/admin/**` | `ed25519` | `admin-agent@…`, `orchestrator@…` | — |
|
|
194
|
-
| Partner integration | `/api/partner/**` | `ed25519` | `partner-bot@partner.example.com` | 200 req / 60 s |
|
|
195
|
-
| Webhook receiver | `/webhooks/**` | `hmac` | — | 500 req / 60 s |
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
# 7h3 Protocol AIP Key Management Policy (v1.0 draft)
|
|
2
|
-
|
|
3
|
-
## Supported signature profiles
|
|
4
|
-
|
|
5
|
-
- `HS256` (shared secret)
|
|
6
|
-
- `ED25519` (asymmetric keypair)
|
|
7
|
-
|
|
8
|
-
## Key ID rules
|
|
9
|
-
|
|
10
|
-
- Every signing key must have a unique `keyId`.
|
|
11
|
-
- Verifiers must resolve verification material by both `keyId` and `sender`.
|
|
12
|
-
- Reusing the same `keyId` for different senders is prohibited.
|
|
13
|
-
|
|
14
|
-
## Rotation policy
|
|
15
|
-
|
|
16
|
-
- Rotation interval target:
|
|
17
|
-
- `HS256`: every 30 days
|
|
18
|
-
- `ED25519`: every 90 days
|
|
19
|
-
- Rotation process:
|
|
20
|
-
1. Provision new key as active for signing.
|
|
21
|
-
2. Keep previous key in verify-only mode during overlap window.
|
|
22
|
-
3. End overlap and revoke old key.
|
|
23
|
-
|
|
24
|
-
## Revocation policy
|
|
25
|
-
|
|
26
|
-
- Immediate revocation triggers:
|
|
27
|
-
- suspected credential leak
|
|
28
|
-
- host compromise
|
|
29
|
-
- failed integrity investigation
|
|
30
|
-
- Revoked keys must fail verification in resolver control plane within SLA.
|
|
31
|
-
- For multi-node deployments, back revocation with a shared `RevocationStore`
|
|
32
|
-
(`createRedisRevocationStore`) and wrap the verification resolver with
|
|
33
|
-
`withRevocationCheck` so a revoke on one node is enforced fleet-wide. The
|
|
34
|
-
store fails **closed** by default: if the revocation list is unreachable, the
|
|
35
|
-
key is treated as revoked. See `KEY_REVOCATION.md`.
|
|
36
|
-
|
|
37
|
-
## Storage requirements
|
|
38
|
-
|
|
39
|
-
- Do not commit secrets/private keys to source control.
|
|
40
|
-
- Store key material in managed secrets/KMS.
|
|
41
|
-
- Restrict read access to signing services and verification control plane.
|
|
42
|
-
|
|
43
|
-
## Runtime policy
|
|
44
|
-
|
|
45
|
-
- Production endpoints require signatures by default.
|
|
46
|
-
- `HS256` is recommended for tightly controlled private clusters.
|
|
47
|
-
- `ED25519` is recommended for cross-domain or multi-tenant federation.
|
|
48
|
-
- Use `RollingKeyring` (`src/keyRotation.ts`) for overlap windows, verify-only periods, and revocation enforcement.
|
|
49
|
-
|
|
50
|
-
## Audit requirements
|
|
51
|
-
|
|
52
|
-
- Log key activation, rotation, revocation, and failed verification events.
|
|
53
|
-
- Retain audit logs for incident response and compliance windows.
|
package/docs/KEY_REVOCATION.md
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# Fleet-Wide Key Revocation
|
|
2
|
-
|
|
3
|
-
`RollingKeyring` (`src/keyRotation.ts`) enforces revocation and `notBefore`/
|
|
4
|
-
`notAfter` expiry **in-process**. For horizontally scaled deployments, a shared
|
|
5
|
-
`RevocationStore` makes a revocation effective across every node: revoke a
|
|
6
|
-
`(sender, keyId)` on one gateway and all gateways that consult the same store
|
|
7
|
-
reject it.
|
|
8
|
-
|
|
9
|
-
Source: `src/revocation.ts`.
|
|
10
|
-
|
|
11
|
-
## Interfaces
|
|
12
|
-
|
|
13
|
-
- `RevocationStore` — `isRevoked(sender, keyId, nowMs?)` and `revoke(sender, keyId, { untilMs? })`.
|
|
14
|
-
- `InMemoryRevocationStore` — single-process implementation (tests, local dev, single node).
|
|
15
|
-
- `createRedisRevocationStore` — Redis-backed shared store with cached reads.
|
|
16
|
-
- `withRevocationCheck(resolver, store)` — wraps a signature resolver so a revoked key resolves to **no material**, which makes verification fail and the envelope is rejected.
|
|
17
|
-
|
|
18
|
-
## Usage
|
|
19
|
-
|
|
20
|
-
```ts
|
|
21
|
-
import {
|
|
22
|
-
RollingKeyring,
|
|
23
|
-
createKeyringSignatureResolver,
|
|
24
|
-
createRedisRevocationStore,
|
|
25
|
-
withRevocationCheck,
|
|
26
|
-
receiveEnvelope,
|
|
27
|
-
} from '@7h3/protocol'
|
|
28
|
-
|
|
29
|
-
const keyring = new RollingKeyring(records)
|
|
30
|
-
const revocations = createRedisRevocationStore(redisLikeClient, {
|
|
31
|
-
keyPrefix: 'aip:revoked:',
|
|
32
|
-
errorBehavior: 'reject', // fail closed (default)
|
|
33
|
-
cacheTtlMs: 5000,
|
|
34
|
-
onDegraded: (err, ctx) => metrics.increment('aip.revocation.degraded'),
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
const signatureResolver = withRevocationCheck(
|
|
38
|
-
createKeyringSignatureResolver(keyring),
|
|
39
|
-
revocations,
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
await receiveEnvelope(rawEnvelope, { signatureResolver })
|
|
43
|
-
|
|
44
|
-
// Operationally, on a suspected compromise:
|
|
45
|
-
await revocations.revoke('agent.worker', 'agent.worker-k1') // permanent
|
|
46
|
-
await revocations.revoke('agent.worker', 'agent.worker-k2', { untilMs: Date.now() + 86_400_000 }) // 24h
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Behavior on Redis outage (`errorBehavior`)
|
|
50
|
-
|
|
51
|
-
| Value | On client error | Rationale |
|
|
52
|
-
|---|---|---|
|
|
53
|
-
| `reject` (default) | Treat the key as **revoked** (fail closed) | A revoked key is a compromised key — never accept on uncertainty |
|
|
54
|
-
| `allow` | Treat the key as **not revoked** | Favor availability where the risk is acceptable |
|
|
55
|
-
|
|
56
|
-
Reads are served from a short-lived local cache (`cacheTtlMs`), so:
|
|
57
|
-
|
|
58
|
-
- the verify hot path does not hit Redis on every message (scalability), and
|
|
59
|
-
- known revocations keep enforcing through a brief Redis outage (a stale cached
|
|
60
|
-
`revoked: true` is still honored).
|
|
61
|
-
|
|
62
|
-
Every degraded decision fires `onDegraded` — degradation is never silent.
|
|
63
|
-
|
|
64
|
-
## Operational guidance
|
|
65
|
-
|
|
66
|
-
- Wire `withRevocationCheck` into every verifying node's `signatureResolver`.
|
|
67
|
-
- Treat the `onDegraded` rate as a security signal; sustained degradation means
|
|
68
|
-
revocations may not be propagating.
|
|
69
|
-
- Keep `cacheTtlMs` short enough that a revocation propagates within your SLA.
|
package/docs/MCP_WRAPPER.md
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
# MCP Hardening Wrapper
|
|
2
|
-
|
|
3
|
-
MCP messages are plain JSON-RPC 2.0 with no signature and no replay protection.
|
|
4
|
-
This wrapper puts a signed AIP envelope around every MCP message on the wire —
|
|
5
|
-
authenticating it, TTL-bounding it, and replay-checking it — **without changing
|
|
6
|
-
your MCP handler**. Your handler still receives plain JSON-RPC `{ method, params }`
|
|
7
|
-
and returns plain results; AIP lives entirely on the wire.
|
|
8
|
-
|
|
9
|
-
Source: `src/mcpWrapper.ts`. Runnable demo: `npm run aip:mcp:wrap`.
|
|
10
|
-
|
|
11
|
-
## Threat coverage
|
|
12
|
-
|
|
13
|
-
| Threat | Covered by |
|
|
14
|
-
|---|---|
|
|
15
|
-
| Message tampering (params/method altered in flight) | Canonical signature over the envelope (HS256 / Ed25519) |
|
|
16
|
-
| Replay / duplicate execution | `(sender, messageId, nonce)` replay cache + TTL; **on by default** (`InMemoryReplayCache` if none supplied) |
|
|
17
|
-
| Cross-server relay (valid envelope for server A replayed to server B) | **Recipient binding** — the server runs the handler only when `recipient === selfAgentId` |
|
|
18
|
-
| Response spoofing (another valid signer answers) | **Sender binding** — the client accepts a response only when `sender === peerAgentId` (peerAgentId is required) |
|
|
19
|
-
| Response substitution (a valid response to request A returned for request B) | **Correlation binding** — the client requires `correlationId === the request's messageId` |
|
|
20
|
-
| Compromised key still in use | Compose `withRevocationCheck` into `receive.signatureResolver` |
|
|
21
|
-
|
|
22
|
-
`encodeRequest` returns `{ raw, messageId }`; pass `messageId` to `decodeResponse(raw, { expectCorrelationId })` to enforce the correlation binding (`wrapMcpClient` does this for you).
|
|
23
|
-
|
|
24
|
-
## Server side — wrap an existing handler
|
|
25
|
-
|
|
26
|
-
```ts
|
|
27
|
-
import { wrapMcpServer, signEnvelopeHmac } from '@7h3/protocol'
|
|
28
|
-
import { DistributedReplayCache, createRedisReplayStore } from '@7h3/protocol'
|
|
29
|
-
|
|
30
|
-
// Your existing MCP handler — unchanged, AIP-unaware.
|
|
31
|
-
async function myMcpServer(request) {
|
|
32
|
-
if (request.method === 'tools/call') return { jsonrpc: '2.0', id: request.id, result: runTool(request.params) }
|
|
33
|
-
return { jsonrpc: '2.0', id: request.id, error: { code: -32601, message: 'Method not found' } }
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const secured = wrapMcpServer(myMcpServer, {
|
|
37
|
-
selfAgentId: 'agent.mcp-server',
|
|
38
|
-
sign: (e) => signEnvelopeHmac(e, process.env.AIP_SECRET!, 'server-k1'),
|
|
39
|
-
receive: {
|
|
40
|
-
secretResolver: async () => process.env.AIP_SECRET!,
|
|
41
|
-
replayCache: new DistributedReplayCache(createRedisReplayStore(redisLikeClient)), // fleet-wide replay
|
|
42
|
-
},
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
// `secured(rawWireEnvelope) => Promise<rawWireEnvelope>` — drop it into your stdio/HTTP transport read loop.
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## HMAC vs Ed25519
|
|
49
|
-
|
|
50
|
-
| | HMAC (HS256) | Ed25519 |
|
|
51
|
-
|---|---|---|
|
|
52
|
-
| Secret model | Shared secret — both sides can sign and verify | Keypair — only you can sign; peers verify with your public key |
|
|
53
|
-
| Peer compromise | A compromised peer can forge messages | A compromised peer cannot forge your messages |
|
|
54
|
-
| Key distribution | One secret distributed to all trusted peers | Public key is safe to publish; private key never leaves the signer |
|
|
55
|
-
| When to use | Dev, testing, fully trusted internal infra | Production, multi-tenant, or any boundary where you do not control both sides |
|
|
56
|
-
|
|
57
|
-
**Use HMAC when** you own both sides of the wire (same team, same trusted cluster) and want the simplest possible setup.
|
|
58
|
-
|
|
59
|
-
**Use Ed25519 in production.** If a worker/peer node is compromised, the attacker gains verify capability only — they cannot impersonate the signer.
|
|
60
|
-
|
|
61
|
-
Ed25519 server example (replace the HMAC `sign`/`receive` block above):
|
|
62
|
-
|
|
63
|
-
```ts
|
|
64
|
-
import { wrapMcpServer, signEnvelopeEd25519 } from '@7h3/protocol'
|
|
65
|
-
|
|
66
|
-
// Generate keys once: npx @7h3/protocol-mcp → aip_generate_keypair
|
|
67
|
-
// Set AIP_PRIVATE_KEY (server) and distribute AIP_CLIENT_PUBLIC_KEY (client's pubkey)
|
|
68
|
-
|
|
69
|
-
const secured = wrapMcpServer(myMcpServer, {
|
|
70
|
-
selfAgentId: 'agent.mcp-server',
|
|
71
|
-
sign: (e) => signEnvelopeEd25519(e, process.env.AIP_PRIVATE_KEY!, 'k1'),
|
|
72
|
-
receive: {
|
|
73
|
-
signatureResolver: async (sig) =>
|
|
74
|
-
sig.alg === 'ED25519'
|
|
75
|
-
? { alg: 'ED25519' as const, publicKey: process.env.AIP_CLIENT_PUBLIC_KEY! }
|
|
76
|
-
: undefined,
|
|
77
|
-
},
|
|
78
|
-
})
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
## Client side — sign requests, verify responses
|
|
82
|
-
|
|
83
|
-
```ts
|
|
84
|
-
import { wrapMcpClient, signEnvelopeHmac } from '@7h3/protocol'
|
|
85
|
-
|
|
86
|
-
const call = wrapMcpClient(transport.send /* (raw) => Promise<raw> */, {
|
|
87
|
-
selfAgentId: 'agent.mcp-client',
|
|
88
|
-
peerAgentId: 'agent.mcp-server',
|
|
89
|
-
sign: (e) => signEnvelopeHmac(e, process.env.AIP_SECRET!, 'client-k1'),
|
|
90
|
-
receive: { secretResolver: async () => process.env.AIP_SECRET! },
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
const result = await call({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: 'planner' } })
|
|
94
|
-
// throws if the server response signature does not verify
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
`createMcpClientCodec(options)` exposes `encodeRequest` / `decodeResponse` directly
|
|
98
|
-
when you manage the transport send yourself. `encodeRequest` returns
|
|
99
|
-
`{ raw, messageId }`; pass that `messageId` as `decodeResponse(raw, { expectCorrelationId })`
|
|
100
|
-
to bind each response to its request. `peerAgentId` is required so responses can be
|
|
101
|
-
bound to the expected sender.
|
|
102
|
-
|
|
103
|
-
## Composes with the rest of the stack
|
|
104
|
-
|
|
105
|
-
The `receive` field is a full `ReceiveEnvelopeOptions`, so the wrapper inherits
|
|
106
|
-
everything the transport pipeline offers:
|
|
107
|
-
|
|
108
|
-
- **Fleet-wide replay** — pass a `DistributedReplayCache(createRedisReplayStore(...))`.
|
|
109
|
-
- **Key revocation** — set `receive.signatureResolver = withRevocationCheck(resolver, revocationStore)`.
|
|
110
|
-
- **Ed25519** — sign with `signEnvelopeEd25519` and resolve material via `signatureResolver`.
|
|
111
|
-
- **Clock skew / TTL / telemetry** — `maxClockSkewMs`, `telemetry`, etc.
|
|
112
|
-
|
|
113
|
-
## Transports
|
|
114
|
-
|
|
115
|
-
The wrapper is transport-agnostic (it operates on wire envelopes). Two adapters
|
|
116
|
-
connect it to real transports; both keep the handler on plain JSON-RPC.
|
|
117
|
-
|
|
118
|
-
### stdio (newline-delimited)
|
|
119
|
-
|
|
120
|
-
```ts
|
|
121
|
-
import { wrapMcpServer, serveMcpOverStdio, createStdioMcpClient, wrapMcpClient } from '@7h3/protocol'
|
|
122
|
-
|
|
123
|
-
// server process: read envelopes from stdin, write replies to stdout
|
|
124
|
-
serveMcpOverStdio(wrapMcpServer(myMcpServer, serverOpts)) // defaults to process.stdin/stdout
|
|
125
|
-
|
|
126
|
-
// client process: spawn the server and talk to it
|
|
127
|
-
const stdio = createStdioMcpClient({ input: child.stdout, output: child.stdin })
|
|
128
|
-
const call = wrapMcpClient(stdio.send, clientOpts)
|
|
129
|
-
const result = await call({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: 'planner' } })
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
Stdio frames one envelope per line, so it supports the `json` and `compact` wire
|
|
133
|
-
formats. For `binary`, use HTTP.
|
|
134
|
-
|
|
135
|
-
### HTTP
|
|
136
|
-
|
|
137
|
-
```ts
|
|
138
|
-
import http from 'node:http'
|
|
139
|
-
import { wrapMcpServer, createHttpMcpHandler, createHttpMcpClient, wrapMcpClient } from '@7h3/protocol'
|
|
140
|
-
|
|
141
|
-
// server: any node:http-compatible host
|
|
142
|
-
http.createServer(createHttpMcpHandler(wrapMcpServer(myMcpServer, serverOpts))).listen(8787)
|
|
143
|
-
|
|
144
|
-
// client: POSTs each request envelope, returns the reply envelope (global fetch)
|
|
145
|
-
const httpClient = createHttpMcpClient({ url: 'http://localhost:8787' })
|
|
146
|
-
const call = wrapMcpClient(httpClient.send, clientOpts)
|
|
147
|
-
const result = await call({ jsonrpc: '2.0', id: 1, method: 'tools/call', params: { name: 'planner' } })
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
Pass `{ binary: true }` to both `createHttpMcpHandler` and `createHttpMcpClient`
|
|
151
|
-
to use the `binary` wire format over HTTP.
|
|
152
|
-
|
|
153
|
-
## Notes
|
|
154
|
-
|
|
155
|
-
- Both peers must be wrapped: the on-wire message is an AIP envelope, not plain
|
|
156
|
-
JSON-RPC. For interop with un-wrapped MCP peers, terminate AIP at a gateway.
|
|
157
|
-
- `wireFormat` defaults to `compact`; use `binary` for the highest-throughput lanes.
|
|
158
|
-
- Verification failures and replays come back as signed JSON-RPC errors
|
|
159
|
-
(`-32600`), so the client still gets an authenticated, well-formed response.
|
package/docs/MIGRATION_GUIDE.md
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# AIP Migration Guide
|
|
2
|
-
|
|
3
|
-
## Import path migration (JS/TS)
|
|
4
|
-
|
|
5
|
-
Use the stable package subpath export:
|
|
6
|
-
|
|
7
|
-
```ts
|
|
8
|
-
import { createAipAgentAdapter, receiveEnvelope } from '@7h3/protocol'
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Avoid repo-relative imports in consumer apps.
|
|
12
|
-
|
|
13
|
-
## Signature profile migration
|
|
14
|
-
|
|
15
|
-
### HS256 to ED25519
|
|
16
|
-
|
|
17
|
-
1. Generate/provision ED25519 key pairs.
|
|
18
|
-
2. Keep HS256 verification active during overlap window.
|
|
19
|
-
3. Start signing outbound envelopes with ED25519.
|
|
20
|
-
4. Monitor verify failures by algorithm.
|
|
21
|
-
5. Revoke/decommission HS256 keys after migration window.
|
|
22
|
-
|
|
23
|
-
## Replay cache migration
|
|
24
|
-
|
|
25
|
-
### Single-node to distributed
|
|
26
|
-
|
|
27
|
-
1. Replace `InMemoryReplayCache` with `DistributedReplayCache`.
|
|
28
|
-
2. Implement atomic reserve in shared store (for example Redis `SET NX PX`).
|
|
29
|
-
3. Roll out gradually and monitor replay reject metrics.
|
|
30
|
-
|
|
31
|
-
## Clock skew migration
|
|
32
|
-
|
|
33
|
-
1. Start with default `maxClockSkewMs` (30s).
|
|
34
|
-
2. Tighten to lower values in synchronized environments.
|
|
35
|
-
3. Monitor `rejected_clock_skew` telemetry for false-positive tuning.
|
|
36
|
-
|
|
37
|
-
## Rollback guidance
|
|
38
|
-
|
|
39
|
-
- Keep prior verification profiles and key material during rollout.
|
|
40
|
-
- Do not remove old verifiers until telemetry confirms stable traffic.
|
package/docs/OPERATORS.md
DELETED
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
# GLUV Operators Guide
|
|
2
|
-
|
|
3
|
-
This guide is for SRE, platform, and performance teams operating GLUV-backed workloads in production.
|
|
4
|
-
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## 1) Operational objectives
|
|
8
|
-
|
|
9
|
-
Primary objectives:
|
|
10
|
-
|
|
11
|
-
1. Maintain low drop-rate under declared load profiles
|
|
12
|
-
2. Maintain p99 latency SLO
|
|
13
|
-
3. Preserve signature/replay guarantees under stress
|
|
14
|
-
4. Detect and stop regressions before release
|
|
15
|
-
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
## 2) SLO model
|
|
19
|
-
|
|
20
|
-
Define SLOs per traffic class (example baseline):
|
|
21
|
-
|
|
22
|
-
- **Availability:** protocol receive path success ≥ 99.9%
|
|
23
|
-
- **Drop rate:** `dropPct <= 0.1%` (or 0% for critical lanes)
|
|
24
|
-
- **Latency:** p99 <= 20ms (adjust by payload and transport class)
|
|
25
|
-
- **Integrity:** 100% signature verification and replay checks on ingress
|
|
26
|
-
|
|
27
|
-
Important: “no drop” means **within declared operating envelope**. Any system can be overloaded if offered load exceeds capacity.
|
|
28
|
-
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
## 3) Transport selection matrix
|
|
32
|
-
|
|
33
|
-
Use this default selection policy:
|
|
34
|
-
|
|
35
|
-
| Workload | Recommended Mode | Why |
|
|
36
|
-
|---|---|---|
|
|
37
|
-
| High-throughput lane | `http-binary-batch` or `ws-binary-batch` | best throughput and lowest overhead |
|
|
38
|
-
| Balanced latency/compatibility | `ws-batch` | low framing overhead and stable p99 |
|
|
39
|
-
| Low/medium compatibility lane | `http` | simplest interoperability |
|
|
40
|
-
| Stress testing only | `http` + `--allow-unsafe-http` | intentional overload characterization |
|
|
41
|
-
|
|
42
|
-
Guardrail behavior in benchmark harness blocks unsafe plain HTTP at high concurrency unless explicitly overridden.
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## 4) Benchmark discipline
|
|
47
|
-
|
|
48
|
-
### Sustainable benchmarks (default)
|
|
49
|
-
|
|
50
|
-
Use adaptive benchmark commands for release confidence:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
npm run bench:openloop:quick
|
|
54
|
-
npm run bench:openloop:full
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
These discover sustainable operating rates using threshold gates.
|
|
58
|
-
|
|
59
|
-
### Stress benchmarks (explicit overload)
|
|
60
|
-
|
|
61
|
-
Use only for capacity ceiling exploration:
|
|
62
|
-
|
|
63
|
-
```bash
|
|
64
|
-
npm run bench:openloop:stress:quick
|
|
65
|
-
npm run bench:openloop:stress:full
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Do not use stress runs alone as production readiness criteria.
|
|
69
|
-
|
|
70
|
-
---
|
|
71
|
-
|
|
72
|
-
## 5) Core runbook commands
|
|
73
|
-
|
|
74
|
-
### Quality and release gates
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
npm run lint
|
|
78
|
-
npm run test
|
|
79
|
-
npm run build
|
|
80
|
-
npm run release:gate
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Conformance gates
|
|
84
|
-
|
|
85
|
-
```bash
|
|
86
|
-
npm run conformance:python
|
|
87
|
-
npm run conformance:rust
|
|
88
|
-
npm run conformance:binary
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### Benchmark analysis
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
npm run bench:diff -- --baseline <baseline.json> --candidate <candidate.json>
|
|
95
|
-
npm run release:dashboard
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
---
|
|
99
|
-
|
|
100
|
-
## 6) Incident runbook
|
|
101
|
-
|
|
102
|
-
### Symptom: high drop rate
|
|
103
|
-
|
|
104
|
-
1. Confirm mode and benchmark class (adaptive vs stress)
|
|
105
|
-
2. Check if plain HTTP is being used at high concurrency
|
|
106
|
-
3. Switch to binary batch mode for hot lanes
|
|
107
|
-
4. Inspect overload/retry behavior and queue pressure
|
|
108
|
-
5. Reduce offered rate or widen worker capacity
|
|
109
|
-
|
|
110
|
-
### Symptom: p99 latency spike
|
|
111
|
-
|
|
112
|
-
1. Compare payload size distribution against baseline
|
|
113
|
-
2. Check in-flight cap / batch-size adaptation behavior
|
|
114
|
-
3. Verify no regression in signature profile or canonicalization path
|
|
115
|
-
4. Re-run adaptive benchmark for sustainable envelope
|
|
116
|
-
|
|
117
|
-
### Symptom: signature failures
|
|
118
|
-
|
|
119
|
-
1. Validate key resolver outputs and key IDs
|
|
120
|
-
2. Verify canonicalization parity across runtime boundaries
|
|
121
|
-
3. Check clock skew / TTL policy window
|
|
122
|
-
|
|
123
|
-
### Symptom: replay rejections
|
|
124
|
-
|
|
125
|
-
1. Verify message uniqueness (`messageId`, `nonce`)
|
|
126
|
-
2. Validate replay cache window sizing
|
|
127
|
-
3. Confirm producer retry semantics are idempotent
|
|
128
|
-
|
|
129
|
-
---
|
|
130
|
-
|
|
131
|
-
## 7) Tuning matrix (starting points)
|
|
132
|
-
|
|
133
|
-
| Setting | Low Traffic | Medium Traffic | High Traffic |
|
|
134
|
-
|---|---:|---:|---:|
|
|
135
|
-
| Batch size | 4–8 | 8–32 | 32–64 |
|
|
136
|
-
| In-flight cap | 16–64 | 64–256 | 256–1024 |
|
|
137
|
-
| Retry backoff | 1–2ms | 2–8ms | 4–16ms |
|
|
138
|
-
| Preferred mode | `http`/`ws` | `ws-batch` | `http-binary-batch` / `ws-binary-batch` |
|
|
139
|
-
|
|
140
|
-
Treat this as a starting policy; tune from measured p99/drop under adaptive runs.
|
|
141
|
-
|
|
142
|
-
---
|
|
143
|
-
|
|
144
|
-
## 8) Security and reliability invariants
|
|
145
|
-
|
|
146
|
-
Never disable these in production:
|
|
147
|
-
|
|
148
|
-
- signature verification
|
|
149
|
-
- canonicalization checks
|
|
150
|
-
- replay defense
|
|
151
|
-
- TTL and clock-skew enforcement
|
|
152
|
-
|
|
153
|
-
Any performance optimization must preserve these invariants.
|
|
154
|
-
|
|
155
|
-
---
|
|
156
|
-
|
|
157
|
-
## 9) Release acceptance checklist
|
|
158
|
-
|
|
159
|
-
Release candidate is acceptable when:
|
|
160
|
-
|
|
161
|
-
1. `release:gate` passes
|
|
162
|
-
2. conformance suites pass (TS/Python/Rust/binary)
|
|
163
|
-
3. adaptive benchmarks satisfy target SLO thresholds
|
|
164
|
-
4. no critical regression in benchmark diff vs baseline
|
|
165
|
-
5. rollback plan and threshold alerts are prepared
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
|
-
## 10) Recommended rollout strategy
|
|
170
|
-
|
|
171
|
-
1. Canary 5%
|
|
172
|
-
2. Observe drop/p99/signature/replay counters
|
|
173
|
-
3. Expand 25% → 50% → 100%
|
|
174
|
-
4. Auto-rollback if drop or p99 breaches thresholds for sustained window
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
## 11) Documentation map
|
|
179
|
-
|
|
180
|
-
- Protocol technical guide: `README.md`
|
|
181
|
-
- Executive brief: `README_EXECUTIVE.md`
|
|
182
|
-
- Performance policy: `PERF_REGRESSION_POLICY.md`
|
|
183
|
-
- Backpressure notes: `BACKPRESSURE_TUNING.md`
|
|
184
|
-
- Release hardening: `RELEASE_GATE.md`
|