@openwop/openwop-conformance 1.0.0 → 1.1.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/CHANGELOG.md +17 -0
- package/README.md +31 -6
- package/api/grpc/openwop.proto +251 -0
- package/api/openapi.yaml +109 -3
- package/coverage.md +48 -9
- package/fixtures/conformance-configurable-schema.json +39 -0
- package/fixtures/conformance-subworkflow-parent.json +1 -1
- package/fixtures/conformance-wasm-pack-memory-cap-breach.json +23 -0
- package/fixtures/openwop-smoke-byok-roundtrip.json +25 -0
- package/fixtures.md +21 -0
- package/package.json +3 -1
- package/schemas/README.md +4 -0
- package/schemas/audit-verify-result.schema.json +90 -0
- package/schemas/capabilities.schema.json +342 -1
- package/schemas/node-pack-manifest.schema.json +4 -4
- package/schemas/pack-lockfile.schema.json +92 -0
- package/schemas/registry-version-manifest.schema.json +145 -0
- package/schemas/run-event-payloads.schema.json +20 -4
- package/schemas/run-event.schema.json +2 -1
- package/schemas/security-advisory.schema.json +109 -0
- package/src/lib/a2a-fake-peer.ts +143 -56
- package/src/lib/behavior-gate.ts +107 -0
- package/src/lib/env.ts +37 -0
- package/src/lib/grpc-framing.test.ts +96 -0
- package/src/lib/grpc-framing.ts +76 -0
- package/src/lib/oidc-issuer.test.ts +328 -0
- package/src/lib/oidc-issuer.ts +241 -0
- package/src/lib/otel-collector-grpc.test.ts +191 -0
- package/src/lib/otel-collector.test.ts +303 -0
- package/src/lib/otel-collector.ts +318 -14
- package/src/lib/otlp-protobuf.test.ts +461 -0
- package/src/lib/otlp-protobuf.ts +529 -0
- package/src/scenarios/a2a-task-roundtrip.test.ts +147 -28
- package/src/scenarios/agentConfidenceEscalation.test.ts +1 -0
- package/src/scenarios/agentMemoryCrossTenantIsolation.test.ts +1 -0
- package/src/scenarios/agentMemoryRedactionContract.test.ts +1 -0
- package/src/scenarios/agentMemoryRoundTrip.test.ts +1 -0
- package/src/scenarios/agentMemoryTtlExpiry.test.ts +1 -0
- package/src/scenarios/agentMessageReducer.test.ts +1 -0
- package/src/scenarios/agentMetadata.test.ts +1 -0
- package/src/scenarios/agentPackExport.test.ts +1 -0
- package/src/scenarios/agentPackInstall.test.ts +1 -0
- package/src/scenarios/agentPackProvenance.test.ts +1 -0
- package/src/scenarios/audit-log-integrity.test.ts +3 -6
- package/src/scenarios/auth-api-key-rotation.test.ts +182 -0
- package/src/scenarios/auth-mtls.test.ts +274 -0
- package/src/scenarios/auth-oauth2-client-credentials.test.ts +259 -0
- package/src/scenarios/auth-oidc-user-bearer.test.ts +361 -0
- package/src/scenarios/bulk-cancel.test.ts +111 -0
- package/src/scenarios/configurable-schema.test.ts +48 -0
- package/src/scenarios/conversationCapabilityNegotiation.test.ts +1 -0
- package/src/scenarios/conversationLifecycle.test.ts +1 -0
- package/src/scenarios/conversationReplayDeterminism.test.ts +1 -0
- package/src/scenarios/conversationVsLegacySuspend.test.ts +1 -0
- package/src/scenarios/debug-bundle-truncation.test.ts +95 -0
- package/src/scenarios/discovery.test.ts +183 -0
- package/src/scenarios/http-client-ssrf.test.ts +71 -0
- package/src/scenarios/idempotency.test.ts +6 -0
- package/src/scenarios/idempotencyRetry.test.ts +3 -0
- package/src/scenarios/mcp-tool-roundtrip.test.ts +205 -34
- package/src/scenarios/mcp-toolcall-redaction.test.ts +66 -0
- package/src/scenarios/memory-compaction-event-emitted.test.ts +121 -0
- package/src/scenarios/memory-compaction-provenance-tag.test.ts +116 -0
- package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +127 -0
- package/src/scenarios/metric-emission.test.ts +113 -0
- package/src/scenarios/multi-region-idempotency.test.ts +39 -4
- package/src/scenarios/orchestratorConservativePath.test.ts +1 -0
- package/src/scenarios/orchestratorDispatch.test.ts +1 -0
- package/src/scenarios/orchestratorTermination.test.ts +1 -0
- package/src/scenarios/otel-emission-grpc.test.ts +98 -0
- package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +139 -0
- package/src/scenarios/pause-resume.test.ts +119 -0
- package/src/scenarios/production-backpressure.test.ts +342 -0
- package/src/scenarios/production-retention-expiry.test.ts +164 -0
- package/src/scenarios/registry-public.test.ts +222 -0
- package/src/scenarios/replay-llm-cache-key.test.ts +35 -0
- package/src/scenarios/replay-retention-expiry.test.ts +178 -0
- package/src/scenarios/restart-during-run.test.ts +177 -0
- package/src/scenarios/spec-corpus-validity.test.ts +59 -26
- package/src/scenarios/staleClaim.test.ts +3 -0
- package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +67 -10
- package/src/scenarios/wasm-pack-memory-cap.test.ts +64 -9
- package/src/scenarios/webhook-negative.test.ts +90 -0
- package/src/scenarios/webhook-signed-delivery.test.ts +178 -0
- package/src/setup.ts +25 -1
- package/vitest.config.ts +5 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "conformance-wasm-pack-memory-cap-breach",
|
|
3
|
+
"name": "Conformance: WASM Pack Memory-Cap Breach (Positive Path)",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "RFC 0008 §K fixture. Invokes the deliberately-misbehaving Rust pack (`vendor.openwop.misbehaving.memory-bomb`) which attempts a 1 GiB allocation beyond the host's `memoryPagesMax` ceiling. Hosts MUST trap or terminate the instance and emit `cap.breached` with `kind: 'wasm-memory'`, then terminate the run as `failed`. The misbehaving pack lives at `examples/packs/rust-misbehaving-memory/`; build it with `cargo build --target wasm32-unknown-unknown --release` before running the scenario end-to-end. Fixture-only — the pack is NOT signed for the registry.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "bomb",
|
|
9
|
+
"typeId": "vendor.openwop.misbehaving.memory-bomb",
|
|
10
|
+
"name": "Memory bomb",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {},
|
|
13
|
+
"inputs": {}
|
|
14
|
+
}
|
|
15
|
+
],
|
|
16
|
+
"edges": [],
|
|
17
|
+
"triggers": [
|
|
18
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
19
|
+
],
|
|
20
|
+
"variables": [],
|
|
21
|
+
"metadata": { "tags": ["conformance", "wasm", "node-pack", "rfc-0008", "cap-breach", "misbehaving"] },
|
|
22
|
+
"settings": { "timeout": 0 }
|
|
23
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "openwop-smoke-byok-roundtrip",
|
|
3
|
+
"name": "Conformance: BYOK Roundtrip",
|
|
4
|
+
"version": "1.0",
|
|
5
|
+
"description": "End-to-end BYOK secret-resolution smoke fixture. Single node 'resolve-secret' (typeId conformance.secret.echo) fetches the host-provisioned canary secret 'openwop-conformance-canary-secret' via the host's SecretResolver, then emits the SHA-256 hex + byte length to the run's variables — never the raw value. Spec: run-options.md §'Credential references' + auth.md §'Secret resolution' + observability.md §'Redaction'.",
|
|
6
|
+
"nodes": [
|
|
7
|
+
{
|
|
8
|
+
"id": "resolve-secret",
|
|
9
|
+
"typeId": "conformance.secret.echo",
|
|
10
|
+
"name": "Resolve Canary Secret",
|
|
11
|
+
"position": { "x": 0, "y": 0 },
|
|
12
|
+
"config": {
|
|
13
|
+
"secretId": "openwop-conformance-canary-secret"
|
|
14
|
+
},
|
|
15
|
+
"inputs": {}
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"edges": [],
|
|
19
|
+
"triggers": [
|
|
20
|
+
{ "id": "manual", "type": "manual", "enabled": true }
|
|
21
|
+
],
|
|
22
|
+
"variables": [],
|
|
23
|
+
"metadata": { "tags": ["conformance", "byok", "secrets", "smoke"] },
|
|
24
|
+
"settings": { "timeout": 10000, "maxRetries": 0 }
|
|
25
|
+
}
|
package/fixtures.md
CHANGED
|
@@ -78,6 +78,9 @@ All fixtures MUST advertise:
|
|
|
78
78
|
| MCP Tool Roundtrip | `conformance-mcp-tool-roundtrip` | Track 6 — host invokes a tool on the conformance suite's synthetic MCP server; trust-boundary visibility in the event log | `completed` | ≤ 30s |
|
|
79
79
|
| A2A Task Roundtrip | `conformance-a2a-task-roundtrip` | Track 6 — host consumes the conformance suite's synthetic A2A peer; covers drift points #3 (`AUTH_REQUIRED`) and #4 (`REJECTED`) | `failed` or `waiting-input` (per `driftScenario` input) | ≤ 30s |
|
|
80
80
|
| WASM Pack Roundtrip | `conformance-wasm-pack-roundtrip` | RFC 0008 — invokes `vendor.openwop.rust-hello.greet` (loaded WASM pack); exercises required exports + at least one import | `completed` | ≤ 10s |
|
|
81
|
+
| WASM Pack Memory-Cap Breach | `conformance-wasm-pack-memory-cap-breach` | RFC 0008 §K — invokes the deliberately-misbehaving `vendor.openwop.misbehaving.memory-bomb` pack (allocates 1 GiB beyond the host's `memoryPagesMax`). Host MUST emit `cap.breached` with `kind: "wasm-memory"` and drive the run to terminal `failed`. Misbehaving pack lives at `examples/packs/rust-misbehaving-memory/` and is fixture-only (NOT signed for registry publication). | `failed` (with `cap.breached`) | ≤ 10s |
|
|
82
|
+
| Configurable Schema | `conformance-configurable-schema` | Track 13 — workflow declares `configurableSchema` (`additionalProperties: false`, `recursionLimit: integer ≥ 1`). Suite verifies `GET /v1/workflows/{id}` surfaces the schema AND `POST /v1/runs` with a mismatched `configurable` returns `validation_error`. | `completed` (with accepted overlay) | ≤ 5s |
|
|
83
|
+
| Smoke — BYOK Roundtrip | `openwop-smoke-byok-roundtrip` | End-to-end BYOK secret-resolution smoke. Single `conformance.secret.echo` node fetches the host-provisioned canary secret `openwop-conformance-canary-secret`, emits SHA-256 hex + byte length to variables — never the raw value. Spec: `run-options.md` §"Credential references" + `auth.md` §"Secret resolution" + `observability.md` §"Redaction". | `completed` | ≤ 10s |
|
|
81
84
|
|
|
82
85
|
The `messages`-mode stream fixture (AI token streaming) is covered by the deterministic mock-provider surface in `spec/v1/run-options.md`. Hosts that do not advertise `Capabilities.testing.mockProviders` skip-equivalent on those scenarios.
|
|
83
86
|
|
|
@@ -321,6 +324,24 @@ Both items are tracked as v1.x conformance expansion work.
|
|
|
321
324
|
|
|
322
325
|
---
|
|
323
326
|
|
|
327
|
+
## `openwop-smoke-byok-roundtrip` (BYOK end-to-end smoke fixture)
|
|
328
|
+
|
|
329
|
+
> **Status: included in the v1.0 conformance baseline.** Server-side `conformance.secret.echo` support is exercised by `src/scenarios/byok-roundtrip.test.ts`.
|
|
330
|
+
|
|
331
|
+
- **Purpose**: verify the BYOK secret-resolution roundtrip end-to-end. A host that advertises `capabilities.secrets.supported: true` MUST resolve the canary `openwop-conformance-canary-secret` via its `SecretResolver` and surface only the SHA-256 hex + byte length on every observable channel (variables, events, debug bundle, logs). The raw value MUST NOT leak per `observability.md` §"Redaction" + `threat-model-secret-leakage.md` §SR-1.
|
|
332
|
+
- **Topology**: single node `resolve-secret` with `typeId: conformance.secret.echo`, `config.secretId: "openwop-conformance-canary-secret"`. Resolves the canary, hashes it, and writes `{secretSha256, secretLength}` to the run's `variables.resolve-secret`.
|
|
333
|
+
- **Conformance test driver**:
|
|
334
|
+
1. POST `/v1/runs` with `{workflowId: "openwop-smoke-byok-roundtrip"}`.
|
|
335
|
+
2. Poll until terminal.
|
|
336
|
+
3. **Assert** terminal status is `completed`.
|
|
337
|
+
4. **Assert** `variables['resolve-secret'].secretSha256` matches `^[0-9a-f]{64}$`.
|
|
338
|
+
5. **Assert** `variables['resolve-secret'].secretLength > 0`.
|
|
339
|
+
6. **Assert** event log does NOT contain a suspicious payload echoing the raw secret (regex check across `value`/`password`/`plaintext`/`raw_secret` adjacent to `secretSha256`).
|
|
340
|
+
|
|
341
|
+
Hosts that don't ship a BYOK SecretResolver MAY return `404` / `422` on the start-run call; the scenario soft-skips in that case.
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
324
345
|
## `conformance-channel-ttl` (closes C3 — channel TTL reducer fold)
|
|
325
346
|
|
|
326
347
|
> **Status: included in the v1.0 conformance baseline.** Server-side `core.channelWrite` support is exercised by `src/scenarios/channel-ttl.test.ts`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openwop/openwop-conformance",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Production-ready black-box conformance suite for OpenWOP v1.0 compliant servers.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -22,10 +22,12 @@
|
|
|
22
22
|
"schemas",
|
|
23
23
|
"vitest.config.ts",
|
|
24
24
|
"README.md",
|
|
25
|
+
"CHANGELOG.md",
|
|
25
26
|
"LICENSE"
|
|
26
27
|
],
|
|
27
28
|
"scripts": {
|
|
28
29
|
"test": "vitest run",
|
|
30
|
+
"test:strict": "vitest run --no-file-parallelism",
|
|
29
31
|
"test:watch": "vitest",
|
|
30
32
|
"typecheck": "tsc --noEmit",
|
|
31
33
|
"build:cli": "tsc -p tsconfig.build.json && chmod +x dist/cli.js",
|
package/schemas/README.md
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|---|---|---|
|
|
7
7
|
| `agent-manifest.schema.json` | `node-packs.md` + agent-pack RFCs | Agent manifest entries distributed alongside node-pack manifests |
|
|
8
8
|
| `agent-ref.schema.json` | `agent-memory.md` + agent-identity RFC | Multi-Agent Shift Phase 1 — slim runtime AgentRef projection carried on `RunSnapshot.agent` / `runOrchestrator`, `WorkflowNode.agent?`, and `agent.*` event payloads |
|
|
9
|
+
| `audit-verify-result.schema.json` | `auth-profiles.md` §`openwop-audit-log-integrity` | Response payload from `GET /v1/audit/verify` — chain-validity verdict + checkpoints + anomalies |
|
|
9
10
|
| `capabilities.schema.json` | `capabilities.md` | `/.well-known/openwop` response — protocolVersion + supportedEnvelopes + schemaVersions + limits + optional v1 discovery surface |
|
|
10
11
|
| `channel-written-payload.schema.json` | `channels-and-reducers.md` §Channel write event | Payload of the `channel.written` RunEvent — write input + reducer name |
|
|
11
12
|
| `conversation-event.schema.json` | `channels-and-reducers.md` + conversation RFC | Multi-turn conversation event shape for orchestrator-driven HITL flows |
|
|
@@ -16,12 +17,15 @@
|
|
|
16
17
|
| `memory-entry.schema.json` | memory-layer RFC | Persisted agent memory entry shape |
|
|
17
18
|
| `memory-list-options.schema.json` | memory-layer RFC | Query options for listing agent memory entries |
|
|
18
19
|
| `node-pack-manifest.schema.json` | `node-packs.md` | Pack manifest (`pack.json`) — name, version, engines, nodes[], runtime, signing |
|
|
20
|
+
| `pack-lockfile.schema.json` | `node-packs.md` §"Dependency resolution + lockfile" | Reproducible-build lockfile pinning resolved pack versions + SHA-256 integrity + Ed25519 signature for the entire workspace dependency graph |
|
|
21
|
+
| `registry-version-manifest.schema.json` | `registry-operations.md` | Registry-augmented version manifest served at `GET /v1/packs/{name}/-/{version}.json`. Extends the bare pack-manifest contract with registry-side metadata (integrity hash, signing-block polymorphism, lifecycle flags). Enforced by the `Validate version manifests against registry-version-manifest schema` step in `.github/workflows/registry-publish.yml`. |
|
|
19
22
|
| `orchestrator-decision.schema.json` | `node-packs.md` + orchestrator RFC | Decision output shape for orchestrator routing nodes |
|
|
20
23
|
| `run-event-payloads.schema.json` | `run-event.schema.json` §RunEventType | Per-RunEventType payload contracts, indexed by `$defs.<typeId>` for opt-in strict validation |
|
|
21
24
|
| `run-event.schema.json` | `version-negotiation.md` + `RunEventDoc` | Event log envelope + event type enum |
|
|
22
25
|
| `run-options.schema.json` | `run-options.md` | Per-run input overlay (configurable + tags + metadata) on `POST /v1/runs` |
|
|
23
26
|
| `run-orchestrator-decided-event.schema.json` | orchestrator RFC + `observability.md` | Event payload for orchestrator decisions |
|
|
24
27
|
| `run-snapshot.schema.json` | `rest-endpoints.md` §RunSnapshot | Projected run state from `GET /v1/runs/{runId}` |
|
|
28
|
+
| `security-advisory.schema.json` | `registry-operations.md` + INCIDENT-RESPONSE runbook | Registry-owned CVE advisory record at `registry/security/advisories.json`. One entry per disclosed vulnerability — id, severity, affected pack-name + SemVer range, optional fixedIn/advisoryUrl/credits. Enforced by `check-advisories.mjs` in `.github/workflows/registry-publish.yml`. |
|
|
25
29
|
| `suspend-request.schema.json` | `interrupt.md` | `InterruptPayload` with 8 `kind` discriminators (approval, clarification, external-event, custom, conversation.start, conversation.exchange, conversation.close, low-confidence) |
|
|
26
30
|
| `workflow-definition.schema.json` | `channels-and-reducers.md` + `node-packs.md` | DAG of nodes + edges + triggers + variables + channels |
|
|
27
31
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://openwop.dev/spec/v1/audit-verify-result.schema.json",
|
|
4
|
+
"title": "AuditVerifyResult",
|
|
5
|
+
"description": "Response payload from `GET /v1/audit/verify` per spec/v1/auth-profiles.md §`openwop-audit-log-integrity` §4 'Verification endpoint'. Hosts advertising the audit-log-integrity profile MUST return this shape on the verify endpoint when called with a valid `audit:read`-scoped credential. The shape carries the verifier's chain-validity verdict, the in-range signed checkpoints, and any anomaly records the verifier detected while re-walking the hash chain.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": ["fromSeq", "toSeq", "chainValid", "checkpoints", "anomalies"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"fromSeq": {
|
|
10
|
+
"type": "integer",
|
|
11
|
+
"minimum": 0,
|
|
12
|
+
"description": "Echo of the caller's `fromSeq` query parameter. The verifier MUST re-walk entries [fromSeq, toSeq] inclusive."
|
|
13
|
+
},
|
|
14
|
+
"toSeq": {
|
|
15
|
+
"type": "integer",
|
|
16
|
+
"minimum": 0,
|
|
17
|
+
"description": "Echo of the caller's `toSeq` query parameter. MUST be >= fromSeq."
|
|
18
|
+
},
|
|
19
|
+
"chainValid": {
|
|
20
|
+
"type": "boolean",
|
|
21
|
+
"description": "True when every entry's `prevHash` matches the SHA-256 of the prior entry's RFC 8785 JCS canonicalization AND every signed checkpoint in `checkpoints[]` verifies against the host's advertised `auditLogIntegrity.checkpointPublicKey`. False when ANY break or invalid signature is detected; `anomalies[]` enumerates the breaks."
|
|
22
|
+
},
|
|
23
|
+
"checkpointsValid": {
|
|
24
|
+
"type": "boolean",
|
|
25
|
+
"description": "OPTIONAL companion bit: true when every checkpoint signature in `checkpoints[]` verifies. Distinguishes 'chain broken but checkpoints OK' from 'checkpoints forged but chain intact'. Hosts MAY omit when `chainValid` already conveys the verdict; clients that distinguish the two failure modes SHOULD prefer hosts that surface this bit explicitly."
|
|
26
|
+
},
|
|
27
|
+
"checkpoints": {
|
|
28
|
+
"type": "array",
|
|
29
|
+
"description": "Signed checkpoints emitted within [fromSeq, toSeq]. Order: ascending by `atSequence`. Empty array MUST appear when no checkpoint was emitted in the window (not omitted).",
|
|
30
|
+
"items": { "$ref": "#/$defs/Checkpoint" }
|
|
31
|
+
},
|
|
32
|
+
"anomalies": {
|
|
33
|
+
"type": "array",
|
|
34
|
+
"description": "One entry per detected hash-chain break in [fromSeq, toSeq]. Empty array MUST appear when chainValid is true (not omitted).",
|
|
35
|
+
"items": { "$ref": "#/$defs/Anomaly" }
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"additionalProperties": false,
|
|
39
|
+
"$defs": {
|
|
40
|
+
"Checkpoint": {
|
|
41
|
+
"type": "object",
|
|
42
|
+
"required": ["checkpoint", "atSequence", "merkleRoot", "signature"],
|
|
43
|
+
"properties": {
|
|
44
|
+
"checkpoint": {
|
|
45
|
+
"type": "string",
|
|
46
|
+
"minLength": 1,
|
|
47
|
+
"maxLength": 256,
|
|
48
|
+
"description": "Host-issued checkpoint id. Globally unique within the host's audit log."
|
|
49
|
+
},
|
|
50
|
+
"atSequence": {
|
|
51
|
+
"type": "integer",
|
|
52
|
+
"minimum": 0,
|
|
53
|
+
"description": "Audit-log sequence number at which the checkpoint was minted. Inclusive — the entry at this sequence is covered by the checkpoint's merkleRoot."
|
|
54
|
+
},
|
|
55
|
+
"merkleRoot": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"minLength": 1,
|
|
58
|
+
"description": "Hex-encoded SHA-256 Merkle root over the canonicalized entries 0..atSequence inclusive. Verifiers re-compute and compare; mismatch implies chain mutation between two checkpoints."
|
|
59
|
+
},
|
|
60
|
+
"signature": {
|
|
61
|
+
"type": "string",
|
|
62
|
+
"minLength": 1,
|
|
63
|
+
"description": "Base64-encoded Ed25519 signature over the checkpoint's canonical JSON (excluding the `signature` field itself), produced with the host's advertised `auditLogIntegrity.checkpointPublicKey`."
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"additionalProperties": false
|
|
67
|
+
},
|
|
68
|
+
"Anomaly": {
|
|
69
|
+
"type": "object",
|
|
70
|
+
"required": ["atSeq", "expectedPrevHash", "actualPrevHash"],
|
|
71
|
+
"properties": {
|
|
72
|
+
"atSeq": {
|
|
73
|
+
"type": "integer",
|
|
74
|
+
"minimum": 0,
|
|
75
|
+
"description": "Sequence number of the entry whose `prevHash` failed verification."
|
|
76
|
+
},
|
|
77
|
+
"expectedPrevHash": {
|
|
78
|
+
"type": "string",
|
|
79
|
+
"minLength": 1,
|
|
80
|
+
"description": "Hex-encoded SHA-256 the verifier computed from the prior entry's RFC 8785 JCS canonicalization."
|
|
81
|
+
},
|
|
82
|
+
"actualPrevHash": {
|
|
83
|
+
"type": "string",
|
|
84
|
+
"description": "The `prevHash` value the audit-log entry actually carries. Empty string when the field is missing (a structural anomaly distinct from a hash mismatch)."
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"additionalProperties": false
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -82,9 +82,80 @@
|
|
|
82
82
|
"type": "object",
|
|
83
83
|
"description": "Optional v1 per-run overlay schema — what `RunOptions.configurable` keys this server honors."
|
|
84
84
|
},
|
|
85
|
+
"nodePackRuntimes": {
|
|
86
|
+
"type": "object",
|
|
87
|
+
"description": "Optional v1 advertisement of node-pack runtimes the host loads. See `node-packs.md` §runtime formats and RFC 0008 (WASM ABI). Hosts that don't load packs MAY omit this block entirely. NOTE: this block intentionally uses `additionalProperties: true` (here and on the nested runtime objects) so a future RFC may add a runtime type (e.g., `python-wasm`, `js-wasm`) without a breaking-change rev of this schema; the trade is that a strict-mode validator will accept arbitrary extra keys under these objects. A future RFC that promotes the open-set fields to first-class SHOULD tighten them to `additionalProperties: false` in the same RFC.",
|
|
88
|
+
"properties": {
|
|
89
|
+
"wasm": {
|
|
90
|
+
"type": "object",
|
|
91
|
+
"description": "WASM core-module runtime per RFC 0008. Hosts that load `runtime.language: \"wasm\"` packs MUST advertise `supported: true` and at least one entry in `abiVersions[]`. `additionalProperties: true` preserved for future RFC 0008 amendments (e.g., per-pack memory accounting fields).",
|
|
92
|
+
"required": ["supported"],
|
|
93
|
+
"properties": {
|
|
94
|
+
"supported": {
|
|
95
|
+
"type": "boolean",
|
|
96
|
+
"description": "Host loads RFC 0008 WASM packs."
|
|
97
|
+
},
|
|
98
|
+
"abiVersions": {
|
|
99
|
+
"type": "array",
|
|
100
|
+
"items": {
|
|
101
|
+
"type": "integer",
|
|
102
|
+
"minimum": 1
|
|
103
|
+
},
|
|
104
|
+
"uniqueItems": true,
|
|
105
|
+
"minItems": 1,
|
|
106
|
+
"description": "ABI versions the loader accepts. v1.1 hosts MUST include `1`. Packs declaring `openwop_abi_version()` outside this list MUST be rejected at load time per RFC 0008 §H."
|
|
107
|
+
},
|
|
108
|
+
"maxMemoryBytes": {
|
|
109
|
+
"type": "integer",
|
|
110
|
+
"minimum": 1048576,
|
|
111
|
+
"maximum": 8589934592,
|
|
112
|
+
"description": "Per-pack memory ceiling enforced by the host loader. Range: 1 MiB ≤ value ≤ 8 GiB. RFC 0008 §K — when a pack exceeds this, the host MUST emit `cap.breached` with `kind: \"wasm-memory\"`."
|
|
113
|
+
},
|
|
114
|
+
"loadedPacks": {
|
|
115
|
+
"type": "array",
|
|
116
|
+
"items": {
|
|
117
|
+
"type": "string",
|
|
118
|
+
"minLength": 1
|
|
119
|
+
},
|
|
120
|
+
"uniqueItems": true,
|
|
121
|
+
"description": "Pack names that passed instantiation (ABI check + load). Packs rejected per RFC 0008 §H MUST NOT appear here. Hosts MAY advertise this for observability; conformance asserts rejection by absence (Track 7)."
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"additionalProperties": true
|
|
125
|
+
},
|
|
126
|
+
"wasmComponent": {
|
|
127
|
+
"type": "object",
|
|
128
|
+
"description": "WASM Component Model variant (WIT-defined interfaces). Reserved for hosts that load `runtime.language: \"wasm-component\"` packs. `additionalProperties: true` preserved until the Component Model spec stabilises in the v1.x line; tighten in the RFC that promotes wasm-component to a first-class runtime alongside `wasm`.",
|
|
129
|
+
"properties": {
|
|
130
|
+
"supported": { "type": "boolean" }
|
|
131
|
+
},
|
|
132
|
+
"additionalProperties": true
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"additionalProperties": true
|
|
136
|
+
},
|
|
85
137
|
"observability": {
|
|
86
138
|
"type": "object",
|
|
87
|
-
"description": "Optional v1 hints about emitted spans/metrics/logs. See observability.md."
|
|
139
|
+
"description": "Optional v1 hints about emitted spans/metrics/logs. See observability.md.",
|
|
140
|
+
"properties": {
|
|
141
|
+
"otel": {
|
|
142
|
+
"type": "object",
|
|
143
|
+
"description": "OTel-specific advertisement. Hosts that emit OTLP traces/metrics MAY advertise the transport protocols they support so collectors can configure exporters accordingly. Track 11 follow-up.",
|
|
144
|
+
"properties": {
|
|
145
|
+
"exportProtocols": {
|
|
146
|
+
"type": "array",
|
|
147
|
+
"items": {
|
|
148
|
+
"type": "string",
|
|
149
|
+
"enum": ["http/json", "http/protobuf", "grpc"]
|
|
150
|
+
},
|
|
151
|
+
"uniqueItems": true,
|
|
152
|
+
"description": "OTLP export protocols the host supports emitting. `http/json` and `http/protobuf` are mandatory for hosts advertising OTel emission; `grpc` is opt-in per Track 11."
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
"additionalProperties": true
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
"additionalProperties": true
|
|
88
159
|
},
|
|
89
160
|
"minClientVersion": {
|
|
90
161
|
"type": "string",
|
|
@@ -260,6 +331,55 @@
|
|
|
260
331
|
},
|
|
261
332
|
"additionalProperties": true
|
|
262
333
|
},
|
|
334
|
+
"memory": {
|
|
335
|
+
"type": "object",
|
|
336
|
+
"description": "MemoryAdapter capability block per RFC 0004 + the optional compaction profile per RFC 0012. Hosts that don't wire any memory surface omit the entire block.",
|
|
337
|
+
"properties": {
|
|
338
|
+
"supported": {
|
|
339
|
+
"type": "boolean",
|
|
340
|
+
"description": "When `true`, host implements the four-operation MemoryAdapter contract (`list`, `get`, `put`, `delete`) per RFC 0004 §A."
|
|
341
|
+
},
|
|
342
|
+
"maxEntrySizeBytes": {
|
|
343
|
+
"type": "integer",
|
|
344
|
+
"minimum": 1,
|
|
345
|
+
"description": "Upper bound on `MemoryEntry.content` size. Hosts SHOULD reject `put` exceeding this with `validation_error`."
|
|
346
|
+
},
|
|
347
|
+
"ttlSupported": {
|
|
348
|
+
"type": "boolean",
|
|
349
|
+
"description": "When `true`, host honors `expiresAt` per RFC 0004 §E."
|
|
350
|
+
},
|
|
351
|
+
"compaction": {
|
|
352
|
+
"type": "object",
|
|
353
|
+
"description": "RFC 0012 Memory Compaction Profile (Accepted 2026-05-15). Hosts that distill many short-lived MemoryEntry rows into fewer long-lived ones MAY advertise here; advertising implies the SR-1 carry-forward invariant (`SECURITY/invariants.yaml` row `memory-compaction-sr-1-carry-forward`).",
|
|
354
|
+
"required": ["supported"],
|
|
355
|
+
"properties": {
|
|
356
|
+
"supported": {
|
|
357
|
+
"type": "boolean",
|
|
358
|
+
"description": "REQUIRED when the sub-block is present. When `true`, host performs compaction over `longTerm` memory and emits the `memory.compacted` event per `observability.md` §Canonical event vocabulary."
|
|
359
|
+
},
|
|
360
|
+
"trigger": {
|
|
361
|
+
"type": "string",
|
|
362
|
+
"enum": ["host-managed", "client-requested", "both"],
|
|
363
|
+
"description": "REQUIRED when `supported: true` per RFC 0012 §A (enforced via the `if/then` clause). `host-managed` runs on a host-internal schedule clients do not control. `client-requested` and `both` are reserved enum values; v1.x normates only `host-managed`."
|
|
364
|
+
},
|
|
365
|
+
"maxInputEntries": {
|
|
366
|
+
"type": "integer",
|
|
367
|
+
"minimum": 1,
|
|
368
|
+
"description": "Informational ceiling on how many source entries one compaction call collapses. Not wire-enforced."
|
|
369
|
+
},
|
|
370
|
+
"maxOutputBytes": {
|
|
371
|
+
"type": "integer",
|
|
372
|
+
"minimum": 0,
|
|
373
|
+
"description": "Informational ceiling on the distilled entry size. SHOULD be ≤ `memory.maxEntrySizeBytes`."
|
|
374
|
+
}
|
|
375
|
+
},
|
|
376
|
+
"additionalProperties": false,
|
|
377
|
+
"if": { "properties": { "supported": { "const": true } }, "required": ["supported"] },
|
|
378
|
+
"then": { "required": ["supported", "trigger"] }
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
"additionalProperties": true
|
|
382
|
+
},
|
|
263
383
|
"conversationPrimitive": {
|
|
264
384
|
"type": "boolean",
|
|
265
385
|
"description": "Multi-Agent Shift Phase 4. When `true`, host advertises that it implements the `core.conversationGate` typeId AND honors the `conversation.start` / `conversation.exchange` / `conversation.close` suspend variants. Hosts that don't claim this fall back to `clarification.requested` interrupts for multi-turn user interjections."
|
|
@@ -281,6 +401,227 @@
|
|
|
281
401
|
}
|
|
282
402
|
},
|
|
283
403
|
"additionalProperties": true
|
|
404
|
+
},
|
|
405
|
+
"production": {
|
|
406
|
+
"type": "object",
|
|
407
|
+
"description": "Production-profile advertisement (see production-profile.md). Optional in v1; absence means the host does not claim the openwop-production profile. When `supported: true`, the host claims every MUST in production-profile.md and conformance scenarios gated on this block MUST run. Landed by RFC 0009.",
|
|
408
|
+
"required": ["supported"],
|
|
409
|
+
"properties": {
|
|
410
|
+
"supported": {
|
|
411
|
+
"type": "boolean",
|
|
412
|
+
"description": "Host claims the openwop-production profile end-to-end (production-profile.md)."
|
|
413
|
+
},
|
|
414
|
+
"backpressure": {
|
|
415
|
+
"type": "object",
|
|
416
|
+
"description": "Backpressure envelope advertisement (production-profile.md §Backpressure).",
|
|
417
|
+
"properties": {
|
|
418
|
+
"supported": {
|
|
419
|
+
"type": "boolean",
|
|
420
|
+
"description": "Host returns 503 + Retry-After + canonical envelope under load per production-profile.md §Backpressure."
|
|
421
|
+
},
|
|
422
|
+
"inflightCap": {
|
|
423
|
+
"type": "integer",
|
|
424
|
+
"minimum": 1,
|
|
425
|
+
"description": "Optional host-side concurrent-inflight cap the conformance suite can saturate. When advertised, the production-backpressure scenario issues `inflightCap + 1` concurrent long-lived requests to deterministically force a 503. When absent, the scenario soft-skips the saturation step (envelope assertion still runs if a 503 happens to fire)."
|
|
426
|
+
},
|
|
427
|
+
"retryAfterSeconds": {
|
|
428
|
+
"type": "integer",
|
|
429
|
+
"minimum": 0,
|
|
430
|
+
"maximum": 86400,
|
|
431
|
+
"description": "Optional advertised Retry-After value in seconds the host returns on 503. When present, MUST equal both the `Retry-After` header and the `details.retryAfter` body field per production-profile.md. Upper bound 86400 (24h) — values beyond that are operationally indistinguishable from 'permanently denied'. Hosts needing longer holds SHOULD omit `Retry-After` entirely (RFC 0009 Q#2)."
|
|
432
|
+
}
|
|
433
|
+
},
|
|
434
|
+
"additionalProperties": false
|
|
435
|
+
},
|
|
436
|
+
"retention": {
|
|
437
|
+
"type": "object",
|
|
438
|
+
"description": "Event-retention advertisement (production-profile.md §\"Event retention\").",
|
|
439
|
+
"properties": {
|
|
440
|
+
"supported": {
|
|
441
|
+
"type": "boolean",
|
|
442
|
+
"description": "Host enforces event-log retention with a documented minimum window."
|
|
443
|
+
},
|
|
444
|
+
"minWindowSeconds": {
|
|
445
|
+
"type": "integer",
|
|
446
|
+
"minimum": 604800,
|
|
447
|
+
"description": "Documented minimum retention window in seconds. Per production-profile.md §\"Event retention\", MUST be ≥ 604800 (7 days) for public hosts; development-only hosts MAY advertise a smaller window but MUST NOT claim `supported: true` while doing so."
|
|
448
|
+
},
|
|
449
|
+
"testForceExpire": {
|
|
450
|
+
"type": "boolean",
|
|
451
|
+
"description": "Host exposes a test-only force-expire hook the conformance suite can call (URL/method supplied via `OPENWOP_TEST_FORCE_EXPIRE_URL` / `OPENWOP_TEST_FORCE_EXPIRE_METHOD` env vars). When `false`, the production-retention-expiry scenario asserts only the 410/404 envelope shape on an operator-supplied already-expired run id (via `OPENWOP_TEST_EXPIRED_RUN_ID`); otherwise it soft-skips. RFC 0009 unresolved question #1 — endpoint normation is deferred."
|
|
452
|
+
}
|
|
453
|
+
},
|
|
454
|
+
"additionalProperties": false
|
|
455
|
+
},
|
|
456
|
+
"debugBundle": {
|
|
457
|
+
"type": "object",
|
|
458
|
+
"description": "Debug-bundle truncation advertisement (production-profile.md §\"Debug bundle behavior\"). Stricter than the existing `capabilities.debugBundle.supported` advertised per debug-bundle.md — this block adds the production-profile MUSTs (truncation metadata, redaction).",
|
|
459
|
+
"properties": {
|
|
460
|
+
"supported": {
|
|
461
|
+
"type": "boolean",
|
|
462
|
+
"description": "Host claims production-profile debug-bundle behavior end-to-end."
|
|
463
|
+
},
|
|
464
|
+
"truncationMetadata": {
|
|
465
|
+
"type": "boolean",
|
|
466
|
+
"description": "When `true`, host surfaces `truncated: true` + non-empty `truncatedReason` per debug-bundle.md §\"Bundle size limits\" when caps are reached."
|
|
467
|
+
}
|
|
468
|
+
},
|
|
469
|
+
"additionalProperties": false
|
|
470
|
+
}
|
|
471
|
+
},
|
|
472
|
+
"additionalProperties": false
|
|
473
|
+
},
|
|
474
|
+
"auth": {
|
|
475
|
+
"type": "object",
|
|
476
|
+
"description": "Auth-profile advertisement (auth-profiles.md). Optional in v1; absence preserves the baseline bearer-token contract from auth.md. RFC 0010 formalized this block; `additionalProperties: true` permits existing informal usages (`auth.auditLogIntegrity` from the audit-log-integrity profile) to continue alongside the formal sub-blocks defined here.",
|
|
477
|
+
"properties": {
|
|
478
|
+
"profiles": {
|
|
479
|
+
"type": "array",
|
|
480
|
+
"items": { "type": "string", "minLength": 1 },
|
|
481
|
+
"uniqueItems": true,
|
|
482
|
+
"description": "Auth profiles the host claims. Canonical ids: `openwop-audit-log-integrity` (auth-profiles.md §Audit-log integrity), `openwop-auth-api-key-rotation`, `openwop-auth-oauth2-client-credentials`, `openwop-auth-oidc-user-bearer`, `openwop-auth-mtls`. Clients SHOULD tolerate unknown profile ids."
|
|
483
|
+
},
|
|
484
|
+
"rotation": {
|
|
485
|
+
"type": "object",
|
|
486
|
+
"description": "API-key rotation advertisement (auth-profiles.md §`openwop-auth-api-key-rotation`).",
|
|
487
|
+
"properties": {
|
|
488
|
+
"supported": {
|
|
489
|
+
"type": "boolean",
|
|
490
|
+
"description": "Host claims the openwop-auth-api-key-rotation profile (old+new key overlap during a documented grace window)."
|
|
491
|
+
},
|
|
492
|
+
"minGraceSeconds": {
|
|
493
|
+
"type": "integer",
|
|
494
|
+
"minimum": 0,
|
|
495
|
+
"description": "Minimum rotation grace window in seconds. auth-profiles.md SHOULDs production-profile hosts to ≥ 86400 (24h). The conformance scenario tolerates any non-negative value but warns in behavior mode when < 86400."
|
|
496
|
+
}
|
|
497
|
+
},
|
|
498
|
+
"additionalProperties": false
|
|
499
|
+
},
|
|
500
|
+
"oauth2": {
|
|
501
|
+
"type": "object",
|
|
502
|
+
"description": "OAuth2 client-credentials advertisement (auth-profiles.md §`openwop-auth-oauth2-client-credentials`).",
|
|
503
|
+
"properties": {
|
|
504
|
+
"supported": { "type": "boolean" },
|
|
505
|
+
"issuer": {
|
|
506
|
+
"type": "string",
|
|
507
|
+
"format": "uri",
|
|
508
|
+
"description": "Token issuer URL the host trusts. Tokens MUST carry a matching `iss` claim."
|
|
509
|
+
},
|
|
510
|
+
"audience": {
|
|
511
|
+
"type": "string",
|
|
512
|
+
"description": "Audience the host requires. Tokens MUST carry a matching `aud` claim."
|
|
513
|
+
},
|
|
514
|
+
"supportedAlgorithms": {
|
|
515
|
+
"type": "array",
|
|
516
|
+
"items": { "type": "string", "minLength": 1 },
|
|
517
|
+
"uniqueItems": true,
|
|
518
|
+
"description": "JWS signing algorithms the host accepts (canonical: RS256, ES256). Hosts MUST reject tokens signed with algorithms outside this list."
|
|
519
|
+
}
|
|
520
|
+
},
|
|
521
|
+
"additionalProperties": false
|
|
522
|
+
},
|
|
523
|
+
"oidc": {
|
|
524
|
+
"type": "object",
|
|
525
|
+
"description": "OIDC user-bearer advertisement (auth-profiles.md §`openwop-auth-oidc-user-bearer`).",
|
|
526
|
+
"properties": {
|
|
527
|
+
"supported": { "type": "boolean" },
|
|
528
|
+
"issuers": {
|
|
529
|
+
"type": "array",
|
|
530
|
+
"items": { "type": "string", "format": "uri" },
|
|
531
|
+
"minItems": 1,
|
|
532
|
+
"uniqueItems": true,
|
|
533
|
+
"description": "Trusted OIDC issuer URLs. The host accepts tokens whose `iss` claim matches any entry."
|
|
534
|
+
},
|
|
535
|
+
"audience": {
|
|
536
|
+
"type": "string",
|
|
537
|
+
"description": "Audience identifier the host requires in OIDC tokens."
|
|
538
|
+
},
|
|
539
|
+
"supportedScopeMapping": {
|
|
540
|
+
"type": "string",
|
|
541
|
+
"enum": ["group-claim", "scope-claim", "host-acl"],
|
|
542
|
+
"description": "How the host derives openwop scopes from the OIDC token. `group-claim`: from `groups` claim via host config. `scope-claim`: from `scope` claim directly. `host-acl`: from a host-side mapping table (sub → scope)."
|
|
543
|
+
},
|
|
544
|
+
"introspectionIntervalSeconds": {
|
|
545
|
+
"type": "integer",
|
|
546
|
+
"minimum": 0,
|
|
547
|
+
"description": "Maximum interval at which the host SHOULD re-introspect a cached token to detect IdP revocation. auth-profiles.md recommends `min(exp - now, 300)`."
|
|
548
|
+
}
|
|
549
|
+
},
|
|
550
|
+
"additionalProperties": false
|
|
551
|
+
},
|
|
552
|
+
"mtls": {
|
|
553
|
+
"type": "object",
|
|
554
|
+
"description": "mTLS advertisement (auth-profiles.md §`openwop-auth-mtls`).",
|
|
555
|
+
"properties": {
|
|
556
|
+
"supported": { "type": "boolean" },
|
|
557
|
+
"required": {
|
|
558
|
+
"type": "boolean",
|
|
559
|
+
"description": "When `true`, the host rejects bearer-only requests (mTLS required for all authenticated calls). When `false`, mTLS is optional and complements bearer auth."
|
|
560
|
+
},
|
|
561
|
+
"subjectMapping": {
|
|
562
|
+
"type": "string",
|
|
563
|
+
"enum": ["cn", "san-dns", "san-uri"],
|
|
564
|
+
"description": "How the host derives the transport principal from the client certificate. `cn`: subject CN. `san-dns`: subjectAltName DNS entry. `san-uri`: subjectAltName URI entry."
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
"additionalProperties": false
|
|
568
|
+
}
|
|
569
|
+
},
|
|
570
|
+
"additionalProperties": true
|
|
571
|
+
},
|
|
572
|
+
"discovery": {
|
|
573
|
+
"type": "object",
|
|
574
|
+
"description": "Discovery advertisement (capabilities-change-detection.md). Optional in v1; absence means the host serves only the public unauthenticated payload at /.well-known/openwop. Landed by RFC 0011.",
|
|
575
|
+
"properties": {
|
|
576
|
+
"authScoped": {
|
|
577
|
+
"type": "object",
|
|
578
|
+
"description": "Auth-scoped discovery advertisement (capabilities-change-detection.md §\"Scoped capability views\"). Hosts that return a different payload when called with Authorization than when called anonymously declare it here. The authenticated view MUST still satisfy the base capabilities.schema.json shape per the spec annex.",
|
|
579
|
+
"properties": {
|
|
580
|
+
"supported": {
|
|
581
|
+
"type": "boolean",
|
|
582
|
+
"description": "Host returns an authenticated/tenant-scoped capability view when the discovery endpoint is called with valid bearer credentials."
|
|
583
|
+
},
|
|
584
|
+
"mode": {
|
|
585
|
+
"type": "string",
|
|
586
|
+
"enum": ["same-endpoint", "extension-endpoint"],
|
|
587
|
+
"description": "How the host exposes the auth-scoped view. `same-endpoint`: the canonical /.well-known/openwop returns a narrowed/enriched view when authenticated. `extension-endpoint`: a separate host route carries the scoped view (path advertised via `endpointPath`). Hosts using the third pattern from the spec annex (documentation pointer in the public payload) MAY omit this field."
|
|
588
|
+
},
|
|
589
|
+
"endpointPath": {
|
|
590
|
+
"type": "string",
|
|
591
|
+
"pattern": "^/",
|
|
592
|
+
"description": "When `mode: \"extension-endpoint\"` is advertised, the leading-slash relative path the host serves the scoped view from. The conformance scenario hits this path with bearer credentials. Absolute URLs are rejected at the schema level."
|
|
593
|
+
}
|
|
594
|
+
},
|
|
595
|
+
"additionalProperties": false
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
"additionalProperties": false
|
|
599
|
+
},
|
|
600
|
+
"i18n": {
|
|
601
|
+
"type": "object",
|
|
602
|
+
"description": "Locale-negotiation advertisement per spec/v1/i18n.md. Optional in v1; absence means the host serves a single locale always (typically `en`). When `supported: true`, the host honors `Accept-Language` on every protected route and emits `Content-Language` on responses carrying localized text.",
|
|
603
|
+
"properties": {
|
|
604
|
+
"supported": {
|
|
605
|
+
"type": "boolean",
|
|
606
|
+
"description": "Host honors `Accept-Language` and returns localized human-facing text when negotiable."
|
|
607
|
+
},
|
|
608
|
+
"defaultLocale": {
|
|
609
|
+
"type": "string",
|
|
610
|
+
"pattern": "^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8}){0,3}$",
|
|
611
|
+
"description": "BCP 47 language tag the host falls back to when no `Accept-Language` matches `supportedLocales`. Default: `\"en\"` when omitted."
|
|
612
|
+
},
|
|
613
|
+
"supportedLocales": {
|
|
614
|
+
"type": "array",
|
|
615
|
+
"minItems": 1,
|
|
616
|
+
"uniqueItems": true,
|
|
617
|
+
"items": {
|
|
618
|
+
"type": "string",
|
|
619
|
+
"pattern": "^[a-zA-Z]{2,3}(-[a-zA-Z0-9]{2,8}){0,3}$"
|
|
620
|
+
},
|
|
621
|
+
"description": "BCP 47 tags of locales the host has validated end-to-end for human-facing text. MUST contain `defaultLocale` when both are present."
|
|
622
|
+
}
|
|
623
|
+
},
|
|
624
|
+
"additionalProperties": false
|
|
284
625
|
}
|
|
285
626
|
},
|
|
286
627
|
"additionalProperties": true
|
|
@@ -192,8 +192,8 @@
|
|
|
192
192
|
"properties": {
|
|
193
193
|
"language": {
|
|
194
194
|
"type": "string",
|
|
195
|
-
"enum": ["javascript", "python", "go", "wasm", "remote"],
|
|
196
|
-
"description": "How the engine loads the pack. See node-packs.md §runtime formats."
|
|
195
|
+
"enum": ["javascript", "python", "go", "wasm", "wasm-component", "remote"],
|
|
196
|
+
"description": "How the engine loads the pack. See node-packs.md §runtime formats. `wasm` is the core-module WASM ABI (RFC 0008). `wasm-component` is the WASM Component Model variant (WIT-defined interfaces); hosts that advertise `capabilities.nodePackRuntimes.wasmComponent.supported: true` load it via wasmtime / wasmer Component Model runtimes. Both share the openwop ABI envelope; the wasm-component variant uses WIT interfaces instead of hand-rolled imports/exports."
|
|
197
197
|
},
|
|
198
198
|
"entry": {
|
|
199
199
|
"type": "string",
|
|
@@ -201,8 +201,8 @@
|
|
|
201
201
|
},
|
|
202
202
|
"format": {
|
|
203
203
|
"type": "string",
|
|
204
|
-
"enum": ["esm", "cjs", "wheel", "binary", "shared-library", "wasm"],
|
|
205
|
-
"description": "Runtime-specific format hint. `esm`/`cjs` for JS, `wheel` for Python, `binary`/`shared-library` for Go, `wasm` for wasm."
|
|
204
|
+
"enum": ["esm", "cjs", "wheel", "binary", "shared-library", "wasm", "wasm-component"],
|
|
205
|
+
"description": "Runtime-specific format hint. `esm`/`cjs` for JS, `wheel` for Python, `binary`/`shared-library` for Go, `wasm` for core-module WASM (RFC 0008), `wasm-component` for WASM Component Model preview 3+ (WIT-defined interfaces, additive RFC 0008.1)."
|
|
206
206
|
},
|
|
207
207
|
"minRuntimeVersion": {
|
|
208
208
|
"type": "string",
|