capdag 1.241.684 → 1.243.691
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/capdag.js +55 -0
- package/capdag.test.js +88 -0
- package/package.json +1 -1
package/capdag.js
CHANGED
|
@@ -949,6 +949,50 @@ class CapUrn {
|
|
|
949
949
|
return runtimeOut;
|
|
950
950
|
}
|
|
951
951
|
|
|
952
|
+
/**
|
|
953
|
+
* THE effect-audit predicate: does an actually-emitted runtime output
|
|
954
|
+
* satisfy this cap's declared effect contract for the given runtime
|
|
955
|
+
* input? Every check of "did the cap emit what its effect promised"
|
|
956
|
+
* must go through this — never a hand-rolled combination of
|
|
957
|
+
* inferRuntimeOutputMedia with equality or conformance checks, so the
|
|
958
|
+
* contract has exactly one definition.
|
|
959
|
+
*
|
|
960
|
+
* The condition is deliberately asymmetric per effect:
|
|
961
|
+
* - effect=none / effect=patch compute an EXACT runtime output type,
|
|
962
|
+
* so the emission must be tag-equivalent to the inference. A more
|
|
963
|
+
* specific emission would still be a lie: the effect promises the
|
|
964
|
+
* type is fully determined by the input.
|
|
965
|
+
* - effect=declared promises only the declared out=, so an emission
|
|
966
|
+
* that is MORE specific than the declaration is legal and desirable;
|
|
967
|
+
* the emission must conform to the declared output. A more generic
|
|
968
|
+
* emission breaks downstream plan refinement and fails.
|
|
969
|
+
*
|
|
970
|
+
* Throws (rather than returning false) when the inference itself is
|
|
971
|
+
* impossible: the runtime input does not conform to the declared
|
|
972
|
+
* input, the effect is the unconstrained request form (?effect), or
|
|
973
|
+
* the URN state is internally inconsistent — those are upstream
|
|
974
|
+
* contract breaks, not emission mismatches.
|
|
975
|
+
*
|
|
976
|
+
* @param {MediaUrn} runtimeInput
|
|
977
|
+
* @param {MediaUrn} runtimeOutput
|
|
978
|
+
* @returns {boolean}
|
|
979
|
+
*/
|
|
980
|
+
isConformantRuntimeOutput(runtimeInput, runtimeOutput) {
|
|
981
|
+
const inferred = this.inferRuntimeOutputMedia(runtimeInput);
|
|
982
|
+
switch (this.effectValue) {
|
|
983
|
+
case CapEffect.NONE:
|
|
984
|
+
case CapEffect.PATCH:
|
|
985
|
+
return runtimeOutput.isEquivalent(inferred);
|
|
986
|
+
case CapEffect.DECLARED:
|
|
987
|
+
return runtimeOutput.conformsTo(inferred);
|
|
988
|
+
default:
|
|
989
|
+
throw new CapUrnError(
|
|
990
|
+
ErrorCodes.INVALID_EFFECT_APPLICATION,
|
|
991
|
+
'Cannot audit an emission against an unconstrained effect request'
|
|
992
|
+
);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
|
|
952
996
|
_validateAdmissible() {
|
|
953
997
|
const inMedia = this.inMediaUrn();
|
|
954
998
|
const outMedia = this.outMediaUrn();
|
|
@@ -1561,6 +1605,17 @@ class MediaUrn {
|
|
|
1561
1605
|
*/
|
|
1562
1606
|
isFilePath() { return this._hasMarkerTag('file-path'); }
|
|
1563
1607
|
|
|
1608
|
+
/**
|
|
1609
|
+
* True if this URN carries the `live` marker tag — a live-feed
|
|
1610
|
+
* REFERENCE (13.2 §Reference Media): the arg value is a selector record
|
|
1611
|
+
* the runtime resolves into an unbounded content stream via a registered
|
|
1612
|
+
* provider, the same transport-resolution family as `media:file-path`.
|
|
1613
|
+
* This is the canonical membership predicate for that family; callers
|
|
1614
|
+
* must not test the `live` tag themselves.
|
|
1615
|
+
* @returns {boolean}
|
|
1616
|
+
*/
|
|
1617
|
+
isLiveFeed() { return this._hasMarkerTag('live'); }
|
|
1618
|
+
|
|
1564
1619
|
/**
|
|
1565
1620
|
* Check if this represents a collection type.
|
|
1566
1621
|
* Returns true if the "collection" marker tag is present.
|
package/capdag.test.js
CHANGED
|
@@ -2797,6 +2797,16 @@ function test551_isFilePath() {
|
|
|
2797
2797
|
assert(!MediaUrn.fromString(MEDIA_IDENTITY).isFilePath(), 'MEDIA_IDENTITY should not be file-path');
|
|
2798
2798
|
}
|
|
2799
2799
|
|
|
2800
|
+
// TEST553: is_live_feed returns true for every URN carrying the `live` marker tag (the reference-media family the runtime resolves via providers), false for everything else — including content URNs a feed delivers.
|
|
2801
|
+
function test553_isLiveFeed() {
|
|
2802
|
+
assert(MediaUrn.fromString('media:live').isLiveFeed(), 'media:live should be live-feed');
|
|
2803
|
+
assert(MediaUrn.fromString('media:live;synthetic').isLiveFeed(), 'media:live;synthetic should be live-feed');
|
|
2804
|
+
assert(MediaUrn.fromString('media:audio;live;microphone').isLiveFeed(), 'microphone URN should be live-feed');
|
|
2805
|
+
assert(!MediaUrn.fromString(MEDIA_STRING).isLiveFeed(), 'MEDIA_STRING should not be live-feed');
|
|
2806
|
+
assert(!MediaUrn.fromString(MEDIA_FILE_PATH).isLiveFeed(), 'MEDIA_FILE_PATH should not be live-feed');
|
|
2807
|
+
assert(!MediaUrn.fromString('media:audio;pcm').isLiveFeed(), 'feed CONTENT urns should not be live-feed');
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2800
2810
|
// Mirror-specific coverage: isCollection returns true when collection marker tag is present
|
|
2801
2811
|
// Mirror-specific coverage: N/A for JS (MEDIA_COLLECTION constants removed - no longer exists)
|
|
2802
2812
|
function test6272_isCollection() {
|
|
@@ -3206,6 +3216,80 @@ function test127_invalidEffectNoneFailsHard() {
|
|
|
3206
3216
|
);
|
|
3207
3217
|
}
|
|
3208
3218
|
|
|
3219
|
+
// TEST8121: isConformantRuntimeOutput — effect=declared accepts a more
|
|
3220
|
+
// specific emission, rejects a more generic one
|
|
3221
|
+
function test8121_effectConformanceDeclaredAsymmetry() {
|
|
3222
|
+
const cap = CapUrn.fromString('cap:extract;in="media:ext=pdf";out="media:record"');
|
|
3223
|
+
const input = MediaUrn.fromString('media:ext=pdf');
|
|
3224
|
+
|
|
3225
|
+
assert(
|
|
3226
|
+
cap.isConformantRuntimeOutput(input, MediaUrn.fromString('media:record')),
|
|
3227
|
+
'emitting exactly the declared out is conformant'
|
|
3228
|
+
);
|
|
3229
|
+
assert(
|
|
3230
|
+
cap.isConformantRuntimeOutput(input, MediaUrn.fromString('media:fmt=json;record')),
|
|
3231
|
+
'a more specific emission than the declared out is conformant'
|
|
3232
|
+
);
|
|
3233
|
+
assert(
|
|
3234
|
+
!cap.isConformantRuntimeOutput(input, MediaUrn.fromString('media:')),
|
|
3235
|
+
'a more generic emission than the declared out is a violation'
|
|
3236
|
+
);
|
|
3237
|
+
assert(
|
|
3238
|
+
!cap.isConformantRuntimeOutput(input, MediaUrn.fromString('media:ext=png;image')),
|
|
3239
|
+
'an unrelated emission is a violation'
|
|
3240
|
+
);
|
|
3241
|
+
}
|
|
3242
|
+
|
|
3243
|
+
// TEST8122: isConformantRuntimeOutput — effect=none requires the emission
|
|
3244
|
+
// to be tag-equivalent to the runtime input; MORE specific is still a lie
|
|
3245
|
+
function test8122_effectConformanceNoneRequiresEquivalence() {
|
|
3246
|
+
const cap = CapUrn.fromString('cap:decimate-sequence;effect=none');
|
|
3247
|
+
const input = MediaUrn.fromString('media:ext=png;image');
|
|
3248
|
+
|
|
3249
|
+
assert(
|
|
3250
|
+
cap.isConformantRuntimeOutput(input, input),
|
|
3251
|
+
'emitting exactly the runtime input type is conformant'
|
|
3252
|
+
);
|
|
3253
|
+
assert(
|
|
3254
|
+
!cap.isConformantRuntimeOutput(input, MediaUrn.fromString('media:ext=png;image;width=64')),
|
|
3255
|
+
'effect=none promises the output type IS the input type; more specific is a lie'
|
|
3256
|
+
);
|
|
3257
|
+
assert(
|
|
3258
|
+
!cap.isConformantRuntimeOutput(input, MediaUrn.fromString('media:image')),
|
|
3259
|
+
'a more generic emission is a violation'
|
|
3260
|
+
);
|
|
3261
|
+
|
|
3262
|
+
const strict = CapUrn.fromString('cap:effect=none;in="media:image";out="media:image"');
|
|
3263
|
+
const nonImage = MediaUrn.fromString('media:ext=pdf');
|
|
3264
|
+
assertThrows(
|
|
3265
|
+
() => strict.isConformantRuntimeOutput(nonImage, nonImage),
|
|
3266
|
+
ErrorCodes.INVALID_EFFECT_APPLICATION,
|
|
3267
|
+
'a nonconforming runtime input is an upstream contract break, surfaced as an error'
|
|
3268
|
+
);
|
|
3269
|
+
}
|
|
3270
|
+
|
|
3271
|
+
// TEST8123: isConformantRuntimeOutput — effect=patch requires exactly the
|
|
3272
|
+
// delta-patched input type
|
|
3273
|
+
function test8123_effectConformancePatchRequiresPatchedInput() {
|
|
3274
|
+
const cap = CapUrn.fromString(
|
|
3275
|
+
'cap:convert;effect=patch;in="media:ext=jpeg;image";out="media:ext=png;image"'
|
|
3276
|
+
);
|
|
3277
|
+
const input = MediaUrn.fromString('media:ext=jpeg;image;width=64');
|
|
3278
|
+
|
|
3279
|
+
assert(
|
|
3280
|
+
cap.isConformantRuntimeOutput(input, MediaUrn.fromString('media:ext=png;image;width=64')),
|
|
3281
|
+
'the delta-patched input type (preserved tags intact) is conformant'
|
|
3282
|
+
);
|
|
3283
|
+
assert(
|
|
3284
|
+
!cap.isConformantRuntimeOutput(input, MediaUrn.fromString('media:ext=png;image')),
|
|
3285
|
+
'dropping the preserved width tag violates the patch promise'
|
|
3286
|
+
);
|
|
3287
|
+
assert(
|
|
3288
|
+
!cap.isConformantRuntimeOutput(input, input),
|
|
3289
|
+
'emitting the unpatched input type is a violation'
|
|
3290
|
+
);
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3209
3293
|
// TEST128: omitted effect means declared; unconstrained effect must be explicit
|
|
3210
3294
|
function test128_effectDispatchRequiresExplicitWildcard() {
|
|
3211
3295
|
const noneCandidate = CapUrn.fromString('cap:effect=none');
|
|
@@ -7234,6 +7318,7 @@ async function runTests() {
|
|
|
7234
7318
|
runTest('TEST1315: is_numeric', test549_isNumeric);
|
|
7235
7319
|
runTest('TEST1298: is_bool', test550_isBool);
|
|
7236
7320
|
runTest('TEST1299: is_file_path', test551_isFilePath);
|
|
7321
|
+
runTest('TEST553: is_live_feed', test553_isLiveFeed);
|
|
7237
7322
|
runTest('TEST1302: predicate_constant_consistency', test558_predicateConstantConsistency);
|
|
7238
7323
|
|
|
7239
7324
|
// cap_urn.rs: TEST1303-TEST1307 (CapUrn tier tests)
|
|
@@ -7270,6 +7355,9 @@ async function runTests() {
|
|
|
7270
7355
|
runTest('TEST655: effect_declared_uses_declared_output', test126_effectDeclaredUsesDeclaredOutput);
|
|
7271
7356
|
runTest('TEST656: invalid_effect_none_fails_hard', test127_invalidEffectNoneFailsHard);
|
|
7272
7357
|
runTest('TEST657: effect_dispatch_requires_explicit_wildcard', test128_effectDispatchRequiresExplicitWildcard);
|
|
7358
|
+
runTest('TEST8121: effect_conformance_declared_asymmetry', test8121_effectConformanceDeclaredAsymmetry);
|
|
7359
|
+
runTest('TEST8122: effect_conformance_none_requires_equivalence', test8122_effectConformanceNoneRequiresEquivalence);
|
|
7360
|
+
runTest('TEST8123: effect_conformance_patch_requires_patched_input', test8123_effectConformancePatchRequiresPatchedInput);
|
|
7273
7361
|
|
|
7274
7362
|
// machine module: parser tests (mirrors parser.rs)
|
|
7275
7363
|
console.log('\n--- machine/parser.rs ---');
|
package/package.json
CHANGED