@openwop/openwop-conformance 2.4.0 → 2.4.2
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
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# `@openwop/openwop-conformance` Changelog
|
|
2
2
|
|
|
3
|
+
## [2.4.2] — 2026-09-18 — an id no host could ever witness
|
|
4
|
+
|
|
5
|
+
**Why a patch.** One assertion moves into its own `it`; no scenario file is
|
|
6
|
+
added or removed and no host obligation changes.
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- **`openwop.requirement.0173.pack-isolation.seam`** was minted inside
|
|
11
|
+
`v2-pack-isolation`'s shared `invoke()` helper.
|
|
12
|
+
`generate-requirement-registry.mjs` harvests `req(…)` only within an `it`, so
|
|
13
|
+
the id never reached `requirements.json` and no bundle could carry a row for
|
|
14
|
+
it — while `check-cut-gates.mjs` scans every `req(` in the source and went on
|
|
15
|
+
demanding one, failing RFC 0167 §G.2 on a row no host could supply. The seam
|
|
16
|
+
contract now has its own `it`, which is the copy the registry can see. The
|
|
17
|
+
helper keeps its `req(…)` call — RFC 0168 §A.1 makes `req(…)` the only
|
|
18
|
+
assertion-message form in `src/scenarios`, so the fix is the extra `it`, not
|
|
19
|
+
a quieter assertion.
|
|
20
|
+
|
|
21
|
+
## [2.4.1] — 2026-09-18 — the leg that reads the host, not the schema
|
|
22
|
+
|
|
23
|
+
**Why a patch.** A leg is added to an existing scenario file; no file is added or removed.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **`v2-chain-pin-exact`** gains a third leg: an EXTERNAL `subChainRef` carrying
|
|
28
|
+
`version: "^1.0.0"`. The existing legs are satisfied by schema validation
|
|
29
|
+
alone (sabotage-proved: delete the reference host's pin rule and both stay
|
|
30
|
+
green); `SubChainRef.ref` types the external `version` as a semver range, so
|
|
31
|
+
this leg is the only one that reads the host's rule.
|
|
32
|
+
|
|
3
33
|
## [2.4.0] — 2026-09-18 — every bound kind, not just runId
|
|
4
34
|
|
|
5
35
|
**Why a minor.** One scenario file is added (`PROTOCOL-STATUS.md` §suite version).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@openwop/openwop-conformance",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "Production-ready black-box conformance suite for OpenWOP v1.0 compliant servers.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"@openwop/spec-artifacts": "file:../spec-artifacts"
|
|
57
57
|
},
|
|
58
58
|
"peerDependencies": {
|
|
59
|
-
"@openwop/spec-artifacts": "2.4.
|
|
59
|
+
"@openwop/spec-artifacts": "2.4.2"
|
|
60
60
|
}
|
|
61
61
|
}
|
package/requirements.json
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
"generatedFrom": "src/scenarios/*.test.ts",
|
|
4
4
|
"counts": {
|
|
5
5
|
"files": 571,
|
|
6
|
-
"tests":
|
|
7
|
-
"withStableId":
|
|
6
|
+
"tests": 2174,
|
|
7
|
+
"withStableId": 2174,
|
|
8
8
|
"interpolatedTitles": 0,
|
|
9
|
-
"explicitIds":
|
|
9
|
+
"explicitIds": 2127
|
|
10
10
|
},
|
|
11
11
|
"records": [
|
|
12
12
|
{
|
|
@@ -26310,7 +26310,7 @@
|
|
|
26310
26310
|
{
|
|
26311
26311
|
"id": "openwop.it.v2-chain-pin-exact.a-chain-reference-carrying-a-range-core-ai-callprompt-1-is-refused-at-register",
|
|
26312
26312
|
"file": "v2-chain-pin-exact.test.ts",
|
|
26313
|
-
"line":
|
|
26313
|
+
"line": 116,
|
|
26314
26314
|
"title": "a chain reference carrying a range (core.ai.callPrompt@^1) is refused at register",
|
|
26315
26315
|
"explicitId": "openwop.requirement.0177.chain-pin-exact.range-refused",
|
|
26316
26316
|
"citations": [
|
|
@@ -26325,10 +26325,28 @@
|
|
|
26325
26325
|
}
|
|
26326
26326
|
]
|
|
26327
26327
|
},
|
|
26328
|
+
{
|
|
26329
|
+
"id": "openwop.it.v2-chain-pin-exact.an-external-sub-chain-reference-carrying-a-range-is-refused-the-one-pin-the-sche",
|
|
26330
|
+
"file": "v2-chain-pin-exact.test.ts",
|
|
26331
|
+
"line": 125,
|
|
26332
|
+
"title": "an EXTERNAL sub-chain reference carrying a range is refused — the one pin the schema cannot catch",
|
|
26333
|
+
"explicitId": "openwop.requirement.0177.chain-pin-exact.external-range-refused",
|
|
26334
|
+
"citations": [
|
|
26335
|
+
{
|
|
26336
|
+
"section": "workflow-chain-packs.md §\"Exact pins\" (RFC 0177 §E.1)",
|
|
26337
|
+
"requirement": null,
|
|
26338
|
+
"interpolated": true
|
|
26339
|
+
},
|
|
26340
|
+
{
|
|
26341
|
+
"section": "workflow-chain-packs.md §\"Exact pins\" (RFC 0177 §E.1)",
|
|
26342
|
+
"requirement": "the refusal MUST carry an error code in the canonical envelope"
|
|
26343
|
+
}
|
|
26344
|
+
]
|
|
26345
|
+
},
|
|
26328
26346
|
{
|
|
26329
26347
|
"id": "openwop.it.v2-chain-pin-exact.a-chain-reference-pinning-an-exact-version-core-ai-callprompt-1-0-0-registers",
|
|
26330
26348
|
"file": "v2-chain-pin-exact.test.ts",
|
|
26331
|
-
"line":
|
|
26349
|
+
"line": 140,
|
|
26332
26350
|
"title": "a chain reference pinning an exact version (core.ai.callPrompt@1.0.0) registers",
|
|
26333
26351
|
"explicitId": "openwop.requirement.0177.chain-pin-exact.exact-accepted",
|
|
26334
26352
|
"citations": [
|
|
@@ -27663,7 +27681,7 @@
|
|
|
27663
27681
|
{
|
|
27664
27682
|
"id": "openwop.it.v2-pack-isolation.sandbox-isolationmodel-names-a-real-mechanism-never-node-vm",
|
|
27665
27683
|
"file": "v2-pack-isolation.test.ts",
|
|
27666
|
-
"line":
|
|
27684
|
+
"line": 78,
|
|
27667
27685
|
"title": "sandbox.isolationModel names a real mechanism, never node:vm",
|
|
27668
27686
|
"explicitId": "openwop.requirement.0173.pack-isolation",
|
|
27669
27687
|
"citations": [
|
|
@@ -27678,10 +27696,24 @@
|
|
|
27678
27696
|
}
|
|
27679
27697
|
]
|
|
27680
27698
|
},
|
|
27699
|
+
{
|
|
27700
|
+
"id": "openwop.it.v2-pack-isolation.the-sandbox-invoke-seam-answers-the-seam-contract",
|
|
27701
|
+
"file": "v2-pack-isolation.test.ts",
|
|
27702
|
+
"line": 92,
|
|
27703
|
+
"title": "the sandbox-invoke seam answers the seam contract",
|
|
27704
|
+
"explicitId": "openwop.requirement.0173.pack-isolation.seam",
|
|
27705
|
+
"citations": [
|
|
27706
|
+
{
|
|
27707
|
+
"section": "host-sample-test-seams.md §8",
|
|
27708
|
+
"requirement": null,
|
|
27709
|
+
"interpolated": true
|
|
27710
|
+
}
|
|
27711
|
+
]
|
|
27712
|
+
},
|
|
27681
27713
|
{
|
|
27682
27714
|
"id": "openwop.it.v2-pack-isolation.node-pack-sandbox-fs-gated-a-host-filesystem-read-is-refused",
|
|
27683
27715
|
"file": "v2-pack-isolation.test.ts",
|
|
27684
|
-
"line":
|
|
27716
|
+
"line": 104,
|
|
27685
27717
|
"title": "node-pack-sandbox-fs-gated: a host filesystem read is refused",
|
|
27686
27718
|
"explicitId": null,
|
|
27687
27719
|
"citations": []
|
|
@@ -27689,7 +27721,7 @@
|
|
|
27689
27721
|
{
|
|
27690
27722
|
"id": "openwop.it.v2-pack-isolation.node-pack-sandbox-fs-gated-a-host-filesystem-write-is-refused",
|
|
27691
27723
|
"file": "v2-pack-isolation.test.ts",
|
|
27692
|
-
"line":
|
|
27724
|
+
"line": 111,
|
|
27693
27725
|
"title": "node-pack-sandbox-fs-gated: a host filesystem write is refused",
|
|
27694
27726
|
"explicitId": null,
|
|
27695
27727
|
"citations": []
|
|
@@ -27697,7 +27729,7 @@
|
|
|
27697
27729
|
{
|
|
27698
27730
|
"id": "openwop.it.v2-pack-isolation.node-pack-sandbox-no-env-the-host-environment-does-not-leak",
|
|
27699
27731
|
"file": "v2-pack-isolation.test.ts",
|
|
27700
|
-
"line":
|
|
27732
|
+
"line": 118,
|
|
27701
27733
|
"title": "node-pack-sandbox-no-env: the host environment does not leak",
|
|
27702
27734
|
"explicitId": null,
|
|
27703
27735
|
"citations": []
|
|
@@ -27705,7 +27737,7 @@
|
|
|
27705
27737
|
{
|
|
27706
27738
|
"id": "openwop.it.v2-pack-isolation.node-pack-sandbox-network-gated-ungated-network-egress-is-refused",
|
|
27707
27739
|
"file": "v2-pack-isolation.test.ts",
|
|
27708
|
-
"line":
|
|
27740
|
+
"line": 125,
|
|
27709
27741
|
"title": "node-pack-sandbox-network-gated: ungated network egress is refused",
|
|
27710
27742
|
"explicitId": null,
|
|
27711
27743
|
"citations": []
|
|
@@ -27713,7 +27745,7 @@
|
|
|
27713
27745
|
{
|
|
27714
27746
|
"id": "openwop.it.v2-pack-isolation.node-pack-sandbox-no-process-host-process-access-is-refused",
|
|
27715
27747
|
"file": "v2-pack-isolation.test.ts",
|
|
27716
|
-
"line":
|
|
27748
|
+
"line": 132,
|
|
27717
27749
|
"title": "node-pack-sandbox-no-process: host process access is refused",
|
|
27718
27750
|
"explicitId": null,
|
|
27719
27751
|
"citations": []
|
|
@@ -27721,7 +27753,7 @@
|
|
|
27721
27753
|
{
|
|
27722
27754
|
"id": "openwop.it.v2-pack-isolation.node-pack-sandbox-timeout-exceeding-wallclocklimitms-fails-with-sandbox-timeout",
|
|
27723
27755
|
"file": "v2-pack-isolation.test.ts",
|
|
27724
|
-
"line":
|
|
27756
|
+
"line": 139,
|
|
27725
27757
|
"title": "node-pack-sandbox-timeout: exceeding wallClockLimitMs fails with sandbox_timeout",
|
|
27726
27758
|
"explicitId": "openwop.requirement.0173.pack-isolation.timeout",
|
|
27727
27759
|
"citations": [
|
|
@@ -27734,7 +27766,7 @@
|
|
|
27734
27766
|
{
|
|
27735
27767
|
"id": "openwop.it.v2-pack-isolation.node-pack-sandbox-memory-cap-exceeding-memorylimitbytes-fails-with-sandbox-memor",
|
|
27736
27768
|
"file": "v2-pack-isolation.test.ts",
|
|
27737
|
-
"line":
|
|
27769
|
+
"line": 146,
|
|
27738
27770
|
"title": "node-pack-sandbox-memory-cap: exceeding memoryLimitBytes fails with sandbox_memory_exceeded",
|
|
27739
27771
|
"explicitId": "openwop.requirement.0173.pack-isolation.memory-cap",
|
|
27740
27772
|
"citations": [
|
|
@@ -27747,7 +27779,7 @@
|
|
|
27747
27779
|
{
|
|
27748
27780
|
"id": "openwop.it.v2-pack-isolation.node-pack-sandbox-isolated-context-a-pack-cannot-mutate-state-another-invocation",
|
|
27749
27781
|
"file": "v2-pack-isolation.test.ts",
|
|
27750
|
-
"line":
|
|
27782
|
+
"line": 153,
|
|
27751
27783
|
"title": "node-pack-sandbox-isolated-context: a pack cannot mutate state another invocation sees",
|
|
27752
27784
|
"explicitId": "openwop.requirement.0173.pack-isolation.isolated-context",
|
|
27753
27785
|
"citations": [
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "Provenance of @openwop/spec-artifacts (RFC 0168 §D.2). files: SHA-256 per file; the conformance suite compares the installed peer against dist/spec-artifacts.lock.json at start.",
|
|
3
3
|
"package": "@openwop/spec-artifacts",
|
|
4
|
-
"version": "2.4.
|
|
5
|
-
"corpusTag": "v2.4.
|
|
4
|
+
"version": "2.4.2",
|
|
5
|
+
"corpusTag": "v2.4.2",
|
|
6
6
|
"files": {
|
|
7
7
|
"api/.redocly.lint-ignore.yaml": "bf5a8350b88a72fa43f59605ed8d903ed24b6cfccda5e45509c9f6ed9ee4e712",
|
|
8
8
|
"api/asyncapi.yaml": "d5ecb9ee6114582be3b1f662c84bfac9ae96dae7bacb853e461168f70a8e1c7d",
|
|
9
9
|
"api/grpc/openwop.proto": "c3e72bb17cba514ee98feb6434e6c9b6ea6795bfd086489ec69fd882dd1ad977",
|
|
10
10
|
"api/openapi.yaml": "39081c59fb696159806b0f2f9a42e7e9ff830d622fcf2ad4159b21357580a955",
|
|
11
11
|
"api/redocly.yaml": "b0604c89b2ca6d5076ec25725c539dad44a741a811fe524439ee6daef8baa09f",
|
|
12
|
-
"api/seams-v2.yaml": "
|
|
13
|
-
"api/v2/asyncapi.yaml": "
|
|
14
|
-
"api/v2/openapi.yaml": "
|
|
12
|
+
"api/seams-v2.yaml": "2a94a4195377913107f884aacd48605e71804f151333de8a8a0abc7b2799c5e2",
|
|
13
|
+
"api/v2/asyncapi.yaml": "930bd4ea705b35ec37605f139a0be7b08b39d8d9c7628c9756c4fdbe47f4655f",
|
|
14
|
+
"api/v2/openapi.yaml": "33298f7981473111ce767695367e44fa3eaa3cbdda9a52badc2b198efcd8259d",
|
|
15
15
|
"api/v2/redocly.yaml": "1e66b60e6118ad11a823bb620678be464d99dfe50a40e3e6f93ec9429b88b34c",
|
|
16
16
|
"schemas/README.md": "0c0b737ffcf8f30e7d2809cec8a498232de710f41443212922ad8337cdde0b51",
|
|
17
17
|
"schemas/a2a-task-state.schema.json": "c9365918f993f943b4b619d42551eb066a1ed33a08d895d51b395432a5b1f1bc",
|
|
@@ -200,7 +200,7 @@
|
|
|
200
200
|
"schemas/workspace-file.schema.json": "464de85c2a068243084ee9c1d969bc7cd5d8f7948574e58450d6493c38a0e1e4",
|
|
201
201
|
"spec/v1/alias-detectors.json": "e90916db12d2297e2e560b2d54d2c4702d6cb3bef7179a575844687a7ec17262",
|
|
202
202
|
"spec/v1/capability-declaration-classes.json": "e7729aed5c4b4e1dd02abab0530f14cc95f5d4070fe51fb139e7f5cccefa00c6",
|
|
203
|
-
"spec/v1/core-standard-manifest.json": "
|
|
203
|
+
"spec/v1/core-standard-manifest.json": "1575d6d8b801b3d84c65c63d55a4f0563a3350a754e403ee06ffb853b996b639",
|
|
204
204
|
"spec/v1/deprecations.json": "c81c8f71460936c8d489d8270477c7661cf4a5d7b7bad86c98899750b5656027",
|
|
205
205
|
"spec/v1/deprecations.schema.json": "18c87e78bedc210431f795ae44c5b5d202f2f3317850d5cf86867d4f1fa1cdfb",
|
|
206
206
|
"spec/v1/event-codemap.json": "3da60d884157793a360da532a9fcbbfb5285636db325a74cec94b34622186d97",
|
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
"spec/v2/core/errors.md": "ad85fc830139e587f20deabf88297b91b1fb6ce31e80d5442624a650246ab16e",
|
|
220
220
|
"spec/v2/core/events.md": "f1bac16419740f3b722febb6f5caaabed8838e092cba3d080fe9184024049dcf",
|
|
221
221
|
"spec/v2/core/form-content-packs.md": "6ffaae85d4550be48dd53fb6e2959af8aceb35bd87c5343b722885084f197713",
|
|
222
|
-
"spec/v2/core/headers.md": "
|
|
222
|
+
"spec/v2/core/headers.md": "d34646a59632a79e9907439d0521c90e613ed968578af02129bad7002063de99",
|
|
223
223
|
"spec/v2/core/idempotency.md": "b86c352d964aebad532727f314e26ed2177d49de382076fa64d3162e2f56118d",
|
|
224
224
|
"spec/v2/core/identity.md": "9d2b823eb899463807452fe5721dcf09881837c161be024175957db27870b243",
|
|
225
225
|
"spec/v2/core/interop.md": "d4c404e469e1d9d9be88bc2c939d777e7d7c1d0419b1251c18770f039838a401",
|
|
@@ -271,8 +271,8 @@
|
|
|
271
271
|
"spec/v2/path-manifest.json": "a6f4e652e866889e8bde815874062f62929aee95dc8e58e7152c56adee262163",
|
|
272
272
|
"spec/v2/peer-dependency-aliases.json": "d10299280abee08258502925bc327293ee413e0108cd6e6ec75ff6110653308d",
|
|
273
273
|
"spec/v2/profiles.json": "0636f19fceae625390003a347e70ef4797d84766b5c24ce8a02cea52aadebca4",
|
|
274
|
-
"spec/v2/release.json": "
|
|
274
|
+
"spec/v2/release.json": "4fdf29fe944e63528cdf5dc108e22e5006b2d7fcb1349c33caee85a1cacdd81e",
|
|
275
275
|
"spec/v2/retention-floors.json": "eaf3722d95c79947af1d4269ef85117e126518c588cfcf1a2b21b97269f51624"
|
|
276
276
|
},
|
|
277
|
-
"corpusCommit": "
|
|
277
|
+
"corpusCommit": "164711f69c396daffb6a300a94e89242640b4087"
|
|
278
278
|
}
|
|
@@ -76,6 +76,20 @@ function chainPack(name: string, reference: string): Record<string, unknown> {
|
|
|
76
76
|
}],
|
|
77
77
|
};
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* The same fixture with an EXTERNAL sub-chain reference. `SubChainRef.ref`
|
|
81
|
+
* oneOf[1] types `version` as a semver RANGE, so — unlike the node reference
|
|
82
|
+
* above — the schema cannot refuse a range here. A host either carries the
|
|
83
|
+
* §Exact pins rule or it does not, and this is the only shape that tells the
|
|
84
|
+
* two apart.
|
|
85
|
+
*/
|
|
86
|
+
function externalRefPack(name: string, version: string): Record<string, unknown> {
|
|
87
|
+
const pack = chainPack(name, 'core.ai.callPrompt@1.0.0');
|
|
88
|
+
const chain = (pack['chains'] as Array<Record<string, unknown>>)[0] as Record<string, unknown>;
|
|
89
|
+
chain['subChains'] = [{ ref: { packName: 'core.openwop.v2-pin-external', chainId: 'c.remote', version } }];
|
|
90
|
+
return pack;
|
|
91
|
+
}
|
|
92
|
+
|
|
79
93
|
async function publish(manifest: Record<string, unknown>) {
|
|
80
94
|
const name = manifest['name'] as string;
|
|
81
95
|
const version = manifest['version'] as string;
|
|
@@ -108,6 +122,21 @@ describe('v2-chain-pin-exact (RFC 0177 §E.1)', () => {
|
|
|
108
122
|
expect(typeof readErrorCode(res.json), req('openwop.requirement.0177.chain-pin-exact.range-refused', SECTION, 'the refusal MUST carry an error code in the canonical envelope')).toBe('string');
|
|
109
123
|
});
|
|
110
124
|
|
|
125
|
+
it('an EXTERNAL sub-chain reference carrying a range is refused — the one pin the schema cannot catch', async () => {
|
|
126
|
+
const skip = await preflight();
|
|
127
|
+
if (skip) return softSkip(skip.kind, skip.reason);
|
|
128
|
+
// Measured 2026-09-18 on both production hosts: the external branch is
|
|
129
|
+
// typed, reachable and UNEXERCISED — every shipped pack uses the sibling
|
|
130
|
+
// string form — so nothing on either host would have noticed a range here.
|
|
131
|
+
// The two legs above are satisfied by schema validation alone (sabotage on
|
|
132
|
+
// the reference host: delete its pin rule and they stay green), which is
|
|
133
|
+
// why this leg exists: it is the only one that reads the HOST's rule.
|
|
134
|
+
const res = await publish(externalRefPack(freshName('chain-ext-range'), '^1.0.0'));
|
|
135
|
+
if (res.status === 404) return softSkip('blocked', 'packs-test publish seam answered 404 — seams profile advertised but the seam is not mounted');
|
|
136
|
+
expect(res.status >= 400 && res.status < 500, req('openwop.requirement.0177.chain-pin-exact.external-range-refused', SECTION, `an external reference carrying a range MUST be refused at register — the schema types this field as a semver range, so only the host's rule can refuse it (got ${res.status})`)).toBe(true);
|
|
137
|
+
expect(typeof readErrorCode(res.json), req('openwop.requirement.0177.chain-pin-exact.external-range-refused', SECTION, 'the refusal MUST carry an error code in the canonical envelope')).toBe('string');
|
|
138
|
+
});
|
|
139
|
+
|
|
111
140
|
it('a chain reference pinning an exact version (core.ai.callPrompt@1.0.0) registers', async () => {
|
|
112
141
|
const skip = await preflight();
|
|
113
142
|
if (skip) return softSkip(skip.kind, skip.reason);
|
|
@@ -57,6 +57,14 @@ async function invoke(typeId: string, extra: Record<string, unknown> = {}): Prom
|
|
|
57
57
|
if (!doc || !seamsProfileAdvertised(doc)) { softSkip('inapplicable', `the ${typeId} leg is seam-driven — seams profile (conformance.seamsProfile = openwop-conformance-seams-v2) not advertised`); return null; }
|
|
58
58
|
const res = await driver.post(INVOKE, { typeId, ...extra });
|
|
59
59
|
if (res.status === 404 || res.status === 403 || res.status === 405) { seamAbsent(`host advertises packs + sandbox but ${INVOKE} answered ${res.status} — the ${typeId} leg is unobservable (host-sample-test-seams.md §8)`); return null; }
|
|
60
|
+
// The same id is ALSO asserted by its own `it` above, and that is the copy the
|
|
61
|
+
// registry can see: `generate-requirement-registry.mjs` harvests `req(…)` only
|
|
62
|
+
// within an `it`, so this helper-level call alone left the id out of
|
|
63
|
+
// requirements.json — and no bundle could carry a row for it — while
|
|
64
|
+
// `check-cut-gates.mjs`, which scans every `req(` in the source, went on
|
|
65
|
+
// demanding one. §G.2 failed on a row no host could supply. RFC 0168 §A.1
|
|
66
|
+
// requires `req(…)` here rather than a bare describe, so the fix is the extra
|
|
67
|
+
// `it`, not a quieter assertion.
|
|
60
68
|
expect(res.status, req('openwop.requirement.0173.pack-isolation.seam', 'host-sample-test-seams.md §8', `${INVOKE} MUST answer 200 { result } | 200 { error } for ${typeId}`)).toBe(200);
|
|
61
69
|
return (res.json ?? {}) as InvokeResult;
|
|
62
70
|
}
|
|
@@ -81,6 +89,18 @@ describe('RFC 0173 §B — pack-isolation (gated on packs + sandbox)', () => {
|
|
|
81
89
|
).toContain(model);
|
|
82
90
|
});
|
|
83
91
|
|
|
92
|
+
it('the sandbox-invoke seam answers the seam contract', async () => {
|
|
93
|
+
if (!(await gated())) return softSkip('inapplicable', 'gate not met (reason recorded above)');
|
|
94
|
+
const doc = await discovery();
|
|
95
|
+
if (!doc || !seamsProfileAdvertised(doc)) return softSkip('inapplicable', 'seam-driven — seams profile (conformance.seamsProfile = openwop-conformance-seams-v2) not advertised');
|
|
96
|
+
const res = await driver.post(INVOKE, { typeId: 'misbehave.fs-escape-read' });
|
|
97
|
+
if (res.status === 404 || res.status === 403 || res.status === 405) return seamAbsent(`host advertises packs + sandbox but ${INVOKE} answered ${res.status}`);
|
|
98
|
+
expect(
|
|
99
|
+
res.status,
|
|
100
|
+
req('openwop.requirement.0173.pack-isolation.seam', 'host-sample-test-seams.md §8', `${INVOKE} MUST answer 200 { result } | 200 { error } — the eight behavioural legs are unobservable otherwise`),
|
|
101
|
+
).toBe(200);
|
|
102
|
+
});
|
|
103
|
+
|
|
84
104
|
it('node-pack-sandbox-fs-gated: a host filesystem read is refused', async () => {
|
|
85
105
|
if (!(await gated())) return softSkip('inapplicable', 'gate not met (reason recorded above)');
|
|
86
106
|
const r = await invoke('misbehave.fs-escape-read');
|