@openwop/openwop-conformance 1.106.1 → 1.124.0
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 +3 -3
- package/coverage.md +6 -0
- package/dist/cli.js +89 -45
- package/dist/lib/certification-bundle-verify.js +274 -0
- package/dist/lib/profiles.js +102 -19
- package/dist/lib/requirement-ledger.js +182 -0
- package/dist/lib/requirement-registry.js +110 -0
- package/dist/lib/scenario-disposition.js +249 -0
- package/dist/lib/soft-skip.js +82 -0
- package/fixtures/conformance-a2a-task-roundtrip.json +1 -1
- package/fixtures.md +1 -1
- package/package.json +1 -1
- package/schemas/CORPUS-STAMP.json +2 -2
- package/schemas/README.md +1 -0
- package/schemas/capabilities.schema.json +2 -2
- package/schemas/compensation-policy.schema.json +64 -0
- package/schemas/run-snapshot.schema.json +5 -0
- package/schemas/workflow-chain-pack-manifest.schema.json +125 -0
- package/schemas/workflow-definition.schema.json +4 -0
- package/src/cli.ts +99 -45
- package/src/lib/a2a-fake-peer.ts +290 -110
- package/src/lib/certification-bundle-verify.ts +356 -0
- package/src/lib/error-envelope.ts +77 -0
- package/src/lib/llm-cache-key-recipe.ts +6 -5
- package/src/lib/mcp-fake-server.ts +235 -72
- package/src/lib/profiles.ts +132 -19
- package/src/lib/requirement-ledger.ts +98 -1
- package/src/lib/requirement-registry.ts +47 -4
- package/src/lib/scenario-disposition.ts +291 -0
- package/src/lib/soft-skip.ts +89 -0
- package/src/lib/workflow-chain-expansion.ts +189 -0
- package/src/scenarios/a2a-1-0-agent-card.test.ts +179 -0
- package/src/scenarios/a2a-1-0-task-roundtrip.test.ts +109 -0
- package/src/scenarios/a2a-card-runtime-consistency.test.ts +167 -0
- package/src/scenarios/a2a-peer-authority.test.ts +99 -0
- package/src/scenarios/a2a-task-roundtrip.test.ts +18 -6
- package/src/scenarios/agent-loop-iteration-monotonic.test.ts +3 -2
- package/src/scenarios/agent-loop-stateful-resume.test.ts +3 -2
- package/src/scenarios/agent-loop-version5-shape.test.ts +2 -1
- package/src/scenarios/agent-loop-workspace-snapshot.test.ts +4 -3
- package/src/scenarios/approval-gate-flow.test.ts +5 -4
- package/src/scenarios/artifact-type-store-without-render.test.ts +2 -1
- package/src/scenarios/auth-scim-profile.test.ts +5 -4
- package/src/scenarios/authorization-fail-closed.test.ts +4 -3
- package/src/scenarios/certification-bundle-non-vacuous.test.ts +249 -0
- package/src/scenarios/certification-bundle-redaction.test.ts +182 -0
- package/src/scenarios/certification-floor-enforcement.test.ts +30 -6
- package/src/scenarios/chain-compensation-expansion.test.ts +243 -0
- package/src/scenarios/commitment-fired.test.ts +3 -2
- package/src/scenarios/compensation-behavior.test.ts +63 -0
- package/src/scenarios/compensation-profile.test.ts +144 -1
- package/src/scenarios/conformance-advertised-seam-required.test.ts +118 -0
- package/src/scenarios/conformance-execution-witness.test.ts +104 -0
- package/src/scenarios/conversationCapabilityNegotiation.test.ts +3 -2
- package/src/scenarios/core-manifest-and-extension-registry.test.ts +26 -0
- package/src/scenarios/credential-payload-redaction.test.ts +4 -3
- package/src/scenarios/credentials-capability-shape.test.ts +4 -3
- package/src/scenarios/cross-engine-append-behavior.test.ts +5 -4
- package/src/scenarios/cross-engine-append-ordering.test.ts +3 -2
- package/src/scenarios/cross-host-ancestry-endpoint.test.ts +5 -4
- package/src/scenarios/cross-host-causation-shape.test.ts +3 -2
- package/src/scenarios/cross-workspace-isolation.test.ts +4 -3
- package/src/scenarios/data-residency-admission.test.ts +6 -6
- package/src/scenarios/deadletter-retry-exhaustion.test.ts +5 -4
- package/src/scenarios/distillation-index-roundtrip.test.ts +3 -2
- package/src/scenarios/distillation-secret-carryforward.test.ts +3 -2
- package/src/scenarios/distillation-shape.test.ts +2 -1
- package/src/scenarios/distillation-stable-archive.test.ts +4 -3
- package/src/scenarios/distillation-token-budget.test.ts +4 -3
- package/src/scenarios/envelope-recovery-applied.test.ts +3 -2
- package/src/scenarios/envelope-refusal-shape.test.ts +4 -3
- package/src/scenarios/error-envelope-canonical-shape.test.ts +64 -0
- package/src/scenarios/feedback-correction-redaction.test.ts +4 -3
- package/src/scenarios/feedback-cross-tenant-isolation.test.ts +4 -3
- package/src/scenarios/feedback-fork-not-copied.test.ts +6 -5
- package/src/scenarios/feedback-on-terminal-run.test.ts +4 -3
- package/src/scenarios/feedback-record-and-list.test.ts +4 -3
- package/src/scenarios/feedback-unsupported-501.test.ts +3 -2
- package/src/scenarios/fixtures-valid.test.ts +16 -18
- package/src/scenarios/fs-path-traversal.test.ts +3 -2
- package/src/scenarios/heartbeat-capability-shape.test.ts +2 -1
- package/src/scenarios/heartbeat-fires-once-per-tick.test.ts +4 -3
- package/src/scenarios/heartbeat-idempotent-no-spam.test.ts +6 -5
- package/src/scenarios/heartbeat-runtime-bound.test.ts +4 -3
- package/src/scenarios/mcp-2026-07-28-discover.test.ts +207 -0
- package/src/scenarios/mcp-cache-tenant-scope.test.ts +66 -0
- package/src/scenarios/mcp-current-auth-boundary.test.ts +55 -0
- package/src/scenarios/mcp-extension-opacity.test.ts +79 -0
- package/src/scenarios/mcp-mrtr-roundtrip.test.ts +140 -0
- package/src/scenarios/mcp-stateless-request.test.ts +77 -0
- package/src/scenarios/mcp-tool-roundtrip.test.ts +4 -3
- package/src/scenarios/mcp-toolcall-redaction.test.ts +2 -1
- package/src/scenarios/memory-attribution-emits-on-write.test.ts +6 -5
- package/src/scenarios/memory-attribution-no-content.test.ts +4 -3
- package/src/scenarios/memory-attribution-replay-stable.test.ts +6 -5
- package/src/scenarios/memory-attribution-tenant-scoped.test.ts +4 -3
- package/src/scenarios/memory-compaction-event-emitted.test.ts +3 -2
- package/src/scenarios/memory-compaction-provenance-tag.test.ts +6 -5
- package/src/scenarios/memory-compaction-sr1-carry-forward.test.ts +4 -3
- package/src/scenarios/memory-consolidation-idempotent.test.ts +4 -3
- package/src/scenarios/memory-injection-budget.test.ts +4 -3
- package/src/scenarios/metric-emission.test.ts +4 -3
- package/src/scenarios/multi-agent-confidence-escalation.test.ts +5 -4
- package/src/scenarios/multi-agent-handoff-state-machine.test.ts +4 -3
- package/src/scenarios/multi-agent-memory-lifecycle.test.ts +5 -4
- package/src/scenarios/multi-party-conversation-behavioral.test.ts +3 -2
- package/src/scenarios/multi-region-idempotency-behavior.test.ts +7 -6
- package/src/scenarios/multi-region-idempotency.test.ts +4 -3
- package/src/scenarios/normative-example-extraction.test.ts +242 -0
- package/src/scenarios/oauth-authorization-code-roundtrip.test.ts +4 -3
- package/src/scenarios/oauth-capability-shape.test.ts +4 -3
- package/src/scenarios/oauth-connector-redaction.test.ts +4 -3
- package/src/scenarios/openapi-asyncapi-sdk-parity.test.ts +309 -0
- package/src/scenarios/org-position-no-authority-escalation.test.ts +2 -1
- package/src/scenarios/otel-emission-grpc.test.ts +4 -3
- package/src/scenarios/otel-emission.test.ts +4 -3
- package/src/scenarios/otel-trace-propagation-subworkflow.test.ts +5 -4
- package/src/scenarios/otel-trace-propagation.test.ts +4 -3
- package/src/scenarios/pack-registry-isolation.test.ts +4 -3
- package/src/scenarios/pack-registry-publish.test.ts +65 -3
- package/src/scenarios/pack-registry.test.ts +22 -0
- package/src/scenarios/profile-discovery-core-alias.test.ts +137 -0
- package/src/scenarios/profileDerivation.test.ts +2 -1
- package/src/scenarios/provider-usage.test.ts +2 -2
- package/src/scenarios/rate-limit-envelope.test.ts +2 -1
- package/src/scenarios/registry-public.test.ts +6 -5
- package/src/scenarios/replay-divergence-at-refusal.test.ts +9 -8
- package/src/scenarios/replay-llm-cache-key-portable.test.ts +19 -13
- package/src/scenarios/replay-llm-cache-key.test.ts +120 -47
- package/src/scenarios/replay-observable-sequence-determinism.test.ts +5 -4
- package/src/scenarios/replay-side-effect-suppression.test.ts +20 -1
- package/src/scenarios/requirement-ledger.test.ts +29 -6
- package/src/scenarios/runner-ledger.test.ts +279 -0
- package/src/scenarios/runtime-requires-install-gate.test.ts +6 -5
- package/src/scenarios/sandbox-memory-cap.test.ts +3 -2
- package/src/scenarios/sandbox-mvp-behavior.test.ts +11 -10
- package/src/scenarios/sandbox-no-host-fs-escape.test.ts +2 -1
- package/src/scenarios/sandbox-timeout-cap.test.ts +3 -2
- package/src/scenarios/stream-text-fixture.test.ts +5 -4
- package/src/scenarios/subrun-approval-fail-closed.test.ts +3 -2
- package/src/scenarios/subrun-approval-gate.test.ts +4 -3
- package/src/scenarios/subrun-attestation-shape.test.ts +2 -1
- package/src/scenarios/subrun-checksum-stable.test.ts +4 -3
- package/src/scenarios/table-schema-enforcement.test.ts +2 -2
- package/src/scenarios/tool-hooks-authorization-fail-closed.test.ts +3 -2
- package/src/scenarios/tool-hooks-content-free.test.ts +3 -2
- package/src/scenarios/tool-hooks-rate-limit.test.ts +3 -2
- package/src/scenarios/tool-hooks-secret-redaction.test.ts +3 -2
- package/src/scenarios/tool-hooks-shape.test.ts +2 -1
- package/src/scenarios/trigger-bridge-delivery.test.ts +3 -2
- package/src/scenarios/version-fold.test.ts +5 -4
- package/src/scenarios/voice-streamref-tenant-bound.test.ts +2 -1
- package/src/scenarios/voice-transcription-streaming.test.ts +2 -1
- package/src/scenarios/voice-transcription-unadvertised.test.ts +2 -1
- package/src/scenarios/wasm-pack-abi-version-rejection.test.ts +5 -4
- package/src/scenarios/wasm-pack-invoke-completed.test.ts +3 -2
- package/src/scenarios/wasm-pack-invoke-suspended.test.ts +3 -2
- package/src/scenarios/wasm-pack-load.test.ts +4 -3
- package/src/scenarios/wasm-pack-memory-cap.test.ts +4 -3
- package/src/scenarios/wasm-pack-replay-determinism.test.ts +3 -2
- package/src/scenarios/webhook-signed-delivery.test.ts +4 -3
- package/src/scenarios/workflow-primary-output-annotation.test.ts +13 -23
- package/src/scenarios/workload-identity-behavior.test.ts +7 -4
- package/src/scenarios/workspace-cross-tenant-isolation-blackbox.test.ts +3 -2
- package/src/scenarios/workspace-cross-tenant-isolation.test.ts +3 -2
- package/src/setup.ts +95 -1
|
@@ -32,6 +32,7 @@
|
|
|
32
32
|
*/
|
|
33
33
|
|
|
34
34
|
import { describe, it, expect } from 'vitest';
|
|
35
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
35
36
|
import { driver, type OpenWOPResponse } from '../lib/driver.js';
|
|
36
37
|
import { subscribe } from '../lib/sse.js';
|
|
37
38
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
@@ -93,14 +94,14 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-text-fixture: messages-mode fold throug
|
|
|
93
94
|
'[stream-text-fixture] host does not advertise the stream-text mock provider ' +
|
|
94
95
|
'(Capabilities.testing.mockProviders); skipping',
|
|
95
96
|
);
|
|
96
|
-
return;
|
|
97
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isStreamTextMockAdvertised())` returned early');
|
|
97
98
|
}
|
|
98
99
|
|
|
99
100
|
const create = await createMockRun('stream-text');
|
|
100
101
|
if (create.status === 403 && errCode(create.json) === 'mock_provider_forbidden') {
|
|
101
102
|
// eslint-disable-next-line no-console
|
|
102
103
|
console.warn('[stream-text-fixture] API key is production-scoped (403 mock_provider_forbidden); skipping');
|
|
103
|
-
return;
|
|
104
|
+
return softSkip('inapplicable', '[stream-text-fixture] API key is production-scoped (403 mock_provider_forbidden); skipping');
|
|
104
105
|
}
|
|
105
106
|
expect(
|
|
106
107
|
create.status,
|
|
@@ -192,13 +193,13 @@ describe.skipIf(SKIP_NO_FIXTURE)('stream-text-fixture: messages-mode fold throug
|
|
|
192
193
|
if (!(await isStreamTextMockAdvertised())) {
|
|
193
194
|
// eslint-disable-next-line no-console
|
|
194
195
|
console.warn('[stream-text-fixture] stream-text mock not advertised; skipping negative leg');
|
|
195
|
-
return;
|
|
196
|
+
return softSkip('inapplicable', '[stream-text-fixture] stream-text mock not advertised; skipping negative leg');
|
|
196
197
|
}
|
|
197
198
|
const create = await createMockRun('does-not-exist');
|
|
198
199
|
if (create.status === 403 && errCode(create.json) === 'mock_provider_forbidden') {
|
|
199
200
|
// eslint-disable-next-line no-console
|
|
200
201
|
console.warn('[stream-text-fixture] API key is production-scoped; skipping negative leg');
|
|
201
|
-
return;
|
|
202
|
+
return softSkip('inapplicable', '[stream-text-fixture] API key is production-scoped; skipping negative leg');
|
|
202
203
|
}
|
|
203
204
|
expect(
|
|
204
205
|
create.status,
|
|
@@ -13,18 +13,19 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { describe, it, expect } from 'vitest';
|
|
16
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
16
17
|
import { driver } from '../lib/driver.js';
|
|
17
18
|
import { readSubRunAttestationCap, invokeSubRunAttest } from '../lib/subRunAttestation.js';
|
|
18
19
|
|
|
19
20
|
describe('subrun-approval-fail-closed (RFC 0063 §C)', () => {
|
|
20
21
|
it('no accept/edit-accept (terminated or expired) MUST NOT merge', async () => {
|
|
21
|
-
if ((await readSubRunAttestationCap()) !== true) return;
|
|
22
|
+
if ((await readSubRunAttestationCap()) !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `(await readSubRunAttestationCap()) !== true` returned early');
|
|
22
23
|
// approvalAction omitted models a run that terminated without a response.
|
|
23
24
|
const res = await invokeSubRunAttest({
|
|
24
25
|
childOutputs: { artifact: 'unverified' },
|
|
25
26
|
outputAttestation: { requireApproval: true },
|
|
26
27
|
});
|
|
27
|
-
if (res === null) return
|
|
28
|
+
if (res === null) return softSkip('blocked', 'seam absent — soft-skip');
|
|
28
29
|
expect(
|
|
29
30
|
res.merged,
|
|
30
31
|
driver.describe('RFC 0063 §C', 'an unresolved approval MUST fail closed — outputs MUST NOT be merged'),
|
|
@@ -10,23 +10,24 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { describe, it, expect } from 'vitest';
|
|
13
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
13
14
|
import { driver } from '../lib/driver.js';
|
|
14
15
|
import { readSubRunAttestationCap, invokeSubRunAttest } from '../lib/subRunAttestation.js';
|
|
15
16
|
|
|
16
17
|
describe('subrun-approval-gate (RFC 0063 §C)', () => {
|
|
17
18
|
it('accept merges the child outputs; reject does not', async () => {
|
|
18
|
-
if ((await readSubRunAttestationCap()) !== true) return;
|
|
19
|
+
if ((await readSubRunAttestationCap()) !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `(await readSubRunAttestationCap()) !== true` returned early');
|
|
19
20
|
const base = { childOutputs: { artifact: 'x' }, outputAttestation: { requireApproval: true } };
|
|
20
21
|
|
|
21
22
|
const accepted = await invokeSubRunAttest({ ...base, approvalAction: 'accept' });
|
|
22
|
-
if (accepted === null) return
|
|
23
|
+
if (accepted === null) return softSkip('blocked', 'seam absent — soft-skip');
|
|
23
24
|
expect(
|
|
24
25
|
accepted.merged,
|
|
25
26
|
driver.describe('RFC 0063 §C', 'an `accept` approval MUST merge the child outputs'),
|
|
26
27
|
).toBe(true);
|
|
27
28
|
|
|
28
29
|
const rejected = await invokeSubRunAttest({ ...base, approvalAction: 'reject' });
|
|
29
|
-
if (rejected === null) return;
|
|
30
|
+
if (rejected === null) return softSkip('blocked', 'precondition not met — `rejected === null` returned early (seam, prior step, or fixture unavailable)');
|
|
30
31
|
expect(
|
|
31
32
|
rejected.merged,
|
|
32
33
|
driver.describe('RFC 0063 §C', 'a `reject` approval MUST NOT merge the child outputs'),
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { describe, it, expect } from 'vitest';
|
|
14
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
14
15
|
import { driver } from '../lib/driver.js';
|
|
15
16
|
import { readSubRunAttestationCap } from '../lib/subRunAttestation.js';
|
|
16
17
|
|
|
@@ -18,7 +19,7 @@ describe('subrun-attestation-shape: advertisement (RFC 0063 §A)', () => {
|
|
|
18
19
|
it('capabilities.agents.subRunAttestation is absent or a boolean', async () => {
|
|
19
20
|
const cap = await readSubRunAttestationCap();
|
|
20
21
|
// null = unadvertised (no agents block OR flag omitted) — valid.
|
|
21
|
-
if (cap === null) return;
|
|
22
|
+
if (cap === null) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap === null` returned early');
|
|
22
23
|
expect(
|
|
23
24
|
typeof cap,
|
|
24
25
|
driver.describe(
|
|
@@ -11,21 +11,22 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { describe, it, expect } from 'vitest';
|
|
14
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
14
15
|
import { driver } from '../lib/driver.js';
|
|
15
16
|
import { readSubRunAttestationCap, invokeSubRunAttest } from '../lib/subRunAttestation.js';
|
|
16
17
|
|
|
17
18
|
describe('subrun-checksum-stable (RFC 0063 §B)', () => {
|
|
18
19
|
it('identical child outputs produce an identical sha256 attestation checksum', async () => {
|
|
19
|
-
if ((await readSubRunAttestationCap()) !== true) return;
|
|
20
|
+
if ((await readSubRunAttestationCap()) !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `(await readSubRunAttestationCap()) !== true` returned early');
|
|
20
21
|
const childOutputs = { report: 'done', score: 0.9, tags: ['a', 'b'] };
|
|
21
22
|
const a = await invokeSubRunAttest({ childOutputs, outputAttestation: { checksum: true } });
|
|
22
|
-
if (a === null) return
|
|
23
|
+
if (a === null) return softSkip('blocked', 'seam absent — soft-skip');
|
|
23
24
|
// Key-reordered but value-identical: JCS canonicalization MUST yield the same hash.
|
|
24
25
|
const b = await invokeSubRunAttest({
|
|
25
26
|
childOutputs: { tags: ['a', 'b'], score: 0.9, report: 'done' },
|
|
26
27
|
outputAttestation: { checksum: true },
|
|
27
28
|
});
|
|
28
|
-
if (b === null) return;
|
|
29
|
+
if (b === null) return softSkip('blocked', 'precondition not met — `b === null` returned early (seam, prior step, or fixture unavailable)');
|
|
29
30
|
const att = a.attestation ?? {};
|
|
30
31
|
expect(
|
|
31
32
|
typeof att.checksum === 'string' && (att.checksum as string).length > 0,
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { describe, it, expect } from 'vitest';
|
|
17
|
+
import { readErrorCode } from '../lib/error-envelope.js';
|
|
17
18
|
import { driver } from '../lib/driver.js';
|
|
18
19
|
|
|
19
20
|
interface DiscoveryDoc {
|
|
@@ -74,8 +75,7 @@ describe('table-schema-enforcement: behavioral (RFC 0016 §B point 2)', () => {
|
|
|
74
75
|
bad.status >= 400 && bad.status < 500,
|
|
75
76
|
driver.describe('RFC 0016 §B point 2', 'type-divergent insert MUST be rejected with 4xx'),
|
|
76
77
|
).toBe(true);
|
|
77
|
-
const
|
|
78
|
-
const code = typeof body.error === 'string' ? body.error : body.error?.code;
|
|
78
|
+
const code = readErrorCode(bad.json);
|
|
79
79
|
expect(
|
|
80
80
|
code,
|
|
81
81
|
driver.describe('RFC 0016 §B point 2', 'rejection MUST carry the table_schema_violation error code'),
|
|
@@ -12,13 +12,14 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { describe, it, expect } from 'vitest';
|
|
15
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
15
16
|
import { driver } from '../lib/driver.js';
|
|
16
17
|
import { readToolHooksCap, invokeToolHook } from '../lib/toolHooks.js';
|
|
17
18
|
|
|
18
19
|
describe('tool-hooks-authorization-fail-closed (RFC 0064 §C)', () => {
|
|
19
20
|
it('a principal lacking a tool scope is denied and the tool is not invoked', async () => {
|
|
20
21
|
const cap = await readToolHooksCap();
|
|
21
|
-
if (cap?.perToolAuthorization !== true) return;
|
|
22
|
+
if (cap?.perToolAuthorization !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap?.perToolAuthorization !== true` returned early');
|
|
22
23
|
// A principal with no scopes against a tool requiring one MUST be denied.
|
|
23
24
|
const res = await invokeToolHook({
|
|
24
25
|
principal: 'conformance-unprivileged',
|
|
@@ -26,7 +27,7 @@ describe('tool-hooks-authorization-fail-closed (RFC 0064 §C)', () => {
|
|
|
26
27
|
requiredScopes: ['db:write'],
|
|
27
28
|
args: {},
|
|
28
29
|
});
|
|
29
|
-
if (res === null) return
|
|
30
|
+
if (res === null) return softSkip('blocked', 'seam absent — soft-skip');
|
|
30
31
|
expect(
|
|
31
32
|
(res.toolReturned ?? {}).status,
|
|
32
33
|
driver.describe('RFC 0064 §C', 'a missing/unevaluable tool scope MUST fail closed → status:"forbidden"'),
|
|
@@ -11,15 +11,16 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { describe, it, expect } from 'vitest';
|
|
14
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
14
15
|
import { driver } from '../lib/driver.js';
|
|
15
16
|
import { readToolHooksCap, invokeToolHook } from '../lib/toolHooks.js';
|
|
16
17
|
|
|
17
18
|
describe('tool-hooks-content-free (RFC 0064 §B)', () => {
|
|
18
19
|
it('toolCalled carries argsHash; toolReturned carries status + durationMs', async () => {
|
|
19
20
|
const cap = await readToolHooksCap();
|
|
20
|
-
if (cap?.prePostEvents !== true) return;
|
|
21
|
+
if (cap?.prePostEvents !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap?.prePostEvents !== true` returned early');
|
|
21
22
|
const res = await invokeToolHook({ principal: 'core.system', toolName: 'web.search', args: { q: 'openwop' } });
|
|
22
|
-
if (res === null) return
|
|
23
|
+
if (res === null) return softSkip('blocked', 'seam absent — soft-skip');
|
|
23
24
|
const called = res.toolCalled ?? {};
|
|
24
25
|
const returned = res.toolReturned ?? {};
|
|
25
26
|
expect(
|
|
@@ -10,20 +10,21 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { describe, it, expect } from 'vitest';
|
|
13
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
13
14
|
import { driver } from '../lib/driver.js';
|
|
14
15
|
import { readToolHooksCap, invokeToolHook } from '../lib/toolHooks.js';
|
|
15
16
|
|
|
16
17
|
describe('tool-hooks-rate-limit (RFC 0064 §D)', () => {
|
|
17
18
|
it('an exhausted (principal, tool) bucket yields status:"rate_limited"', async () => {
|
|
18
19
|
const cap = await readToolHooksCap();
|
|
19
|
-
if (cap?.perToolRateLimit !== true) return;
|
|
20
|
+
if (cap?.perToolRateLimit !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap?.perToolRateLimit !== true` returned early');
|
|
20
21
|
const res = await invokeToolHook({
|
|
21
22
|
principal: 'core.system',
|
|
22
23
|
toolName: 'web.search',
|
|
23
24
|
args: { q: 'x' },
|
|
24
25
|
simulateRateLimitExhausted: true,
|
|
25
26
|
});
|
|
26
|
-
if (res === null) return
|
|
27
|
+
if (res === null) return softSkip('blocked', 'seam absent — soft-skip');
|
|
27
28
|
expect(
|
|
28
29
|
(res.toolReturned ?? {}).status,
|
|
29
30
|
driver.describe('RFC 0064 §D', 'an exhausted token bucket MUST yield status:"rate_limited" without invoking the tool'),
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { describe, it, expect } from 'vitest';
|
|
14
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
14
15
|
import { driver } from '../lib/driver.js';
|
|
15
16
|
import { readToolHooksCap, invokeToolHook } from '../lib/toolHooks.js';
|
|
16
17
|
|
|
@@ -19,13 +20,13 @@ const CANARY = 'sk-canary-rfc0064-do-not-leak-xyz789';
|
|
|
19
20
|
describe('tool-hooks-secret-redaction (RFC 0064 §E)', () => {
|
|
20
21
|
it('a secret-shaped tool arg never appears in the emitted events', async () => {
|
|
21
22
|
const cap = await readToolHooksCap();
|
|
22
|
-
if (cap?.prePostEvents !== true) return;
|
|
23
|
+
if (cap?.prePostEvents !== true) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `cap?.prePostEvents !== true` returned early');
|
|
23
24
|
const res = await invokeToolHook({
|
|
24
25
|
principal: 'core.system',
|
|
25
26
|
toolName: 'web.search',
|
|
26
27
|
args: { apiKey: CANARY, q: 'openwop' },
|
|
27
28
|
});
|
|
28
|
-
if (res === null) return
|
|
29
|
+
if (res === null) return softSkip('blocked', 'seam absent — soft-skip');
|
|
29
30
|
expect(
|
|
30
31
|
JSON.stringify(res).includes(CANARY),
|
|
31
32
|
driver.describe('RFC 0064 §B', 'a resolved secret MUST be redacted before hashing; the raw value MUST NOT appear in argsHash or any emitted field (SR-1)'),
|
|
@@ -11,13 +11,14 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { describe, it, expect } from 'vitest';
|
|
14
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
14
15
|
import { driver } from '../lib/driver.js';
|
|
15
16
|
import { readToolHooksCap } from '../lib/toolHooks.js';
|
|
16
17
|
|
|
17
18
|
describe('tool-hooks-shape: advertisement (RFC 0064 §A)', () => {
|
|
18
19
|
it('capabilities.toolHooks is absent or a well-formed object', async () => {
|
|
19
20
|
const cap = await readToolHooksCap();
|
|
20
|
-
if (cap === null) return
|
|
21
|
+
if (cap === null) return softSkip('inapplicable', 'not advertised — valid');
|
|
21
22
|
expect(
|
|
22
23
|
typeof cap.supported,
|
|
23
24
|
driver.describe('capabilities.schema.json §toolHooks', 'toolHooks.supported MUST be a boolean when the block is present'),
|
|
@@ -28,6 +28,7 @@
|
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
30
|
import { describe, it, expect } from 'vitest';
|
|
31
|
+
import { seamAbsent } from '../lib/soft-skip.js';
|
|
31
32
|
import { driver } from '../lib/driver.js';
|
|
32
33
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
33
34
|
import {
|
|
@@ -52,11 +53,11 @@ function expectContentFree(payload: Record<string, unknown>, where: string): voi
|
|
|
52
53
|
describe('trigger-bridge-delivery (RFC 0083 §C)', () => {
|
|
53
54
|
it('de-dups by dedupKey, retries to dead-letter, and links delivery→run causation', async () => {
|
|
54
55
|
if (!behaviorGate('openwop-trigger-bridge', await isTriggerBridgeProfileAdvertised())) return;
|
|
55
|
-
if (!(await isEventLogSeamAvailable())) return
|
|
56
|
+
if (!(await isEventLogSeamAvailable())) return seamAbsent('host advertises openwop-trigger-bridge but the event-log seam is absent');
|
|
56
57
|
|
|
57
58
|
// ---- Leg 1: dedup → effectively-once (§C-1) ---------------------------
|
|
58
59
|
const dedup = await driveDelivery({ scenario: 'dedup', dedupKey: 'conformance-dedup-key', source: 'queue' });
|
|
59
|
-
if (dedup === null) return
|
|
60
|
+
if (dedup === null) return seamAbsent('host advertises openwop-trigger-bridge but the delivery seam is unwired');
|
|
60
61
|
|
|
61
62
|
// The profile is derived AND the seam is wired — missing evidence is a
|
|
62
63
|
// FAILURE, not a soft-skip. A repeated dedupKey MUST be effectively-once:
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
36
|
import { describe, it, expect } from 'vitest';
|
|
37
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
37
38
|
import { driver, type OpenWOPResponse } from '../lib/driver.js';
|
|
38
39
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
39
40
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
@@ -84,7 +85,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
84
85
|
'[version-fold] host does not advertise Capabilities.testing.forceEngineVersionRange; ' +
|
|
85
86
|
'skipping (the X-Force-Engine-Version seam is test-keys-only and optional)',
|
|
86
87
|
);
|
|
87
|
-
return;
|
|
88
|
+
return softSkip('blocked', 'precondition not met — `seam === null` returned early (seam, prior step, or fixture unavailable)');
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
const candidates = [seam.range.min, ...(seam.current === null ? [] : [seam.current]), seam.range.max];
|
|
@@ -104,7 +105,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
104
105
|
if (create.status === 403 && errCode(create.json) === 'force_engine_version_forbidden') {
|
|
105
106
|
// eslint-disable-next-line no-console
|
|
106
107
|
console.warn('[version-fold] API key is production-scoped (403 force_engine_version_forbidden); skipping');
|
|
107
|
-
return;
|
|
108
|
+
return softSkip('blocked', '[version-fold] API key is production-scoped (403 force_engine_version_forbidden); skipping (create.status === 403 && errCode(create.json) === \'force_engine_version_forbidden\')');
|
|
108
109
|
}
|
|
109
110
|
expect(
|
|
110
111
|
create.status,
|
|
@@ -165,7 +166,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
165
166
|
if (seam === null) {
|
|
166
167
|
// eslint-disable-next-line no-console
|
|
167
168
|
console.warn('[version-fold] forceEngineVersionRange not advertised; skipping negative leg');
|
|
168
|
-
return;
|
|
169
|
+
return softSkip('inapplicable', '[version-fold] forceEngineVersionRange not advertised; skipping negative leg');
|
|
169
170
|
}
|
|
170
171
|
|
|
171
172
|
const outOfRange = seam.range.max + 1;
|
|
@@ -173,7 +174,7 @@ describe.skipIf(SKIP_NO_FIXTURE)('version-fold: forced engine versions fold-best
|
|
|
173
174
|
if (create.status === 403 && errCode(create.json) === 'force_engine_version_forbidden') {
|
|
174
175
|
// eslint-disable-next-line no-console
|
|
175
176
|
console.warn('[version-fold] API key is production-scoped; skipping negative leg');
|
|
176
|
-
return;
|
|
177
|
+
return softSkip('blocked', '[version-fold] API key is production-scoped; skipping negative leg (create.status === 403 && errCode(create.json) === \'force_engine_version_forbidden\')');
|
|
177
178
|
}
|
|
178
179
|
expect(
|
|
179
180
|
create.status,
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import { describe, it, expect } from 'vitest';
|
|
21
|
+
import { readErrorCode } from '../lib/error-envelope.js';
|
|
21
22
|
import { driver } from '../lib/driver.js';
|
|
22
23
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
23
24
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
@@ -29,7 +30,7 @@ function realtimeVoiceOf(ai: Record<string, unknown> | undefined): Record<string
|
|
|
29
30
|
return rv && typeof rv === 'object' ? (rv as Record<string, unknown>) : undefined;
|
|
30
31
|
}
|
|
31
32
|
function errCode(json: unknown): string | undefined {
|
|
32
|
-
return (json
|
|
33
|
+
return readErrorCode(json);
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
describe('voice-streamref-tenant-bound (RFC 0106 §F INV-4)', () => {
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import { describe, it, expect } from 'vitest';
|
|
22
|
+
import { readErrorCode } from '../lib/error-envelope.js';
|
|
22
23
|
import { driver } from '../lib/driver.js';
|
|
23
24
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
24
25
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
@@ -30,7 +31,7 @@ function realtimeVoiceOf(ai: Record<string, unknown> | undefined): Record<string
|
|
|
30
31
|
return rv && typeof rv === 'object' ? (rv as Record<string, unknown>) : undefined;
|
|
31
32
|
}
|
|
32
33
|
function errCode(json: unknown): string | undefined {
|
|
33
|
-
return (json
|
|
34
|
+
return readErrorCode(json);
|
|
34
35
|
}
|
|
35
36
|
function eventsOf(json: unknown): Array<{ type?: string; payload?: Record<string, unknown> }> {
|
|
36
37
|
const e = (json as { events?: unknown })?.events;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import { describe, it, expect } from 'vitest';
|
|
17
|
+
import { readErrorCode } from '../lib/error-envelope.js';
|
|
17
18
|
import { driver } from '../lib/driver.js';
|
|
18
19
|
import { behaviorGate } from '../lib/behavior-gate.js';
|
|
19
20
|
import { readCapabilityFamily } from '../lib/discovery-capabilities.js';
|
|
@@ -25,7 +26,7 @@ function realtimeVoiceOf(ai: Record<string, unknown> | undefined): Record<string
|
|
|
25
26
|
return rv && typeof rv === 'object' ? (rv as Record<string, unknown>) : undefined;
|
|
26
27
|
}
|
|
27
28
|
function errCode(json: unknown): string | undefined {
|
|
28
|
-
return (json
|
|
29
|
+
return readErrorCode(json);
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
describe('voice-transcription-unadvertised (RFC 0106 §B)', () => {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
import { describe, it, expect } from 'vitest';
|
|
28
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
28
29
|
import { driver } from '../lib/driver.js';
|
|
29
30
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
30
31
|
|
|
@@ -37,7 +38,7 @@ describe('wasm-pack-abi-version-rejection: host advertises supported ABI version
|
|
|
37
38
|
const wasm =
|
|
38
39
|
capabilityFamily<{ wasm?: Record<string, unknown> }>(disco.json, 'nodePackRuntimes')?.wasm;
|
|
39
40
|
|
|
40
|
-
if (!wasm?.supported) return;
|
|
41
|
+
if (!wasm?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!wasm?.supported` returned early');
|
|
41
42
|
|
|
42
43
|
expect(Array.isArray(wasm.abiVersions), driver.describe(
|
|
43
44
|
'RFCS/0008-wasm-abi.md §H',
|
|
@@ -63,7 +64,7 @@ describe('wasm-pack-abi-version-rejection: positive path via misbehaving pack',
|
|
|
63
64
|
const wasm =
|
|
64
65
|
capabilityFamily<{ wasm?: Record<string, unknown> }>(disco.json, 'nodePackRuntimes')?.wasm;
|
|
65
66
|
|
|
66
|
-
if (!wasm?.supported) return;
|
|
67
|
+
if (!wasm?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!wasm?.supported` returned early');
|
|
67
68
|
|
|
68
69
|
if (!Array.isArray(wasm.loadedPacks)) {
|
|
69
70
|
// eslint-disable-next-line no-console
|
|
@@ -71,7 +72,7 @@ describe('wasm-pack-abi-version-rejection: positive path via misbehaving pack',
|
|
|
71
72
|
'[wasm-pack-abi-version-rejection] host does not advertise capabilities.nodePackRuntimes.wasm.loadedPacks[]; skipping positive path. ' +
|
|
72
73
|
'Hosts MAY advertise loadedPacks[] to surface ABI rejection observably (RFC 0008 §H + Track 7).',
|
|
73
74
|
);
|
|
74
|
-
return;
|
|
75
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!Array.isArray(wasm.loadedPacks)` returned early');
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
// Soft-skip when the well-behaved reference pack isn't loaded. If
|
|
@@ -84,7 +85,7 @@ describe('wasm-pack-abi-version-rejection: positive path via misbehaving pack',
|
|
|
84
85
|
`[wasm-pack-abi-version-rejection] reference pack ${WELL_BEHAVED_PACK_NAME} not in loadedPacks[]; ` +
|
|
85
86
|
'skipping positive path (build examples/packs/rust-hello first or run against a host that ships it).',
|
|
86
87
|
);
|
|
87
|
-
return;
|
|
88
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!wasm.loadedPacks.includes(WELL_BEHAVED_PACK_NAME)` returned early');
|
|
88
89
|
}
|
|
89
90
|
|
|
90
91
|
// Core assertion: ABI 999 pack MUST NOT be in loadedPacks[]
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { describe, it, expect } from 'vitest';
|
|
16
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
16
17
|
import { driver } from '../lib/driver.js';
|
|
17
18
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
18
19
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
@@ -29,11 +30,11 @@ async function isWasmSupported(): Promise<boolean> {
|
|
|
29
30
|
|
|
30
31
|
describe('wasm-pack-invoke-completed: round-trip output', () => {
|
|
31
32
|
it('greet node returns Hello, <name>! and run reaches completed', async () => {
|
|
32
|
-
if (!isFixtureAdvertised(FIXTURE)) return;
|
|
33
|
+
if (!isFixtureAdvertised(FIXTURE)) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(FIXTURE)` returned early');
|
|
33
34
|
if (!(await isWasmSupported())) {
|
|
34
35
|
// eslint-disable-next-line no-console
|
|
35
36
|
console.warn('[wasm-pack-invoke-completed] WASM not advertised; skipping');
|
|
36
|
-
return;
|
|
37
|
+
return softSkip('inapplicable', '[wasm-pack-invoke-completed] WASM not advertised; skipping');
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
const create = await driver.post('/v1/runs', {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { describe, it, expect } from 'vitest';
|
|
20
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
20
21
|
import { driver } from '../lib/driver.js';
|
|
21
22
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
22
23
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
@@ -33,8 +34,8 @@ async function isWasmSupported(): Promise<boolean> {
|
|
|
33
34
|
|
|
34
35
|
describe('wasm-pack-invoke-suspended: suspend → resume round-trip', () => {
|
|
35
36
|
it('host either suspends the run or explicitly reports wasm_suspend_not_implemented', async () => {
|
|
36
|
-
if (!isFixtureAdvertised(FIXTURE)) return;
|
|
37
|
-
if (!(await isWasmSupported())) return;
|
|
37
|
+
if (!isFixtureAdvertised(FIXTURE)) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(FIXTURE)` returned early');
|
|
38
|
+
if (!(await isWasmSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isWasmSupported())` returned early');
|
|
38
39
|
|
|
39
40
|
// The reference rust-hello pack does NOT itself suspend (it always
|
|
40
41
|
// returns `completed`), so against that pack this scenario can only
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { describe, it, expect } from 'vitest';
|
|
16
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
16
17
|
import { driver } from '../lib/driver.js';
|
|
17
18
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
18
19
|
import { capabilityFamily } from '../lib/discovery-capabilities.js';
|
|
@@ -39,7 +40,7 @@ describe('wasm-pack-load: discovery surfaces WASM runtime support', () => {
|
|
|
39
40
|
if (!wasm?.supported) {
|
|
40
41
|
// eslint-disable-next-line no-console
|
|
41
42
|
console.warn('[wasm-pack-load] host does not advertise WASM support; skipping');
|
|
42
|
-
return;
|
|
43
|
+
return softSkip('inapplicable', '[wasm-pack-load] host does not advertise WASM support; skipping');
|
|
43
44
|
}
|
|
44
45
|
expect(Array.isArray(wasm.abiVersions), driver.describe(
|
|
45
46
|
'RFCS/0008-wasm-abi.md §H',
|
|
@@ -55,11 +56,11 @@ describe('wasm-pack-load: discovery surfaces WASM runtime support', () => {
|
|
|
55
56
|
describe('wasm-pack-load: loaded pack typeIds are dispatchable', () => {
|
|
56
57
|
it('host accepts a workflow whose node typeId is provided by a loaded WASM pack', async () => {
|
|
57
58
|
const wasm = await getWasmCaps();
|
|
58
|
-
if (!wasm?.supported) return;
|
|
59
|
+
if (!wasm?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!wasm?.supported` returned early');
|
|
59
60
|
if (!isFixtureAdvertised(FIXTURE)) {
|
|
60
61
|
// eslint-disable-next-line no-console
|
|
61
62
|
console.warn(`[wasm-pack-load] fixture ${FIXTURE} not advertised; skipping`);
|
|
62
|
-
return;
|
|
63
|
+
return softSkip('inapplicable', '[wasm-pack-load] fixture … not advertised; skipping');
|
|
63
64
|
}
|
|
64
65
|
// Creating a run against the fixture proves the host knows about the
|
|
65
66
|
// WASM-provided typeId. A host that loaded the pack accepts the
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import { describe, it, expect } from 'vitest';
|
|
26
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
26
27
|
import { driver } from '../lib/driver.js';
|
|
27
28
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
28
29
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
@@ -36,7 +37,7 @@ describe('wasm-pack-memory-cap: host advertises maxMemoryBytes', () => {
|
|
|
36
37
|
const wasm =
|
|
37
38
|
capabilityFamily<{ wasm?: Record<string, unknown> }>(disco.json, 'nodePackRuntimes')?.wasm;
|
|
38
39
|
|
|
39
|
-
if (!wasm?.supported) return;
|
|
40
|
+
if (!wasm?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!wasm?.supported` returned early');
|
|
40
41
|
|
|
41
42
|
// The cap is REQUIRED to enforce §K. Hosts MUST surface the configured
|
|
42
43
|
// ceiling so clients can size their packs accordingly.
|
|
@@ -59,12 +60,12 @@ describe('wasm-pack-memory-cap: positive path via misbehaving pack', () => {
|
|
|
59
60
|
`[wasm-pack-memory-cap] fixture ${CAP_BREACH_FIXTURE} not advertised; skipping positive path. ` +
|
|
60
61
|
'Build the misbehaving pack at examples/packs/rust-misbehaving-memory/ and ensure the host serves the fixture.',
|
|
61
62
|
);
|
|
62
|
-
return;
|
|
63
|
+
return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(CAP_BREACH_FIXTURE)` returned early');
|
|
63
64
|
}
|
|
64
65
|
const disco = await driver.get('/.well-known/openwop');
|
|
65
66
|
const wasm =
|
|
66
67
|
capabilityFamily<{ wasm?: Record<string, unknown> }>(disco.json, 'nodePackRuntimes')?.wasm;
|
|
67
|
-
if (!wasm?.supported) return;
|
|
68
|
+
if (!wasm?.supported) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!wasm?.supported` returned early');
|
|
68
69
|
|
|
69
70
|
const create = await driver.post('/v1/runs', {
|
|
70
71
|
workflowId: CAP_BREACH_FIXTURE,
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { describe, it, expect } from 'vitest';
|
|
14
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
14
15
|
import { driver } from '../lib/driver.js';
|
|
15
16
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
16
17
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
@@ -33,8 +34,8 @@ function extractGreeting(events: Array<{ type: string; data?: unknown }>): strin
|
|
|
33
34
|
|
|
34
35
|
describe('wasm-pack-replay-determinism: same inputs → same output', () => {
|
|
35
36
|
it('two independent runs with same inputs produce same WASM output', async () => {
|
|
36
|
-
if (!isFixtureAdvertised(FIXTURE)) return;
|
|
37
|
-
if (!(await isWasmSupported())) return;
|
|
37
|
+
if (!isFixtureAdvertised(FIXTURE)) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!isFixtureAdvertised(FIXTURE)` returned early');
|
|
38
|
+
if (!(await isWasmSupported())) return softSkip('inapplicable', 'capability or profile not advertised by this host — gate `!(await isWasmSupported())` returned early');
|
|
38
39
|
|
|
39
40
|
const inputs = { name: 'determinism-probe' };
|
|
40
41
|
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
27
|
+
import { softSkip } from '../lib/soft-skip.js';
|
|
27
28
|
import { createHmac } from 'node:crypto';
|
|
28
29
|
import { createServer, type IncomingMessage, type Server, type ServerResponse } from 'node:http';
|
|
29
30
|
import { driver } from '../lib/driver.js';
|
|
@@ -78,12 +79,12 @@ describe('webhook-signed-delivery: end-to-end HMAC v1', () => {
|
|
|
78
79
|
if (!(await isWebhookSupported())) {
|
|
79
80
|
// eslint-disable-next-line no-console
|
|
80
81
|
console.warn('[webhook-signed-delivery] host does not advertise webhook support; skipping');
|
|
81
|
-
return;
|
|
82
|
+
return softSkip('inapplicable', '[webhook-signed-delivery] host does not advertise webhook support; skipping');
|
|
82
83
|
}
|
|
83
84
|
if (!isFixtureAdvertised('conformance-noop')) {
|
|
84
85
|
// eslint-disable-next-line no-console
|
|
85
86
|
console.warn('[webhook-signed-delivery] conformance-noop not advertised; skipping');
|
|
86
|
-
return;
|
|
87
|
+
return softSkip('inapplicable', '[webhook-signed-delivery] conformance-noop not advertised; skipping');
|
|
87
88
|
}
|
|
88
89
|
|
|
89
90
|
const receiver = await startReceiver();
|
|
@@ -114,7 +115,7 @@ describe('webhook-signed-delivery: end-to-end HMAC v1', () => {
|
|
|
114
115
|
'[webhook-signed-delivery] host SSRF guard rejected the loopback receiver; ' +
|
|
115
116
|
'set OPENWOP_WEBHOOK_ALLOW_PRIVATE=true on the host (or equivalent) to run',
|
|
116
117
|
);
|
|
117
|
-
return;
|
|
118
|
+
return softSkip('blocked', 'precondition not met — `body.error === \'webhook_url_rejected\'` returned early (seam, prior step, or fixture unavailable)');
|
|
118
119
|
}
|
|
119
120
|
}
|
|
120
121
|
|