@openwop/openwop-conformance 1.102.0 → 1.103.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/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "Provenance of this vendored schemas/ copy. See conformance/README.md \u00a7\"Resolving the contract\". Compare against the stamp in your installed @openwop/openwop-conformance to detect a stale hand-copied contract.",
|
|
3
|
-
"suiteVersion": "1.
|
|
4
|
-
"corpusCommit": "
|
|
3
|
+
"suiteVersion": "1.103.0",
|
|
4
|
+
"corpusCommit": "c6f779513a26705a5d9fd8958ec1cd75ab8f6fdb"
|
|
5
5
|
}
|
|
@@ -48,6 +48,9 @@ import { describe, it, expect } from 'vitest';
|
|
|
48
48
|
import { driver } from '../lib/driver.js';
|
|
49
49
|
import { pollUntilTerminal } from '../lib/polling.js';
|
|
50
50
|
import { isFixtureAdvertised } from '../lib/fixtures.js';
|
|
51
|
+
import { readFileSync } from 'node:fs';
|
|
52
|
+
import { join } from 'node:path';
|
|
53
|
+
import { V1_DIR } from '../lib/paths.js';
|
|
51
54
|
|
|
52
55
|
const WORKFLOW_ID = 'conformance-replay-side-effect';
|
|
53
56
|
const EFFECT_NODE = 'effect';
|
|
@@ -182,3 +185,65 @@ describe.skipIf(SKIP_NO_FIXTURE)('replay-side-effect-suppression: a replay does
|
|
|
182
185
|
).toBe(true);
|
|
183
186
|
});
|
|
184
187
|
});
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* `replay.md` requirement 4 — the manifest declaration is a classification FLOOR.
|
|
191
|
+
*
|
|
192
|
+
* A pack manifest may declare `role: "side-effect"`. Until 2026-08-14 the only
|
|
193
|
+
* stated purpose of that field was that it "drives engine scheduling", so a host
|
|
194
|
+
* was free to classify side-effecting nodes from a private list and never read
|
|
195
|
+
* it. A tier-1 host did exactly that and a shipped `core.storage.blob-put` node
|
|
196
|
+
* performed real object-store `PUT`s **during a replay**, past two independent
|
|
197
|
+
* guards, because neither consulted the manifest that had declared the node
|
|
198
|
+
* side-effecting all along.
|
|
199
|
+
*
|
|
200
|
+
* Requirement 4 makes the declaration binding: a host's own classifier is a floor
|
|
201
|
+
* ABOVE it and never a substitute — more nodes may be treated as side-effecting,
|
|
202
|
+
* never fewer.
|
|
203
|
+
*
|
|
204
|
+
* **This is a coherence gate, not a behavioral witness, and the distinction
|
|
205
|
+
* matters.** Proving a host honours requirement 4 needs that host advertising
|
|
206
|
+
* `recorded-outcome`, a pack node declaring the role, and an observable external
|
|
207
|
+
* effect across a replay — none of which the suite can synthesize. What it CAN
|
|
208
|
+
* do is ensure the declaration and the obligation cannot drift apart: if someone
|
|
209
|
+
* renames the role value, or drops the requirement, this fails. RFC 0148 §A
|
|
210
|
+
* resolves the behavioral half to `blocked`, not to a pass.
|
|
211
|
+
*/
|
|
212
|
+
describe.skipIf(V1_DIR === null)('replay.md req 4 — the manifest role is a classification floor', () => {
|
|
213
|
+
const dir = V1_DIR as string;
|
|
214
|
+
const replay = () => readFileSync(join(dir, 'replay.md'), 'utf8');
|
|
215
|
+
const manifest = () =>
|
|
216
|
+
readFileSync(join(dir, '..', '..', 'schemas', 'node-pack-manifest.schema.json'), 'utf8');
|
|
217
|
+
|
|
218
|
+
it('the manifest still offers the role value the requirement binds', () => {
|
|
219
|
+
// If `side-effect` is renamed or dropped from the taxonomy, requirement 4
|
|
220
|
+
// binds a value nothing can declare — a rule with no reachable trigger.
|
|
221
|
+
expect(
|
|
222
|
+
manifest().includes('side-effect'),
|
|
223
|
+
'node-pack-manifest.schema.json §role MUST still describe the `side-effect` value that ' +
|
|
224
|
+
'replay.md requirement 4 makes binding. A requirement whose trigger no longer exists is ' +
|
|
225
|
+
'not enforcement, it is decoration.',
|
|
226
|
+
).toBe(true);
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('replay.md binds that declaration, naming the schema it comes from', () => {
|
|
230
|
+
const doc = replay();
|
|
231
|
+
expect(
|
|
232
|
+
/MUST\*{0,2} be treated as side-effecting/.test(doc) && doc.includes('node-pack-manifest.schema.json'),
|
|
233
|
+
'replay.md §"Requirements when a host declares `sideEffectSuppression: \\"recorded-outcome\\"`" ' +
|
|
234
|
+
'MUST bind a manifest-declared `role: "side-effect"` to the suppression obligation, and MUST ' +
|
|
235
|
+
'name the schema the declaration comes from so a reader can find it.',
|
|
236
|
+
).toBe(true);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('the floor direction is stated, not left to inference', () => {
|
|
240
|
+
// The dangerous reading is symmetric: "my classifier disagrees, so the
|
|
241
|
+
// manifest is wrong." The requirement is one-directional and says so.
|
|
242
|
+
expect(
|
|
243
|
+
replay().includes('MUST NOT classify fewer'),
|
|
244
|
+
'replay.md requirement 4 MUST state the direction: a host classifier may treat MORE nodes as ' +
|
|
245
|
+
'side-effecting and never fewer. Without the direction, a host that trusts its own list over ' +
|
|
246
|
+
'the manifest can read the clause as permission to disagree.',
|
|
247
|
+
).toBe(true);
|
|
248
|
+
});
|
|
249
|
+
});
|