@entelekheia/ref-id 0.3.0 → 0.4.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 +72 -6
- package/dist/digest.js +2 -2
- package/dist/digest.js.map +1 -1
- package/dist/hash.browser.d.ts +9 -0
- package/dist/hash.browser.js +27 -0
- package/dist/hash.browser.js.map +1 -0
- package/dist/hash.d.ts +10 -0
- package/dist/hash.js +34 -0
- package/dist/hash.js.map +1 -0
- package/dist/hash.node.d.ts +7 -0
- package/dist/hash.node.js +12 -0
- package/dist/hash.node.js.map +1 -0
- package/dist/index.browser.d.ts +11 -0
- package/dist/index.browser.js +41 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/relations.d.ts +29 -0
- package/dist/relations.js +135 -0
- package/dist/relations.js.map +1 -0
- package/dist/spec.browser.d.ts +12 -0
- package/dist/spec.browser.js +22 -0
- package/dist/spec.browser.js.map +1 -0
- package/dist/spec.d.ts +31 -11
- package/dist/spec.js +39 -44
- package/dist/spec.js.map +1 -1
- package/dist/spec.node.d.ts +11 -0
- package/dist/spec.node.js +49 -0
- package/dist/spec.node.js.map +1 -0
- package/dist/validators.js +54 -1
- package/dist/validators.js.map +1 -1
- package/package.json +8 -2
- package/spec/ref-id.json +2464 -1816
- package/spec/ref-id.json.sha256 +1 -1
package/spec/ref-id.json
CHANGED
|
@@ -1,1852 +1,2500 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
},
|
|
47
|
-
"state": {
|
|
48
|
-
"separator": ";",
|
|
49
|
-
"pair": "^(?<key>[a-z][a-z0-9-]*)=(?<value>[^\\r\\n]*)$",
|
|
50
|
-
"unknownKey": "carry-through",
|
|
51
|
-
"repeatedKey": "malformed"
|
|
52
|
-
},
|
|
53
|
-
"fragment": {
|
|
54
|
-
"separator": ";",
|
|
55
|
-
"pair": "^(?<key>[a-z][a-z0-9-]*)=(?<value>[^\\r\\n]*)$",
|
|
56
|
-
"path": "the text before the first separator, verbatim",
|
|
57
|
-
"repeatedKey": "malformed"
|
|
58
|
-
}
|
|
2
|
+
"specVersion": "1.3.0",
|
|
3
|
+
"scheme": "ref",
|
|
4
|
+
"grammar": {
|
|
5
|
+
"dialect": "ecmascript-2018",
|
|
6
|
+
"expression": "^ref:(?:(?<version>[0-9]+):)?(?<type>[a-z][a-z0-9+.-]*):(?<locator>[^;#\\r\\n]+)(?:;(?<state>[^#\\r\\n]*))?(?:#(?<fragment>[^\\r\\n]*))?$",
|
|
7
|
+
"groups": [
|
|
8
|
+
"version",
|
|
9
|
+
"type",
|
|
10
|
+
"locator",
|
|
11
|
+
"state",
|
|
12
|
+
"fragment"
|
|
13
|
+
],
|
|
14
|
+
"adaptationsApplyTo": "every pattern in this file — the expression, the pair grammars, the forms, the dispatch and refinement patterns",
|
|
15
|
+
"anchors": "the canonical dialect ends a pattern with $ meaning end of input; an engine whose $ also matches before a final line break declares the replacement above",
|
|
16
|
+
"adaptations": {
|
|
17
|
+
"ecmascript-2018": {
|
|
18
|
+
"replace": []
|
|
19
|
+
},
|
|
20
|
+
"pcre2": {
|
|
21
|
+
"replace": [
|
|
22
|
+
[
|
|
23
|
+
"$",
|
|
24
|
+
"\\z"
|
|
25
|
+
]
|
|
26
|
+
]
|
|
27
|
+
},
|
|
28
|
+
"rust-regex": {
|
|
29
|
+
"replace": []
|
|
30
|
+
},
|
|
31
|
+
"python-re": {
|
|
32
|
+
"replace": [
|
|
33
|
+
[
|
|
34
|
+
"(?<",
|
|
35
|
+
"(?P<"
|
|
36
|
+
],
|
|
37
|
+
[
|
|
38
|
+
"$",
|
|
39
|
+
"\\Z"
|
|
40
|
+
]
|
|
41
|
+
]
|
|
42
|
+
},
|
|
43
|
+
"swift-regex": {
|
|
44
|
+
"replace": []
|
|
45
|
+
}
|
|
59
46
|
},
|
|
60
|
-
"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
"mints": [
|
|
66
|
-
"normalisation or percent-encoding",
|
|
67
|
-
"separators or shape"
|
|
68
|
-
],
|
|
69
|
-
"note": "A leading digit can only be a version because a type starts with a letter; ref:v2:... is type v2."
|
|
47
|
+
"state": {
|
|
48
|
+
"separator": ";",
|
|
49
|
+
"pair": "^(?<key>[a-z][a-z0-9-]*)=(?<value>[^\\r\\n]*)$",
|
|
50
|
+
"unknownKey": "carry-through",
|
|
51
|
+
"repeatedKey": "malformed"
|
|
70
52
|
},
|
|
71
|
-
"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
53
|
+
"fragment": {
|
|
54
|
+
"separator": ";",
|
|
55
|
+
"pair": "^(?<key>[a-z][a-z0-9-]*)=(?<value>[^\\r\\n]*)$",
|
|
56
|
+
"path": "the text before the first separator, verbatim",
|
|
57
|
+
"repeatedKey": "malformed"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
"version": {
|
|
61
|
+
"default": 1,
|
|
62
|
+
"supported": [
|
|
63
|
+
1
|
|
64
|
+
],
|
|
65
|
+
"mints": [
|
|
66
|
+
"normalisation or percent-encoding",
|
|
67
|
+
"separators or shape"
|
|
68
|
+
],
|
|
69
|
+
"note": "A leading digit can only be a version because a type starts with a letter; ref:v2:... is type v2."
|
|
70
|
+
},
|
|
71
|
+
"encoding": {
|
|
72
|
+
"locator": {
|
|
73
|
+
"reserved": [],
|
|
74
|
+
"note": "a locator is handed to its validator verbatim — a format's own percent-encoding is the format's, and a value that needs a reserved character cannot be a locator"
|
|
89
75
|
},
|
|
90
|
-
"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
"
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
76
|
+
"nested": {
|
|
77
|
+
"reserved": [
|
|
78
|
+
";",
|
|
79
|
+
"#",
|
|
80
|
+
"%"
|
|
81
|
+
],
|
|
82
|
+
"table": {
|
|
83
|
+
";": "%3B",
|
|
84
|
+
"#": "%23",
|
|
85
|
+
"%": "%25"
|
|
86
|
+
},
|
|
87
|
+
"strict": "every % in a nested value begins one of the forms in the table; any other % is malformed at the key"
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
"dispatch": {
|
|
91
|
+
"pkg": {
|
|
92
|
+
"locator": "package-url",
|
|
93
|
+
"validator": "package-url",
|
|
94
|
+
"delegate": "type-prefixed",
|
|
95
|
+
"versionTail": true,
|
|
96
|
+
"corpus": "the nearest manifest declaring a name, skipping any ancestor manifest whose own workspace or package configuration excludes the file; unversioned, the Package URL names the living package and state= carries the frozen one. A path inside the package follows the version and leaves for the Package URL as its own subpath component; with no version declared there is no marker separating the name from the path, so a file in an unversioned corpus is named through folder instead.",
|
|
97
|
+
"reference": "https://github.com/package-url/purl-spec"
|
|
98
|
+
},
|
|
99
|
+
"folder": {
|
|
100
|
+
"locator": "declared-corpus-name",
|
|
101
|
+
"validator": "declared-name",
|
|
102
|
+
"delegate": "verbatim",
|
|
103
|
+
"versionTail": false,
|
|
104
|
+
"pattern": "^[A-Za-z0-9][A-Za-z0-9._-]*(/[A-Za-z0-9._-]+)*$",
|
|
105
|
+
"declaredBy": "one line in the repository configuration, per subtree, nearest ancestor wins",
|
|
106
|
+
"corpus": "the subtree declared by name in the repository configuration; the locator continues into that subtree, one segment per directory, and ends at the file whose declared names the fragment cuts"
|
|
107
|
+
},
|
|
108
|
+
"url": {
|
|
109
|
+
"locator": "hostname-path",
|
|
110
|
+
"validator": "declared-name",
|
|
111
|
+
"delegate": "verbatim",
|
|
112
|
+
"pattern": "^(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z][a-z0-9-]{1,62}(?:/[^/@;#:.][^/@;#:]*)*(?:@[A-Za-z0-9][A-Za-z0-9._+-]*)?$",
|
|
113
|
+
"versionTail": true,
|
|
114
|
+
"declaredBy": "the owner of the host names what lives under it: each path segment is a declared name, never a URL path, and @version is optional on the last segment. A segment admits every character except the four the grammar reserves and ':', which is excluded so that a name carrying its own version after a colon is refused rather than absorbed whole — an identifier spelled in another format's convention must be converted, and a segment admitting ':' would accept it silently with the version inert inside the name. '~' is admitted alone, because a digest never appears without the colon that introduces it. A segment may not open on '.', which excludes '.' and '..' for the reason the served-model entry gives below: the delegate is verbatim, so a consumer mapping a declared name onto a path would otherwise inherit a traversal from a locator that parsed clean.",
|
|
115
|
+
"corpus": "a manifest that declares a host names the corpus by that host; the package name stays the identifier of the software",
|
|
116
|
+
"reference": "RFC 1123 host labels, lowercase, internationalised labels in their punycode form"
|
|
117
|
+
},
|
|
118
|
+
"email": {
|
|
119
|
+
"locator": "addr-spec",
|
|
120
|
+
"validator": "declared-name",
|
|
121
|
+
"delegate": "verbatim",
|
|
122
|
+
"versionTail": false,
|
|
123
|
+
"pattern": "^[A-Za-z0-9._%+-]+@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z][a-z0-9-]{1,62}(?:/[A-Za-z0-9._%+@-]+)*$",
|
|
124
|
+
"declaredBy": "a mailbox identifies a person or a role, and the items served under it are declared by whoever serves them — a message by its RFC 5322 Message-ID, a thread by the id its provider minted. The scheme checks neither who minted an id nor that the item exists, so the locator continues into the mailbox one segment per item. The first segment is the addr-spec and nothing else: an item id carrying an @, which a Message-ID does, sits after the first / and is never mistaken for the mailbox. A Message-ID is carried without the angle brackets RFC 5322 writes it between, which is the form a mail API hands over.",
|
|
125
|
+
"reference": "RFC 5322 addr-spec, dot-atom local part — describing the first segment of the locator; RFC 5322 msg-id for an item, angle brackets stripped"
|
|
126
|
+
},
|
|
127
|
+
"unknown": {
|
|
128
|
+
"locator": "deferred-species-name",
|
|
129
|
+
"validator": "declared-name",
|
|
130
|
+
"delegate": "verbatim",
|
|
131
|
+
"versionTail": true,
|
|
132
|
+
"pattern": "^(?:[a-z][a-z0-9+.-]*:)?[A-Za-z0-9][A-Za-z0-9._-]*(?:/[A-Za-z0-9][A-Za-z0-9._-]*)*(?:@[A-Za-z0-9][A-Za-z0-9._+-]*)?$",
|
|
133
|
+
"declaredBy": "an authority this registry does not cover. The optional prefix before the first ':' names the species — the naming system the locator belongs to — so that an uncovered authority is still named precisely rather than opaquely; registering that species as a type of its own later leaves the written identifier unchanged and moves only its status. A colon is safe inside this locator and unsafe at the top level for the same reason: here the outer type is fixed, so this grammar owns every colon within it.",
|
|
134
|
+
"corpus": "whatever the species declares"
|
|
140
135
|
},
|
|
141
|
-
"
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
136
|
+
"tel": {
|
|
137
|
+
"locator": "global-number",
|
|
138
|
+
"validator": "declared-name",
|
|
139
|
+
"delegate": "verbatim",
|
|
140
|
+
"versionTail": false,
|
|
141
|
+
"pattern": "^\\+[1-9][0-9]{1,14}$",
|
|
142
|
+
"declaredBy": "the global number of ITU-T E.164, written as RFC 3966 writes it — the leading '+' is required, so one number has one spelling. Visual separators are legal in both standards and are not admitted here: a locator reaches its validator verbatim, so a non-canonical spelling is refused rather than repaired.",
|
|
143
|
+
"reference": "RFC 3966 tel URI, global-number-digits; ITU-T E.164"
|
|
145
144
|
},
|
|
146
|
-
"
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
145
|
+
"isbn": {
|
|
146
|
+
"locator": "book-number",
|
|
147
|
+
"validator": "check-digit",
|
|
148
|
+
"delegate": "verbatim",
|
|
149
|
+
"versionTail": false,
|
|
150
|
+
"pattern": "^(?:97[89][0-9]{10}|[0-9]{9}[0-9X])$",
|
|
151
|
+
"declaredBy": "the International Standard Book Number of ISO 2108, in its canonical digits with no hyphens. Both registered lengths are admitted: the 13-digit form, which is also a GTIN-13 under the 978 and 979 prefixes, and the 10-digit form, whose final character may be 'X' for the value ten. The check digit is computed, so a number of the right shape and the wrong digit is refused.",
|
|
152
|
+
"reference": "ISO 2108"
|
|
153
|
+
},
|
|
154
|
+
"gtin": {
|
|
155
|
+
"locator": "trade-item-number",
|
|
156
|
+
"validator": "check-digit",
|
|
157
|
+
"delegate": "verbatim",
|
|
158
|
+
"versionTail": false,
|
|
159
|
+
"pattern": "^(?:[0-9]{8}|[0-9]{12}|[0-9]{13}|[0-9]{14})$",
|
|
160
|
+
"declaredBy": "the Global Trade Item Number of GS1 — the number a retail barcode carries. Four lengths are registered and all four are admitted: GTIN-8 (EAN-8), GTIN-12 (UPC-A), GTIN-13 (EAN-13) and GTIN-14 (ITF-14). The check digit is the GS1 weighted sum and is computed, so a number of the right shape and the wrong digit is refused. A 13-digit book number is both a GTIN-13 and an ISBN; the two types overlap there deliberately and diverge at the 10-digit form.",
|
|
161
|
+
"reference": "GS1 General Specifications, GTIN and its check digit calculation"
|
|
162
|
+
},
|
|
163
|
+
"ai-model": {
|
|
164
|
+
"locator": "served-model-id",
|
|
165
|
+
"validator": "declared-name",
|
|
166
|
+
"delegate": "verbatim",
|
|
167
|
+
"versionTail": false,
|
|
168
|
+
"pattern": "^[A-Za-z0-9][A-Za-z0-9._:@-]*(?:/[A-Za-z0-9][A-Za-z0-9._:@-]*)*$",
|
|
169
|
+
"declaredBy": "the id the model is served under — the exact string a caller sends to the serving process to select it, verbatim. Deliberately permissive: coercing a served name breaks the round-trip that makes it an identifier at all, so ':' (an Ollama tag), '/' (a hub-style namespace) and '@' (an LM Studio quantisation key, a revision pin) are all admitted, because a serving process accepts each of them today and rejecting one would be a defect rather than a safeguard. Every '/'-separated segment must open on an alphanumeric, which admits each of those and excludes '..', '//' and a trailing '/': the delegate is verbatim, so a consumer mapping a served id onto a path — a local weights cache — would otherwise inherit a traversal from a locator that parsed clean. Case is significant and there is no normalisation, which is a decision with no way back: two callers naming one model in two casings mint two identifiers, and adding a fold later would be a change to normalisation, which mints identifier version 2.",
|
|
170
|
+
"reference": "no published grammar names a hosted API model: Package URL registers artifact-registry namespaces only (huggingface, mlflow), CycloneDX carries the category as a component type and identifies with an ordinary purl, SPDX 3.0's AIPackage identifies by free-text name and delegates to packageUrl, and OpenTelemetry's gen_ai.request.model is explicitly free text — so this type is this specification's own, not a delegation."
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
"typeRegistry": "a type names the naming system that owns the locator grammar; an unregistered type parses to uncovered, never to malformed, and registering its validator here is what promotes it — the registry is this table. A type name MUST be one an unrelated party solving the same problem would have chosen identically: a product name fails, because claiming it is the point of it, and a short desirable word naming a general activity fails for the opposite reason, because several parties would choose it and none owns a grammar. The test refuses the fight before it starts — a registry that admits a contested name is settled by whoever is larger rather than by whoever is right. An authority the registry does not cover is named through 'unknown' with its species declared, which costs nothing and stays precise.",
|
|
174
|
+
"delegation": {
|
|
175
|
+
"type-prefixed": "the validator receives <type>:<locator> verbatim — the type token is also the delegated format's own scheme",
|
|
176
|
+
"verbatim": "the validator receives the locator alone"
|
|
177
|
+
},
|
|
178
|
+
"statuses": [
|
|
179
|
+
"ok",
|
|
180
|
+
"malformed",
|
|
181
|
+
"uncovered",
|
|
182
|
+
"unsupported"
|
|
183
|
+
],
|
|
184
|
+
"parts": [
|
|
185
|
+
"grammar",
|
|
186
|
+
"type",
|
|
187
|
+
"state",
|
|
188
|
+
"fragment",
|
|
189
|
+
"locator",
|
|
190
|
+
"member",
|
|
191
|
+
"<qualifier key>",
|
|
192
|
+
"<refinement key>"
|
|
193
|
+
],
|
|
194
|
+
"unknownType": "uncovered",
|
|
195
|
+
"roles": {
|
|
196
|
+
"identity": [
|
|
197
|
+
"type",
|
|
198
|
+
"locator",
|
|
199
|
+
"fragment.path"
|
|
151
200
|
],
|
|
152
|
-
"
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
"member",
|
|
159
|
-
"<qualifier key>",
|
|
160
|
-
"<refinement key>"
|
|
201
|
+
"cut": "the locator names the item and the fragment names one level inside it. What that level is depends on the kind of item — a folder cuts to a file, a file to a declared name inside it. Descending a level moves the previous one into the locator, so an identifier carries exactly one cut and choosing where to cut is choosing what is named.",
|
|
202
|
+
"scope": "a path inside the locator is the scope a declared name was declared in, not where the bytes sit. The scope of a heading in a document IS that document, which is why it belongs to identity; a language that gives a symbol a qualified name needs no path for the same reason.",
|
|
203
|
+
"location": [
|
|
204
|
+
"a filesystem path on one machine",
|
|
205
|
+
"a byte offset into one copy",
|
|
206
|
+
"a mirror serving the same bytes"
|
|
161
207
|
],
|
|
162
|
-
"
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
"
|
|
177
|
-
|
|
178
|
-
|
|
208
|
+
"freeze": [
|
|
209
|
+
"state"
|
|
210
|
+
],
|
|
211
|
+
"moment": [
|
|
212
|
+
"when"
|
|
213
|
+
],
|
|
214
|
+
"note": "location is how a reader reaches the bytes from OUTSIDE the identifier, and it never enters one. A refinement such as `lines=` is not location: it narrows within the cut, and it is declared, not measured."
|
|
215
|
+
},
|
|
216
|
+
"qualifiers": {
|
|
217
|
+
"state": {
|
|
218
|
+
"role": "freeze",
|
|
219
|
+
"forms": [
|
|
220
|
+
"swhid",
|
|
221
|
+
"git",
|
|
222
|
+
"content-hash",
|
|
223
|
+
"none"
|
|
224
|
+
]
|
|
225
|
+
},
|
|
226
|
+
"by": {
|
|
227
|
+
"role": "instrument",
|
|
228
|
+
"forms": [
|
|
229
|
+
"ref",
|
|
230
|
+
"sha256"
|
|
231
|
+
]
|
|
232
|
+
},
|
|
233
|
+
"over": {
|
|
234
|
+
"role": "population",
|
|
235
|
+
"forms": [
|
|
236
|
+
"ref",
|
|
237
|
+
"sha256",
|
|
238
|
+
"unknown"
|
|
239
|
+
]
|
|
240
|
+
},
|
|
241
|
+
"when": {
|
|
242
|
+
"role": "moment",
|
|
243
|
+
"forms": [
|
|
244
|
+
"rfc3339"
|
|
245
|
+
]
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"forms": {
|
|
249
|
+
"swhid": {
|
|
250
|
+
"pattern": "^swh:1:(cnt|dir|rev|rel|snp):[0-9a-f]{40}$",
|
|
251
|
+
"reference": "ISO/IEC 18670 core identifier, no SWHID qualifiers"
|
|
252
|
+
},
|
|
253
|
+
"sha256": {
|
|
254
|
+
"pattern": "^sha256:[0-9a-f]{64}$",
|
|
255
|
+
"digest": true
|
|
256
|
+
},
|
|
257
|
+
"git": {
|
|
258
|
+
"pattern": "^git:[0-9a-f]{7,40}$",
|
|
259
|
+
"reference": "a commit object name, abbreviated or full — a freeze the repository can resolve, weaker than a SWHID only in that it names no archive"
|
|
260
|
+
},
|
|
261
|
+
"content-hash": {
|
|
262
|
+
"pattern": "^(sha256|blake3):[0-9a-f]{64}$",
|
|
263
|
+
"reference": "a hash of the content itself, for what no version control holds; never a digest of members, so it declares no digest: true"
|
|
264
|
+
},
|
|
265
|
+
"none": {
|
|
266
|
+
"pattern": "^none$",
|
|
267
|
+
"reference": "the declared level for a state nobody captured — an unknown state recorded honestly, worth more than a properties hash presented as proof of content"
|
|
268
|
+
},
|
|
269
|
+
"rfc3339": {
|
|
270
|
+
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\\.[0-9]+)?Z$",
|
|
271
|
+
"reference": "RFC 3339, UTC only — a moment, never a state"
|
|
272
|
+
},
|
|
273
|
+
"ref": {
|
|
274
|
+
"nested": true,
|
|
275
|
+
"depth": 1,
|
|
276
|
+
"encoding": "nested"
|
|
277
|
+
},
|
|
278
|
+
"unknown": {
|
|
279
|
+
"pattern": "^unknown$",
|
|
280
|
+
"reference": "the declared level for a population nobody established. Deliberately not `none`, which `state` uses: a state cannot be empty, so `none` is unambiguous there, while a population over zero members is a real and different thing from a population nobody recorded — and an identifier must not let the two read alike. It is a floor, never a destination: a producer that can enumerate its population says so with `sha256`, which names which population rather than admitting there was one"
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
"refinements": {
|
|
284
|
+
"lines": {
|
|
285
|
+
"pattern": "^[0-9]+(,[0-9]+)?$",
|
|
286
|
+
"range": "ascending",
|
|
287
|
+
"boundSeparator": ",",
|
|
288
|
+
"reference": "RFC 5147 placement"
|
|
289
|
+
},
|
|
290
|
+
"item": {
|
|
291
|
+
"pattern": "^[0-9]+$"
|
|
292
|
+
},
|
|
293
|
+
"para": {
|
|
294
|
+
"pattern": "^[0-9]+$"
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
"unknownRefinement": "carry-through",
|
|
298
|
+
"resolutionStates": [
|
|
299
|
+
"resolved",
|
|
300
|
+
"unresolved",
|
|
301
|
+
"uncovered",
|
|
302
|
+
"archival"
|
|
303
|
+
],
|
|
304
|
+
"stateLevels": [
|
|
305
|
+
"properties",
|
|
306
|
+
"content-hash",
|
|
307
|
+
"none"
|
|
308
|
+
],
|
|
309
|
+
"digest": {
|
|
310
|
+
"algorithm": "sha256",
|
|
311
|
+
"over": "identifier-strings",
|
|
312
|
+
"order": "declared",
|
|
313
|
+
"join": "\n",
|
|
314
|
+
"encoding": "utf-8",
|
|
315
|
+
"dedupe": false,
|
|
316
|
+
"output": "sha256:<64 lowercase hex>"
|
|
317
|
+
},
|
|
318
|
+
"identifierEquivalence": {
|
|
319
|
+
"qualifierOrder": "insignificant",
|
|
320
|
+
"refinementOrder": "significant",
|
|
321
|
+
"canonicalForm": "re-serialise the parsed identifier with its qualifiers sorted by key in UTF-16 code unit order; every other part verbatim, refinements included",
|
|
322
|
+
"comparison": "two identifiers name one thing when their canonical forms are equal byte for byte",
|
|
323
|
+
"reserialisation": "SHOULD preserve the order written; MUST NOT be relied on to tell two identifiers apart",
|
|
324
|
+
"note": "distinct from `canonicalisation`, which is the form of THIS FILE for its own digest"
|
|
325
|
+
},
|
|
326
|
+
"comparison": {
|
|
327
|
+
"note": "two relations equality cannot express. Both are computed on the parsed parts, never on the bytes, and both refuse an identifier this grammar did not decompose: `malformed` has no parts, and a version of the scheme an implementation does not support has parts read by the wrong expression. An `uncovered` type is compared like any other — its locator's grammar is unknown, its shape is not.",
|
|
328
|
+
"dimensions": [
|
|
329
|
+
"type",
|
|
330
|
+
"version",
|
|
331
|
+
"locator stem",
|
|
332
|
+
"locator version",
|
|
333
|
+
"fragment path",
|
|
334
|
+
"fragment refinements",
|
|
335
|
+
"qualifiers"
|
|
336
|
+
],
|
|
337
|
+
"samePackage": {
|
|
338
|
+
"symmetry": "symmetric",
|
|
339
|
+
"rule": "every dimension is compared identically except the locator version, which is ignored. A locator carries a version only where its type declares `versionTail`; elsewhere an @ belongs to the format and is part of the stem. Where a version is carried, an @ that opens a segment is a namespace and an @ inside a segment closes the name — the version runs to the next /, and the path after it stays in the stem, because one file at two releases is one file.",
|
|
340
|
+
"purpose": "whether two identifiers name the same released thing at whatever version each declares. Only a type declaring `versionTail` has a version dimension at all — three of the nine do — so for every other type this relation is equality, and its name is borrowed from the type that motivated it."
|
|
341
|
+
},
|
|
342
|
+
"covers": {
|
|
343
|
+
"symmetry": "asymmetric — the general covers the specific, and the specific does not cover the general",
|
|
344
|
+
"rule": "the type and the scheme version must be equal, and the general locator stem must reach the specific one — equal, or a whole segment prefix of it, so a corpus reaches the files under it and never a sibling whose name merely begins with the same characters. For the locator version, the fragment path, each fragment refinement and each qualifier: what the first leaves undeclared, the second may declare freely; what the first declares, the second must declare identically.",
|
|
345
|
+
"purpose": "a partial identifier is a query — a store keyed by identifier answers a family by asking which of its keys the partial one covers",
|
|
346
|
+
"reflexive": "every identifier this relation accepts covers itself"
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
"canonicalisation": {
|
|
350
|
+
"form": "json-sorted-keys-compact",
|
|
351
|
+
"rules": [
|
|
352
|
+
"object keys sorted by UTF-16 code unit order",
|
|
353
|
+
"no whitespace outside strings",
|
|
354
|
+
"strings escaped as JSON.stringify does",
|
|
355
|
+
"numbers are integers only",
|
|
356
|
+
"UTF-8 bytes of the result are what the digest covers"
|
|
357
|
+
],
|
|
358
|
+
"sidecar": "ref-id.json.sha256 holds the digest of this file; the file never contains its own digest"
|
|
359
|
+
},
|
|
360
|
+
"envelope": {
|
|
361
|
+
"fields": {
|
|
362
|
+
"id": "required",
|
|
363
|
+
"sets": "required when the identifier carries a digest",
|
|
364
|
+
"alsoKnownAs": "optional, a declaration never a similarity match",
|
|
365
|
+
"data": "opaque"
|
|
179
366
|
},
|
|
180
|
-
"
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
367
|
+
"selfReference": "id",
|
|
368
|
+
"setsField": "sets",
|
|
369
|
+
"digestForms": "every form declaring digest: true",
|
|
370
|
+
"invariant": "for every qualifier whose value is a digest, sets[qualifier] exists and digest(sets[qualifier]) equals it; and id equals the identifier the envelope was requested under",
|
|
371
|
+
"onFailure": "refuse at ingestion"
|
|
372
|
+
},
|
|
373
|
+
"vectors": {
|
|
374
|
+
"parse": [
|
|
375
|
+
{
|
|
376
|
+
"name": "pkg with declared name",
|
|
377
|
+
"input": "ref:pkg:npm/@acme/scanner-core@0.1.0#Observation",
|
|
378
|
+
"expect": {
|
|
379
|
+
"status": "ok",
|
|
380
|
+
"version": 1,
|
|
381
|
+
"qualifiers": [],
|
|
382
|
+
"fragment": {
|
|
383
|
+
"path": "Observation",
|
|
384
|
+
"refinements": []
|
|
385
|
+
},
|
|
386
|
+
"type": "pkg",
|
|
387
|
+
"locator": "npm/@acme/scanner-core@0.1.0",
|
|
388
|
+
"delegated": "pkg:npm/@acme/scanner-core@0.1.0"
|
|
389
|
+
}
|
|
390
|
+
},
|
|
391
|
+
{
|
|
392
|
+
"name": "pkg with versioned declared-name path",
|
|
393
|
+
"input": "ref:pkg:npm/@acme/trait-citation-fidelity@0.0.1#citation-fidelity@1/not-invented",
|
|
394
|
+
"expect": {
|
|
395
|
+
"status": "ok",
|
|
396
|
+
"version": 1,
|
|
397
|
+
"qualifiers": [],
|
|
398
|
+
"fragment": {
|
|
399
|
+
"path": "citation-fidelity@1/not-invented",
|
|
400
|
+
"refinements": []
|
|
401
|
+
},
|
|
402
|
+
"type": "pkg",
|
|
403
|
+
"locator": "npm/@acme/trait-citation-fidelity@0.0.1"
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
"name": "folder corpus with declared name",
|
|
408
|
+
"input": "ref:folder:acme-governance#learnings/a-chunk-carrying-no-answer-means-death-or-health",
|
|
409
|
+
"expect": {
|
|
410
|
+
"status": "ok",
|
|
411
|
+
"version": 1,
|
|
412
|
+
"qualifiers": [],
|
|
413
|
+
"fragment": {
|
|
414
|
+
"path": "learnings/a-chunk-carrying-no-answer-means-death-or-health",
|
|
415
|
+
"refinements": []
|
|
416
|
+
},
|
|
417
|
+
"type": "folder",
|
|
418
|
+
"locator": "acme-governance"
|
|
419
|
+
}
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
"name": "folder with state and by digest",
|
|
423
|
+
"input": "ref:folder:acme-tools;state=swh:1:rev:7e29bb6000000000000000000000000000000000;by=sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
424
|
+
"expect": {
|
|
425
|
+
"status": "ok",
|
|
426
|
+
"version": 1,
|
|
427
|
+
"qualifiers": [
|
|
428
|
+
[
|
|
429
|
+
"state",
|
|
430
|
+
"swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
431
|
+
],
|
|
432
|
+
[
|
|
433
|
+
"by",
|
|
434
|
+
"sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
188
435
|
]
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
436
|
+
],
|
|
437
|
+
"fragment": null,
|
|
438
|
+
"type": "folder",
|
|
439
|
+
"locator": "acme-tools"
|
|
440
|
+
}
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
"name": "explicit version 1 is version 1",
|
|
444
|
+
"input": "ref:1:pkg:npm/x@1.0.0",
|
|
445
|
+
"expect": {
|
|
446
|
+
"status": "ok",
|
|
447
|
+
"version": 1,
|
|
448
|
+
"qualifiers": [],
|
|
449
|
+
"fragment": null,
|
|
450
|
+
"type": "pkg",
|
|
451
|
+
"locator": "npm/x@1.0.0",
|
|
452
|
+
"delegated": "pkg:npm/x@1.0.0",
|
|
453
|
+
"explicitVersion": true
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
"name": "version outside the supported range is unsupported, not malformed",
|
|
458
|
+
"input": "ref:2:pkg:npm/x@1.0.0",
|
|
459
|
+
"expect": {
|
|
460
|
+
"status": "unsupported",
|
|
461
|
+
"version": 2,
|
|
462
|
+
"type": "pkg",
|
|
463
|
+
"locator": "npm/x@1.0.0"
|
|
464
|
+
}
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
"name": "letter-led token is a type, not a version",
|
|
468
|
+
"input": "ref:v2:pkg:npm/x",
|
|
469
|
+
"expect": {
|
|
470
|
+
"status": "uncovered",
|
|
471
|
+
"version": 1,
|
|
472
|
+
"type": "v2",
|
|
473
|
+
"locator": "pkg:npm/x"
|
|
474
|
+
}
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
"name": "unknown type is uncovered, never an exception",
|
|
478
|
+
"input": "ref:doi:10.1000/182",
|
|
479
|
+
"expect": {
|
|
480
|
+
"status": "uncovered",
|
|
481
|
+
"version": 1,
|
|
482
|
+
"type": "doi",
|
|
483
|
+
"locator": "10.1000/182"
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
{
|
|
487
|
+
"name": "unknown qualifier key is carried through",
|
|
488
|
+
"input": "ref:folder:acme-tools;zz=1;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
489
|
+
"expect": {
|
|
490
|
+
"status": "ok",
|
|
491
|
+
"version": 1,
|
|
492
|
+
"qualifiers": [
|
|
493
|
+
[
|
|
494
|
+
"zz",
|
|
495
|
+
"1"
|
|
496
|
+
],
|
|
497
|
+
[
|
|
498
|
+
"state",
|
|
499
|
+
"swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
195
500
|
]
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
501
|
+
],
|
|
502
|
+
"fragment": null,
|
|
503
|
+
"type": "folder",
|
|
504
|
+
"locator": "acme-tools"
|
|
505
|
+
}
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
"name": "nested by carrying a fragment",
|
|
509
|
+
"input": "ref:folder:acme-tools;by=ref:pkg:npm/@acme/profiles@0.1.0%23profile/conformance@1",
|
|
510
|
+
"expect": {
|
|
511
|
+
"status": "ok",
|
|
512
|
+
"version": 1,
|
|
513
|
+
"qualifiers": [
|
|
514
|
+
[
|
|
515
|
+
"by",
|
|
516
|
+
"ref:pkg:npm/@acme/profiles@0.1.0%23profile/conformance@1"
|
|
203
517
|
]
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
518
|
+
],
|
|
519
|
+
"fragment": null,
|
|
520
|
+
"type": "folder",
|
|
521
|
+
"locator": "acme-tools",
|
|
522
|
+
"nested": {
|
|
523
|
+
"by": "ref:pkg:npm/@acme/profiles@0.1.0#profile/conformance@1"
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
{
|
|
528
|
+
"name": "nested by carrying its own qualifier",
|
|
529
|
+
"input": "ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000%23S",
|
|
530
|
+
"expect": {
|
|
531
|
+
"status": "ok",
|
|
532
|
+
"version": 1,
|
|
533
|
+
"qualifiers": [
|
|
534
|
+
[
|
|
535
|
+
"by",
|
|
536
|
+
"ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000%23S"
|
|
209
537
|
]
|
|
538
|
+
],
|
|
539
|
+
"fragment": null,
|
|
540
|
+
"type": "folder",
|
|
541
|
+
"locator": "acme-tools",
|
|
542
|
+
"nested": {
|
|
543
|
+
"by": "ref:pkg:npm/x@1.0.0;state=swh:1:rev:7e29bb6000000000000000000000000000000000#S"
|
|
544
|
+
}
|
|
210
545
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
"
|
|
214
|
-
|
|
215
|
-
|
|
546
|
+
},
|
|
547
|
+
{
|
|
548
|
+
"name": "two different nested values are two different identifiers",
|
|
549
|
+
"input": "ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
550
|
+
"expect": {
|
|
551
|
+
"status": "ok",
|
|
552
|
+
"version": 1,
|
|
553
|
+
"qualifiers": [
|
|
554
|
+
[
|
|
555
|
+
"by",
|
|
556
|
+
"ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
557
|
+
]
|
|
558
|
+
],
|
|
559
|
+
"fragment": null,
|
|
560
|
+
"type": "folder",
|
|
561
|
+
"locator": "acme-tools",
|
|
562
|
+
"nested": {
|
|
563
|
+
"by": "ref:pkg:npm/x@1.0.0;state=swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
{
|
|
568
|
+
"name": "a purl keeps its own percent-encoding intact",
|
|
569
|
+
"input": "ref:pkg:npm/%40acme/x@1.0.0#S",
|
|
570
|
+
"expect": {
|
|
571
|
+
"status": "ok",
|
|
572
|
+
"version": 1,
|
|
573
|
+
"qualifiers": [],
|
|
574
|
+
"fragment": {
|
|
575
|
+
"path": "S",
|
|
576
|
+
"refinements": []
|
|
577
|
+
},
|
|
578
|
+
"type": "pkg",
|
|
579
|
+
"locator": "npm/%40acme/x@1.0.0",
|
|
580
|
+
"delegated": "pkg:npm/%40acme/x@1.0.0"
|
|
581
|
+
}
|
|
582
|
+
},
|
|
583
|
+
{
|
|
584
|
+
"name": "an identifier is one line",
|
|
585
|
+
"input": "ref:folder:acme-tools\nx",
|
|
586
|
+
"expect": {
|
|
587
|
+
"status": "malformed",
|
|
588
|
+
"part": "grammar"
|
|
589
|
+
}
|
|
590
|
+
},
|
|
591
|
+
{
|
|
592
|
+
"name": "nesting deeper than one level is malformed",
|
|
593
|
+
"input": "ref:folder:b;by=ref:folder:a%3Bby=ref:pkg:npm/x@1.0.0%2523S",
|
|
594
|
+
"expect": {
|
|
595
|
+
"status": "malformed",
|
|
596
|
+
"part": "by"
|
|
597
|
+
}
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
"name": "a reversed line range is malformed",
|
|
601
|
+
"input": "ref:folder:acme-tools#AGENTS.md;lines=20,10",
|
|
602
|
+
"expect": {
|
|
603
|
+
"status": "malformed",
|
|
604
|
+
"part": "lines"
|
|
605
|
+
}
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
"name": "an unknown key keeps an encoded separator in its value",
|
|
609
|
+
"input": "ref:folder:acme-tools;zz=a%3Bb;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
610
|
+
"expect": {
|
|
611
|
+
"status": "ok",
|
|
612
|
+
"version": 1,
|
|
613
|
+
"qualifiers": [
|
|
614
|
+
[
|
|
615
|
+
"zz",
|
|
616
|
+
"a%3Bb"
|
|
617
|
+
],
|
|
618
|
+
[
|
|
619
|
+
"state",
|
|
620
|
+
"swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
621
|
+
]
|
|
622
|
+
],
|
|
623
|
+
"fragment": null,
|
|
624
|
+
"type": "folder",
|
|
625
|
+
"locator": "acme-tools"
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
{
|
|
629
|
+
"name": "refinement after the declared-name path",
|
|
630
|
+
"input": "ref:folder:acme-tools#AGENTS.md;lines=10,20",
|
|
631
|
+
"expect": {
|
|
632
|
+
"status": "ok",
|
|
633
|
+
"version": 1,
|
|
634
|
+
"qualifiers": [],
|
|
635
|
+
"fragment": {
|
|
636
|
+
"path": "AGENTS.md",
|
|
637
|
+
"refinements": [
|
|
638
|
+
[
|
|
639
|
+
"lines",
|
|
640
|
+
"10,20"
|
|
641
|
+
]
|
|
642
|
+
]
|
|
643
|
+
},
|
|
644
|
+
"type": "folder",
|
|
645
|
+
"locator": "acme-tools"
|
|
646
|
+
}
|
|
647
|
+
},
|
|
648
|
+
{
|
|
649
|
+
"name": "qualifier before the hash, refinement after it",
|
|
650
|
+
"input": "ref:folder:acme-tools;state=swh:1:cnt:3404a00f00000000000000000000000000000000#AGENTS.md;lines=1",
|
|
651
|
+
"expect": {
|
|
652
|
+
"status": "ok",
|
|
653
|
+
"version": 1,
|
|
654
|
+
"qualifiers": [
|
|
655
|
+
[
|
|
656
|
+
"state",
|
|
657
|
+
"swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
658
|
+
]
|
|
659
|
+
],
|
|
660
|
+
"fragment": {
|
|
661
|
+
"path": "AGENTS.md",
|
|
662
|
+
"refinements": [
|
|
663
|
+
[
|
|
664
|
+
"lines",
|
|
665
|
+
"1"
|
|
666
|
+
]
|
|
667
|
+
]
|
|
668
|
+
},
|
|
669
|
+
"type": "folder",
|
|
670
|
+
"locator": "acme-tools"
|
|
671
|
+
}
|
|
672
|
+
},
|
|
673
|
+
{
|
|
674
|
+
"name": "unknown refinement key is carried through",
|
|
675
|
+
"input": "ref:folder:acme-tools#AGENTS.md;zz=q",
|
|
676
|
+
"expect": {
|
|
677
|
+
"status": "ok",
|
|
678
|
+
"version": 1,
|
|
679
|
+
"qualifiers": [],
|
|
680
|
+
"fragment": {
|
|
681
|
+
"path": "AGENTS.md",
|
|
682
|
+
"refinements": [
|
|
683
|
+
[
|
|
684
|
+
"zz",
|
|
685
|
+
"q"
|
|
686
|
+
]
|
|
687
|
+
]
|
|
688
|
+
},
|
|
689
|
+
"type": "folder",
|
|
690
|
+
"locator": "acme-tools"
|
|
691
|
+
}
|
|
692
|
+
},
|
|
693
|
+
{
|
|
694
|
+
"name": "over as a digest",
|
|
695
|
+
"input": "ref:folder:acme-tools;over=sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
696
|
+
"expect": {
|
|
697
|
+
"status": "ok",
|
|
698
|
+
"version": 1,
|
|
699
|
+
"qualifiers": [
|
|
700
|
+
[
|
|
701
|
+
"over",
|
|
702
|
+
"sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
703
|
+
]
|
|
704
|
+
],
|
|
705
|
+
"fragment": null,
|
|
706
|
+
"type": "folder",
|
|
707
|
+
"locator": "acme-tools"
|
|
708
|
+
}
|
|
709
|
+
},
|
|
710
|
+
{
|
|
711
|
+
"name": "a validator failure outranks an unknown type",
|
|
712
|
+
"input": "ref:doi:10.1000/182;state=swh:1:rev:7e29bb6",
|
|
713
|
+
"expect": {
|
|
714
|
+
"status": "malformed",
|
|
715
|
+
"part": "state"
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
{
|
|
719
|
+
"name": "an unsupported version is not validated further",
|
|
720
|
+
"input": "ref:2:pkg:npm/x@1.0.0;state=swh:1:rev:7e29bb6",
|
|
721
|
+
"expect": {
|
|
722
|
+
"status": "unsupported",
|
|
723
|
+
"version": 2,
|
|
724
|
+
"type": "pkg",
|
|
725
|
+
"locator": "npm/x@1.0.0",
|
|
726
|
+
"qualifiers": [
|
|
727
|
+
[
|
|
728
|
+
"state",
|
|
729
|
+
"swh:1:rev:7e29bb6"
|
|
730
|
+
]
|
|
731
|
+
]
|
|
732
|
+
}
|
|
733
|
+
},
|
|
734
|
+
{
|
|
735
|
+
"name": "an uncovered type still carries its qualifiers and fragment",
|
|
736
|
+
"input": "ref:doi:10.1000/182;state=swh:1:rev:7e29bb6000000000000000000000000000000000#S",
|
|
737
|
+
"expect": {
|
|
738
|
+
"status": "uncovered",
|
|
739
|
+
"version": 1,
|
|
740
|
+
"type": "doi",
|
|
741
|
+
"locator": "10.1000/182",
|
|
742
|
+
"qualifiers": [
|
|
743
|
+
[
|
|
744
|
+
"state",
|
|
745
|
+
"swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
746
|
+
]
|
|
747
|
+
],
|
|
748
|
+
"fragment": {
|
|
749
|
+
"path": "S",
|
|
750
|
+
"refinements": []
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
},
|
|
754
|
+
{
|
|
755
|
+
"name": "percent in a nested value is itself encoded",
|
|
756
|
+
"input": "ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%2523src/y",
|
|
757
|
+
"expect": {
|
|
758
|
+
"status": "ok",
|
|
759
|
+
"version": 1,
|
|
760
|
+
"qualifiers": [
|
|
761
|
+
[
|
|
762
|
+
"by",
|
|
763
|
+
"ref:pkg:npm/x@1.0.0%2523src/y"
|
|
764
|
+
]
|
|
765
|
+
],
|
|
766
|
+
"fragment": null,
|
|
767
|
+
"type": "folder",
|
|
768
|
+
"locator": "acme-tools",
|
|
769
|
+
"nested": {
|
|
770
|
+
"by": "ref:pkg:npm/x@1.0.0%23src/y"
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
},
|
|
774
|
+
{
|
|
775
|
+
"name": "empty fragment is malformed",
|
|
776
|
+
"input": "ref:folder:acme-tools#",
|
|
777
|
+
"expect": {
|
|
778
|
+
"status": "malformed",
|
|
779
|
+
"part": "fragment"
|
|
780
|
+
}
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
"name": "empty qualifier is malformed",
|
|
784
|
+
"input": "ref:folder:acme-tools;",
|
|
785
|
+
"expect": {
|
|
786
|
+
"status": "malformed",
|
|
787
|
+
"part": "state"
|
|
788
|
+
}
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
"name": "qualifier without a value separator is malformed",
|
|
792
|
+
"input": "ref:folder:acme-tools;at",
|
|
793
|
+
"expect": {
|
|
794
|
+
"status": "malformed",
|
|
795
|
+
"part": "state"
|
|
796
|
+
}
|
|
797
|
+
},
|
|
798
|
+
{
|
|
799
|
+
"name": "a nested value that is not a ref and not a digest fails the by validator",
|
|
800
|
+
"input": "ref:folder:acme-tools;by=rumdl",
|
|
801
|
+
"expect": {
|
|
802
|
+
"status": "malformed",
|
|
803
|
+
"part": "by"
|
|
804
|
+
}
|
|
805
|
+
},
|
|
806
|
+
{
|
|
807
|
+
"name": "a refinement key on the qualifier side is malformed",
|
|
808
|
+
"input": "ref:folder:acme-tools;lines=1#AGENTS.md",
|
|
809
|
+
"expect": {
|
|
810
|
+
"status": "malformed",
|
|
811
|
+
"part": "lines"
|
|
812
|
+
}
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
"name": "a qualifier key on the fragment side is malformed",
|
|
816
|
+
"input": "ref:folder:acme-tools#AGENTS.md;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
817
|
+
"expect": {
|
|
818
|
+
"status": "malformed",
|
|
819
|
+
"part": "state"
|
|
820
|
+
}
|
|
821
|
+
},
|
|
822
|
+
{
|
|
823
|
+
"name": "an empty path before a refinement is malformed",
|
|
824
|
+
"input": "ref:folder:acme-tools#;lines=1",
|
|
825
|
+
"expect": {
|
|
826
|
+
"status": "malformed",
|
|
827
|
+
"part": "fragment"
|
|
828
|
+
}
|
|
829
|
+
},
|
|
830
|
+
{
|
|
831
|
+
"name": "a nested identifier of an unsupported version is carried, not rejected",
|
|
832
|
+
"input": "ref:folder:acme-tools;by=ref:2:pkg:npm/x@1.0.0",
|
|
833
|
+
"expect": {
|
|
834
|
+
"status": "ok",
|
|
835
|
+
"version": 1,
|
|
836
|
+
"qualifiers": [
|
|
837
|
+
[
|
|
838
|
+
"by",
|
|
839
|
+
"ref:2:pkg:npm/x@1.0.0"
|
|
840
|
+
]
|
|
841
|
+
],
|
|
842
|
+
"fragment": null,
|
|
843
|
+
"type": "folder",
|
|
844
|
+
"locator": "acme-tools",
|
|
845
|
+
"nested": {
|
|
846
|
+
"by": "ref:2:pkg:npm/x@1.0.0"
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
},
|
|
850
|
+
{
|
|
851
|
+
"name": "a version token round-trips as written",
|
|
852
|
+
"input": "ref:01:pkg:npm/x@1.0.0",
|
|
853
|
+
"expect": {
|
|
854
|
+
"status": "ok",
|
|
855
|
+
"version": 1,
|
|
856
|
+
"qualifiers": [],
|
|
857
|
+
"fragment": null,
|
|
858
|
+
"type": "pkg",
|
|
859
|
+
"locator": "npm/x@1.0.0",
|
|
860
|
+
"explicitVersion": true,
|
|
861
|
+
"versionText": "01"
|
|
862
|
+
}
|
|
863
|
+
},
|
|
864
|
+
{
|
|
865
|
+
"name": "a trailing line break is malformed in every engine",
|
|
866
|
+
"input": "ref:folder:acme-tools\n",
|
|
867
|
+
"expect": {
|
|
868
|
+
"status": "malformed",
|
|
869
|
+
"part": "grammar"
|
|
870
|
+
}
|
|
871
|
+
},
|
|
872
|
+
{
|
|
873
|
+
"name": "a repeated qualifier key is malformed at that key",
|
|
874
|
+
"input": "ref:folder:acme-tools;state=swh:1:rev:7e29bb6000000000000000000000000000000000;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
875
|
+
"expect": {
|
|
876
|
+
"status": "malformed",
|
|
877
|
+
"part": "state"
|
|
878
|
+
}
|
|
879
|
+
},
|
|
880
|
+
{
|
|
881
|
+
"name": "a repeated refinement key is malformed at that key",
|
|
882
|
+
"input": "ref:folder:acme-tools#AGENTS.md;lines=1;lines=2",
|
|
883
|
+
"expect": {
|
|
884
|
+
"status": "malformed",
|
|
885
|
+
"part": "lines"
|
|
886
|
+
}
|
|
887
|
+
},
|
|
888
|
+
{
|
|
889
|
+
"name": "a raw percent in a nested value is malformed at the key",
|
|
890
|
+
"input": "ref:folder:acme-tools;by=ref:pkg:npm/%40acme/x@1.0.0",
|
|
891
|
+
"expect": {
|
|
892
|
+
"status": "malformed",
|
|
893
|
+
"part": "by"
|
|
894
|
+
}
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
"name": "a nested value carries the inner percent-encoding doubled",
|
|
898
|
+
"input": "ref:folder:acme-tools;by=ref:pkg:npm/%2540acme/x@1.0.0",
|
|
899
|
+
"expect": {
|
|
900
|
+
"status": "ok",
|
|
901
|
+
"version": 1,
|
|
902
|
+
"qualifiers": [
|
|
903
|
+
[
|
|
904
|
+
"by",
|
|
905
|
+
"ref:pkg:npm/%2540acme/x@1.0.0"
|
|
906
|
+
]
|
|
907
|
+
],
|
|
908
|
+
"fragment": null,
|
|
909
|
+
"type": "folder",
|
|
910
|
+
"locator": "acme-tools",
|
|
911
|
+
"nested": {
|
|
912
|
+
"by": "ref:pkg:npm/%40acme/x@1.0.0"
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
"name": "when carries a moment in UTC",
|
|
918
|
+
"input": "ref:pkg:npm/@acme/scanner-core;when=2026-08-12T18:55:27.811Z#governance@0.0.1/markdown-link",
|
|
919
|
+
"expect": {
|
|
920
|
+
"status": "ok",
|
|
921
|
+
"version": 1,
|
|
922
|
+
"qualifiers": [
|
|
923
|
+
[
|
|
924
|
+
"when",
|
|
925
|
+
"2026-08-12T18:55:27.811Z"
|
|
926
|
+
]
|
|
927
|
+
],
|
|
928
|
+
"fragment": {
|
|
929
|
+
"path": "governance@0.0.1/markdown-link",
|
|
930
|
+
"refinements": []
|
|
931
|
+
},
|
|
932
|
+
"type": "pkg",
|
|
933
|
+
"locator": "npm/@acme/scanner-core",
|
|
934
|
+
"delegated": "pkg:npm/@acme/scanner-core"
|
|
935
|
+
}
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
"name": "a moment with an offset is malformed at when",
|
|
939
|
+
"input": "ref:folder:acme-tools;when=2026-08-12T15:55:27-03:00",
|
|
940
|
+
"expect": {
|
|
941
|
+
"status": "malformed",
|
|
942
|
+
"part": "when"
|
|
943
|
+
}
|
|
944
|
+
},
|
|
945
|
+
{
|
|
946
|
+
"name": "a typed governed-record fragment on an unversioned package corpus",
|
|
947
|
+
"input": "ref:pkg:npm/acme-tools#acme/adr@2/0019",
|
|
948
|
+
"expect": {
|
|
949
|
+
"status": "ok",
|
|
950
|
+
"version": 1,
|
|
951
|
+
"qualifiers": [],
|
|
952
|
+
"fragment": {
|
|
953
|
+
"path": "acme/adr@2/0019",
|
|
954
|
+
"refinements": []
|
|
955
|
+
},
|
|
956
|
+
"type": "pkg",
|
|
957
|
+
"locator": "npm/acme-tools",
|
|
958
|
+
"delegated": "pkg:npm/acme-tools"
|
|
959
|
+
}
|
|
960
|
+
},
|
|
961
|
+
{
|
|
962
|
+
"name": "an agent named by no authority carries the name alone, under unknown",
|
|
963
|
+
"input": "ref:unknown:MentorUniversitario@1.4.1",
|
|
964
|
+
"expect": {
|
|
965
|
+
"status": "ok",
|
|
966
|
+
"version": 1,
|
|
967
|
+
"qualifiers": [],
|
|
968
|
+
"fragment": null,
|
|
969
|
+
"type": "unknown",
|
|
970
|
+
"locator": "MentorUniversitario@1.4.1"
|
|
971
|
+
}
|
|
972
|
+
},
|
|
973
|
+
{
|
|
974
|
+
"name": "an agent named by its host, its digest carried by state",
|
|
975
|
+
"input": "ref:url:acme.example/doctor@v1.0;state=git:a1b2c3d4",
|
|
976
|
+
"expect": {
|
|
977
|
+
"status": "ok",
|
|
978
|
+
"version": 1,
|
|
979
|
+
"qualifiers": [
|
|
980
|
+
[
|
|
981
|
+
"state",
|
|
982
|
+
"git:a1b2c3d4"
|
|
983
|
+
]
|
|
984
|
+
],
|
|
985
|
+
"fragment": null,
|
|
986
|
+
"type": "url",
|
|
987
|
+
"locator": "acme.example/doctor@v1.0"
|
|
988
|
+
}
|
|
989
|
+
},
|
|
990
|
+
{
|
|
991
|
+
"name": "a platform vouching for a user is two segments under the host",
|
|
992
|
+
"input": "ref:url:github.example/someone/doctor",
|
|
993
|
+
"expect": {
|
|
994
|
+
"status": "ok",
|
|
995
|
+
"version": 1,
|
|
996
|
+
"qualifiers": [],
|
|
997
|
+
"fragment": null,
|
|
998
|
+
"type": "url",
|
|
999
|
+
"locator": "github.example/someone/doctor"
|
|
1000
|
+
}
|
|
1001
|
+
},
|
|
1002
|
+
{
|
|
1003
|
+
"name": "a segment refuses the colon, so a name carrying its own version is not absorbed whole",
|
|
1004
|
+
"input": "ref:url:acme.example/doctor:v1.0",
|
|
1005
|
+
"expect": {
|
|
1006
|
+
"status": "malformed",
|
|
1007
|
+
"part": "locator"
|
|
1008
|
+
}
|
|
1009
|
+
},
|
|
1010
|
+
{
|
|
1011
|
+
"name": "a retired type degrades to uncovered — an identifier written against it keeps its parts",
|
|
1012
|
+
"input": "ref:dot-agent:acme.example/doctor:v1.0",
|
|
1013
|
+
"expect": {
|
|
1014
|
+
"status": "uncovered",
|
|
1015
|
+
"version": 1,
|
|
1016
|
+
"qualifiers": [],
|
|
1017
|
+
"fragment": null,
|
|
1018
|
+
"type": "dot-agent",
|
|
1019
|
+
"locator": "acme.example/doctor:v1.0"
|
|
1020
|
+
}
|
|
1021
|
+
},
|
|
1022
|
+
{
|
|
1023
|
+
"name": "a dotted host needs no registry to parse — whether it resolves is the ecosystem's check, never the grammar's",
|
|
1024
|
+
"input": "ref:url:mentor.pessoal.agent/MentorUniversitario@1.4.1",
|
|
1025
|
+
"expect": {
|
|
1026
|
+
"status": "ok",
|
|
1027
|
+
"version": 1,
|
|
1028
|
+
"qualifiers": [],
|
|
1029
|
+
"fragment": null,
|
|
1030
|
+
"type": "url",
|
|
1031
|
+
"locator": "mentor.pessoal.agent/MentorUniversitario@1.4.1"
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
{
|
|
1035
|
+
"name": "a tilde opens a segment — a platform whose usernames carry one needs no exception",
|
|
1036
|
+
"input": "ref:url:sr.ht/~reykjalin/fonn@v1.0",
|
|
1037
|
+
"expect": {
|
|
1038
|
+
"status": "ok",
|
|
1039
|
+
"version": 1,
|
|
1040
|
+
"qualifiers": [],
|
|
1041
|
+
"fragment": null,
|
|
1042
|
+
"type": "url",
|
|
1043
|
+
"locator": "sr.ht/~reykjalin/fonn@v1.0"
|
|
1044
|
+
}
|
|
1045
|
+
},
|
|
1046
|
+
{
|
|
1047
|
+
"name": "an opaque value minted by a product is named by that product, with the value as the declared name",
|
|
1048
|
+
"input": "ref:url:entelekheia.example/app#550e8400-e29b-41d4-a716-446655440000",
|
|
1049
|
+
"expect": {
|
|
1050
|
+
"status": "ok",
|
|
1051
|
+
"version": 1,
|
|
1052
|
+
"qualifiers": [],
|
|
1053
|
+
"type": "url",
|
|
1054
|
+
"locator": "entelekheia.example/app",
|
|
1055
|
+
"fragment": {
|
|
1056
|
+
"path": "550e8400-e29b-41d4-a716-446655440000",
|
|
1057
|
+
"refinements": []
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
},
|
|
1061
|
+
{
|
|
1062
|
+
"name": "unknown carries its species, so an uncovered authority is still named precisely",
|
|
1063
|
+
"input": "ref:unknown:doi:10.1000/182",
|
|
1064
|
+
"expect": {
|
|
1065
|
+
"status": "ok",
|
|
1066
|
+
"version": 1,
|
|
1067
|
+
"qualifiers": [],
|
|
1068
|
+
"fragment": null,
|
|
1069
|
+
"type": "unknown",
|
|
1070
|
+
"locator": "doi:10.1000/182"
|
|
1071
|
+
}
|
|
1072
|
+
},
|
|
1073
|
+
{
|
|
1074
|
+
"name": "a species is lowercase, so one naming system has one spelling under unknown",
|
|
1075
|
+
"input": "ref:unknown:DOI:10.1000/182",
|
|
1076
|
+
"expect": {
|
|
1077
|
+
"status": "malformed",
|
|
1078
|
+
"part": "locator"
|
|
1079
|
+
}
|
|
1080
|
+
},
|
|
1081
|
+
{
|
|
1082
|
+
"name": "a species with nothing under it names no thing",
|
|
1083
|
+
"input": "ref:unknown:doi:",
|
|
1084
|
+
"expect": {
|
|
1085
|
+
"status": "malformed",
|
|
1086
|
+
"part": "locator"
|
|
1087
|
+
}
|
|
1088
|
+
},
|
|
1089
|
+
{
|
|
1090
|
+
"name": "a species inside unknown may itself be a naming system this registry once carried",
|
|
1091
|
+
"input": "ref:unknown:dot-agent:doctor@v1.0",
|
|
1092
|
+
"expect": {
|
|
1093
|
+
"status": "ok",
|
|
1094
|
+
"version": 1,
|
|
1095
|
+
"qualifiers": [],
|
|
1096
|
+
"fragment": null,
|
|
1097
|
+
"type": "unknown",
|
|
1098
|
+
"locator": "dot-agent:doctor@v1.0"
|
|
1099
|
+
}
|
|
1100
|
+
},
|
|
1101
|
+
{
|
|
1102
|
+
"name": "a telephone number is the global form of E.164, and the leading + is required",
|
|
1103
|
+
"input": "ref:tel:+5511999999999",
|
|
1104
|
+
"expect": {
|
|
1105
|
+
"status": "ok",
|
|
1106
|
+
"version": 1,
|
|
1107
|
+
"qualifiers": [],
|
|
1108
|
+
"fragment": null,
|
|
1109
|
+
"type": "tel",
|
|
1110
|
+
"locator": "+5511999999999"
|
|
1111
|
+
}
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
"name": "a telephone number without its + is a different spelling of the same number, and only one spelling is an identifier",
|
|
1115
|
+
"input": "ref:tel:5511999999999",
|
|
1116
|
+
"expect": {
|
|
1117
|
+
"status": "malformed",
|
|
1118
|
+
"part": "locator"
|
|
1119
|
+
}
|
|
1120
|
+
},
|
|
1121
|
+
{
|
|
1122
|
+
"name": "visual separators are legal in the standard and refused here — a locator reaches its validator verbatim",
|
|
1123
|
+
"input": "ref:tel:+1-201-555-0123",
|
|
1124
|
+
"expect": {
|
|
1125
|
+
"status": "malformed",
|
|
1126
|
+
"part": "locator"
|
|
1127
|
+
}
|
|
1128
|
+
},
|
|
1129
|
+
{
|
|
1130
|
+
"name": "a thirteen-digit book number carries a check digit that is computed, not matched",
|
|
1131
|
+
"input": "ref:isbn:9780262033848",
|
|
1132
|
+
"expect": {
|
|
1133
|
+
"status": "ok",
|
|
1134
|
+
"version": 1,
|
|
1135
|
+
"qualifiers": [],
|
|
1136
|
+
"fragment": null,
|
|
1137
|
+
"type": "isbn",
|
|
1138
|
+
"locator": "9780262033848"
|
|
1139
|
+
}
|
|
1140
|
+
},
|
|
1141
|
+
{
|
|
1142
|
+
"name": "the ten-digit form admits X for the value ten in its check digit",
|
|
1143
|
+
"input": "ref:isbn:080442957X",
|
|
1144
|
+
"expect": {
|
|
1145
|
+
"status": "ok",
|
|
1146
|
+
"version": 1,
|
|
1147
|
+
"qualifiers": [],
|
|
1148
|
+
"fragment": null,
|
|
1149
|
+
"type": "isbn",
|
|
1150
|
+
"locator": "080442957X"
|
|
1151
|
+
}
|
|
1152
|
+
},
|
|
1153
|
+
{
|
|
1154
|
+
"name": "a book number of the right shape and the wrong check digit is a typo, which a pattern alone cannot see",
|
|
1155
|
+
"input": "ref:isbn:9780262033847",
|
|
1156
|
+
"expect": {
|
|
1157
|
+
"status": "malformed",
|
|
1158
|
+
"part": "locator"
|
|
1159
|
+
}
|
|
1160
|
+
},
|
|
1161
|
+
{
|
|
1162
|
+
"name": "a trade item number is the number a retail barcode carries, in any of its four registered lengths",
|
|
1163
|
+
"input": "ref:gtin:036000291452",
|
|
1164
|
+
"expect": {
|
|
1165
|
+
"status": "ok",
|
|
1166
|
+
"version": 1,
|
|
1167
|
+
"qualifiers": [],
|
|
1168
|
+
"fragment": null,
|
|
1169
|
+
"type": "gtin",
|
|
1170
|
+
"locator": "036000291452"
|
|
1171
|
+
}
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
"name": "the eight-digit length is a trade item number too",
|
|
1175
|
+
"input": "ref:gtin:40170725",
|
|
1176
|
+
"expect": {
|
|
1177
|
+
"status": "ok",
|
|
1178
|
+
"version": 1,
|
|
1179
|
+
"qualifiers": [],
|
|
1180
|
+
"fragment": null,
|
|
1181
|
+
"type": "gtin",
|
|
1182
|
+
"locator": "40170725"
|
|
1183
|
+
}
|
|
1184
|
+
},
|
|
1185
|
+
{
|
|
1186
|
+
"name": "a trade item number with the wrong check digit is refused by the same weighted sum",
|
|
1187
|
+
"input": "ref:gtin:036000291453",
|
|
1188
|
+
"expect": {
|
|
1189
|
+
"status": "malformed",
|
|
1190
|
+
"part": "locator"
|
|
1191
|
+
}
|
|
1192
|
+
},
|
|
1193
|
+
{
|
|
1194
|
+
"name": "a domain names a corpus",
|
|
1195
|
+
"input": "ref:url:portfolio.example",
|
|
1196
|
+
"expect": {
|
|
1197
|
+
"status": "ok",
|
|
1198
|
+
"version": 1,
|
|
1199
|
+
"qualifiers": [],
|
|
1200
|
+
"fragment": null,
|
|
1201
|
+
"type": "url",
|
|
1202
|
+
"locator": "portfolio.example"
|
|
1203
|
+
}
|
|
1204
|
+
},
|
|
1205
|
+
{
|
|
1206
|
+
"name": "a declared name under a domain, versioned, with a section fragment",
|
|
1207
|
+
"input": "ref:url:portfolio.example/case-xpto@2#results",
|
|
1208
|
+
"expect": {
|
|
1209
|
+
"status": "ok",
|
|
1210
|
+
"version": 1,
|
|
1211
|
+
"qualifiers": [],
|
|
1212
|
+
"fragment": {
|
|
1213
|
+
"path": "results",
|
|
1214
|
+
"refinements": []
|
|
1215
|
+
},
|
|
1216
|
+
"type": "url",
|
|
1217
|
+
"locator": "portfolio.example/case-xpto@2"
|
|
1218
|
+
}
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
"name": "an uppercase host is malformed at the locator",
|
|
1222
|
+
"input": "ref:url:Portfolio.example/case",
|
|
1223
|
+
"expect": {
|
|
1224
|
+
"status": "malformed",
|
|
1225
|
+
"part": "locator"
|
|
1226
|
+
}
|
|
1227
|
+
},
|
|
1228
|
+
{
|
|
1229
|
+
"name": "a mailbox identifies a person",
|
|
1230
|
+
"input": "ref:email:someone@mail.example",
|
|
1231
|
+
"expect": {
|
|
1232
|
+
"status": "ok",
|
|
1233
|
+
"version": 1,
|
|
1234
|
+
"qualifiers": [],
|
|
1235
|
+
"fragment": null,
|
|
1236
|
+
"type": "email",
|
|
1237
|
+
"locator": "someone@mail.example"
|
|
1238
|
+
}
|
|
1239
|
+
},
|
|
1240
|
+
{
|
|
1241
|
+
"name": "an item under a mailbox is named by whoever serves it",
|
|
1242
|
+
"input": "ref:email:someone@mail.example/doctor",
|
|
1243
|
+
"expect": {
|
|
1244
|
+
"status": "ok",
|
|
1245
|
+
"version": 1,
|
|
1246
|
+
"qualifiers": [],
|
|
1247
|
+
"fragment": null,
|
|
1248
|
+
"type": "email",
|
|
1249
|
+
"locator": "someone@mail.example/doctor"
|
|
1250
|
+
}
|
|
1251
|
+
},
|
|
1252
|
+
{
|
|
1253
|
+
"name": "an unregistered naming system is uncovered",
|
|
1254
|
+
"input": "ref:spotify:track/4uLU6hMCjMI75M1A2tKUQC",
|
|
1255
|
+
"expect": {
|
|
1256
|
+
"status": "uncovered",
|
|
1257
|
+
"version": 1,
|
|
1258
|
+
"type": "spotify",
|
|
1259
|
+
"locator": "track/4uLU6hMCjMI75M1A2tKUQC"
|
|
1260
|
+
}
|
|
1261
|
+
},
|
|
1262
|
+
{
|
|
1263
|
+
"name": "a content hash freezes what no version control holds",
|
|
1264
|
+
"input": "ref:url:models.example/quant-q4;state=blake3:0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f",
|
|
1265
|
+
"expect": {
|
|
1266
|
+
"status": "ok",
|
|
1267
|
+
"version": 1,
|
|
1268
|
+
"qualifiers": [
|
|
1269
|
+
[
|
|
1270
|
+
"state",
|
|
1271
|
+
"blake3:0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
|
|
1272
|
+
]
|
|
1273
|
+
],
|
|
1274
|
+
"fragment": null,
|
|
1275
|
+
"type": "url",
|
|
1276
|
+
"locator": "models.example/quant-q4"
|
|
1277
|
+
}
|
|
1278
|
+
},
|
|
1279
|
+
{
|
|
1280
|
+
"name": "none is a declared state level",
|
|
1281
|
+
"input": "ref:url:models.example/quant-q4;state=none",
|
|
1282
|
+
"expect": {
|
|
1283
|
+
"status": "ok",
|
|
1284
|
+
"version": 1,
|
|
1285
|
+
"qualifiers": [
|
|
1286
|
+
[
|
|
1287
|
+
"state",
|
|
1288
|
+
"none"
|
|
1289
|
+
]
|
|
1290
|
+
],
|
|
1291
|
+
"fragment": null,
|
|
1292
|
+
"type": "url",
|
|
1293
|
+
"locator": "models.example/quant-q4"
|
|
1294
|
+
}
|
|
1295
|
+
},
|
|
1296
|
+
{
|
|
1297
|
+
"name": "a state in an undeclared form is malformed at state",
|
|
1298
|
+
"input": "ref:url:models.example/quant-q4;state=sha1:0f0f0f0f",
|
|
1299
|
+
"expect": {
|
|
1300
|
+
"status": "malformed",
|
|
1301
|
+
"part": "state"
|
|
1302
|
+
}
|
|
1303
|
+
},
|
|
1304
|
+
{
|
|
1305
|
+
"name": "uppercase type is malformed",
|
|
1306
|
+
"input": "ref:Pkg:npm/x@1.0.0",
|
|
1307
|
+
"expect": {
|
|
1308
|
+
"status": "malformed",
|
|
1309
|
+
"part": "grammar"
|
|
1310
|
+
}
|
|
1311
|
+
},
|
|
1312
|
+
{
|
|
1313
|
+
"name": "missing scheme is malformed",
|
|
1314
|
+
"input": "pkg:npm/x@1.0.0",
|
|
1315
|
+
"expect": {
|
|
1316
|
+
"status": "malformed",
|
|
1317
|
+
"part": "grammar"
|
|
1318
|
+
}
|
|
1319
|
+
},
|
|
1320
|
+
{
|
|
1321
|
+
"name": "empty locator is malformed",
|
|
1322
|
+
"input": "ref:pkg:",
|
|
1323
|
+
"expect": {
|
|
1324
|
+
"status": "malformed",
|
|
1325
|
+
"part": "grammar"
|
|
1326
|
+
}
|
|
1327
|
+
},
|
|
1328
|
+
{
|
|
1329
|
+
"name": "abbreviated SWHID fails the state validator",
|
|
1330
|
+
"input": "ref:folder:acme-tools;state=swh:1:rev:7e29bb6",
|
|
1331
|
+
"expect": {
|
|
1332
|
+
"status": "malformed",
|
|
1333
|
+
"part": "state"
|
|
1334
|
+
}
|
|
1335
|
+
},
|
|
1336
|
+
{
|
|
1337
|
+
"name": "invalid purl fails the locator validator",
|
|
1338
|
+
"input": "ref:pkg:not-a-purl",
|
|
1339
|
+
"expect": {
|
|
1340
|
+
"status": "malformed",
|
|
1341
|
+
"part": "locator"
|
|
1342
|
+
}
|
|
1343
|
+
},
|
|
1344
|
+
{
|
|
1345
|
+
"name": "malformed refinement value",
|
|
1346
|
+
"input": "ref:folder:acme-tools#AGENTS.md;lines=ten",
|
|
1347
|
+
"expect": {
|
|
1348
|
+
"status": "malformed",
|
|
1349
|
+
"part": "lines"
|
|
1350
|
+
}
|
|
1351
|
+
},
|
|
1352
|
+
{
|
|
1353
|
+
"name": "a corpus name carries the path to a file inside it",
|
|
1354
|
+
"input": "ref:folder:acme-tools/docs#AGENTS.md",
|
|
1355
|
+
"expect": {
|
|
1356
|
+
"status": "ok",
|
|
1357
|
+
"version": 1,
|
|
1358
|
+
"qualifiers": [],
|
|
1359
|
+
"fragment": {
|
|
1360
|
+
"path": "AGENTS.md",
|
|
1361
|
+
"refinements": []
|
|
1362
|
+
},
|
|
1363
|
+
"type": "folder",
|
|
1364
|
+
"locator": "acme-tools/docs"
|
|
1365
|
+
}
|
|
1366
|
+
},
|
|
1367
|
+
{
|
|
1368
|
+
"name": "ai-model served id is admitted: Qwen3-4B-Instruct-2507-4bit",
|
|
1369
|
+
"input": "ref:ai-model:Qwen3-4B-Instruct-2507-4bit",
|
|
1370
|
+
"expect": {
|
|
1371
|
+
"status": "ok",
|
|
1372
|
+
"version": 1,
|
|
1373
|
+
"qualifiers": [],
|
|
1374
|
+
"fragment": null,
|
|
1375
|
+
"type": "ai-model",
|
|
1376
|
+
"locator": "Qwen3-4B-Instruct-2507-4bit"
|
|
1377
|
+
}
|
|
1378
|
+
},
|
|
1379
|
+
{
|
|
1380
|
+
"name": "ai-model served id is admitted: gemma-4-26b-a4b-it-4bit",
|
|
1381
|
+
"input": "ref:ai-model:gemma-4-26b-a4b-it-4bit",
|
|
1382
|
+
"expect": {
|
|
1383
|
+
"status": "ok",
|
|
1384
|
+
"version": 1,
|
|
1385
|
+
"qualifiers": [],
|
|
1386
|
+
"fragment": null,
|
|
1387
|
+
"type": "ai-model",
|
|
1388
|
+
"locator": "gemma-4-26b-a4b-it-4bit"
|
|
1389
|
+
}
|
|
1390
|
+
},
|
|
1391
|
+
{
|
|
1392
|
+
"name": "ai-model served id is admitted: Qwen3.5-9B-OptiQ-4bit",
|
|
1393
|
+
"input": "ref:ai-model:Qwen3.5-9B-OptiQ-4bit",
|
|
1394
|
+
"expect": {
|
|
1395
|
+
"status": "ok",
|
|
1396
|
+
"version": 1,
|
|
1397
|
+
"qualifiers": [],
|
|
1398
|
+
"fragment": null,
|
|
1399
|
+
"type": "ai-model",
|
|
1400
|
+
"locator": "Qwen3.5-9B-OptiQ-4bit"
|
|
1401
|
+
}
|
|
1402
|
+
},
|
|
1403
|
+
{
|
|
1404
|
+
"name": "ai-model served id is admitted: gpt-oss-20b-MXFP4-Q8",
|
|
1405
|
+
"input": "ref:ai-model:gpt-oss-20b-MXFP4-Q8",
|
|
1406
|
+
"expect": {
|
|
1407
|
+
"status": "ok",
|
|
1408
|
+
"version": 1,
|
|
1409
|
+
"qualifiers": [],
|
|
1410
|
+
"fragment": null,
|
|
1411
|
+
"type": "ai-model",
|
|
1412
|
+
"locator": "gpt-oss-20b-MXFP4-Q8"
|
|
1413
|
+
}
|
|
1414
|
+
},
|
|
1415
|
+
{
|
|
1416
|
+
"name": "ai-model served id is admitted: Llama-3.2-1B-Instruct-4bit",
|
|
1417
|
+
"input": "ref:ai-model:Llama-3.2-1B-Instruct-4bit",
|
|
1418
|
+
"expect": {
|
|
1419
|
+
"status": "ok",
|
|
1420
|
+
"version": 1,
|
|
1421
|
+
"qualifiers": [],
|
|
1422
|
+
"fragment": null,
|
|
1423
|
+
"type": "ai-model",
|
|
1424
|
+
"locator": "Llama-3.2-1B-Instruct-4bit"
|
|
1425
|
+
}
|
|
1426
|
+
},
|
|
1427
|
+
{
|
|
1428
|
+
"name": "ai-model served id is admitted: Qwen3.5-27B-Claude-4.6-Opus-Distilled-MLX-4bit",
|
|
1429
|
+
"input": "ref:ai-model:Qwen3.5-27B-Claude-4.6-Opus-Distilled-MLX-4bit",
|
|
1430
|
+
"expect": {
|
|
1431
|
+
"status": "ok",
|
|
1432
|
+
"version": 1,
|
|
1433
|
+
"qualifiers": [],
|
|
1434
|
+
"fragment": null,
|
|
1435
|
+
"type": "ai-model",
|
|
1436
|
+
"locator": "Qwen3.5-27B-Claude-4.6-Opus-Distilled-MLX-4bit"
|
|
1437
|
+
}
|
|
1438
|
+
},
|
|
1439
|
+
{
|
|
1440
|
+
"name": "ai-model served id is admitted: SmolLM3-3B-4bit",
|
|
1441
|
+
"input": "ref:ai-model:SmolLM3-3B-4bit",
|
|
1442
|
+
"expect": {
|
|
1443
|
+
"status": "ok",
|
|
1444
|
+
"version": 1,
|
|
1445
|
+
"qualifiers": [],
|
|
1446
|
+
"fragment": null,
|
|
1447
|
+
"type": "ai-model",
|
|
1448
|
+
"locator": "SmolLM3-3B-4bit"
|
|
1449
|
+
}
|
|
1450
|
+
},
|
|
1451
|
+
{
|
|
1452
|
+
"name": "ai-model served id is admitted: T-mixed-gemma-4-12B-it-OptiQ-4bit",
|
|
1453
|
+
"input": "ref:ai-model:T-mixed-gemma-4-12B-it-OptiQ-4bit",
|
|
1454
|
+
"expect": {
|
|
1455
|
+
"status": "ok",
|
|
1456
|
+
"version": 1,
|
|
1457
|
+
"qualifiers": [],
|
|
1458
|
+
"fragment": null,
|
|
1459
|
+
"type": "ai-model",
|
|
1460
|
+
"locator": "T-mixed-gemma-4-12B-it-OptiQ-4bit"
|
|
1461
|
+
}
|
|
1462
|
+
},
|
|
1463
|
+
{
|
|
1464
|
+
"name": "ai-model served id is admitted: claude-opus-5",
|
|
1465
|
+
"input": "ref:ai-model:claude-opus-5",
|
|
1466
|
+
"expect": {
|
|
1467
|
+
"status": "ok",
|
|
1468
|
+
"version": 1,
|
|
1469
|
+
"qualifiers": [],
|
|
1470
|
+
"fragment": null,
|
|
1471
|
+
"type": "ai-model",
|
|
1472
|
+
"locator": "claude-opus-5"
|
|
1473
|
+
}
|
|
1474
|
+
},
|
|
1475
|
+
{
|
|
1476
|
+
"name": "ai-model served id is admitted: Ternary-Bonsai-27B-mlx-2bit",
|
|
1477
|
+
"input": "ref:ai-model:Ternary-Bonsai-27B-mlx-2bit",
|
|
1478
|
+
"expect": {
|
|
1479
|
+
"status": "ok",
|
|
1480
|
+
"version": 1,
|
|
1481
|
+
"qualifiers": [],
|
|
1482
|
+
"fragment": null,
|
|
1483
|
+
"type": "ai-model",
|
|
1484
|
+
"locator": "Ternary-Bonsai-27B-mlx-2bit"
|
|
1485
|
+
}
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
"name": "ai-model served id is admitted: gemini-2.5-flash",
|
|
1489
|
+
"input": "ref:ai-model:gemini-2.5-flash",
|
|
1490
|
+
"expect": {
|
|
1491
|
+
"status": "ok",
|
|
1492
|
+
"version": 1,
|
|
1493
|
+
"qualifiers": [],
|
|
1494
|
+
"fragment": null,
|
|
1495
|
+
"type": "ai-model",
|
|
1496
|
+
"locator": "gemini-2.5-flash"
|
|
1497
|
+
}
|
|
1498
|
+
},
|
|
1499
|
+
{
|
|
1500
|
+
"name": "ai-model served id is admitted: llama3:8b",
|
|
1501
|
+
"input": "ref:ai-model:llama3:8b",
|
|
1502
|
+
"expect": {
|
|
1503
|
+
"status": "ok",
|
|
1504
|
+
"version": 1,
|
|
1505
|
+
"qualifiers": [],
|
|
1506
|
+
"fragment": null,
|
|
1507
|
+
"type": "ai-model",
|
|
1508
|
+
"locator": "llama3:8b"
|
|
1509
|
+
}
|
|
1510
|
+
},
|
|
1511
|
+
{
|
|
1512
|
+
"name": "ai-model served id is admitted: gpt-4o-2024-08-06",
|
|
1513
|
+
"input": "ref:ai-model:gpt-4o-2024-08-06",
|
|
1514
|
+
"expect": {
|
|
1515
|
+
"status": "ok",
|
|
1516
|
+
"version": 1,
|
|
1517
|
+
"qualifiers": [],
|
|
1518
|
+
"fragment": null,
|
|
1519
|
+
"type": "ai-model",
|
|
1520
|
+
"locator": "gpt-4o-2024-08-06"
|
|
1521
|
+
}
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
"name": "ai-model served id is admitted: mlx-community/Qwen3-1.7B-4bit",
|
|
1525
|
+
"input": "ref:ai-model:mlx-community/Qwen3-1.7B-4bit",
|
|
1526
|
+
"expect": {
|
|
1527
|
+
"status": "ok",
|
|
1528
|
+
"version": 1,
|
|
1529
|
+
"qualifiers": [],
|
|
1530
|
+
"fragment": null,
|
|
1531
|
+
"type": "ai-model",
|
|
1532
|
+
"locator": "mlx-community/Qwen3-1.7B-4bit"
|
|
1533
|
+
}
|
|
1534
|
+
},
|
|
1535
|
+
{
|
|
1536
|
+
"name": "an ai-model id cannot open on a separator",
|
|
1537
|
+
"input": "ref:ai-model:-Qwen3-4B",
|
|
1538
|
+
"expect": {
|
|
1539
|
+
"status": "malformed",
|
|
1540
|
+
"part": "locator"
|
|
1541
|
+
}
|
|
1542
|
+
},
|
|
1543
|
+
{
|
|
1544
|
+
"name": "unknown is a declared population level",
|
|
1545
|
+
"input": "ref:folder:acme-tools;over=unknown",
|
|
1546
|
+
"expect": {
|
|
1547
|
+
"status": "ok",
|
|
1548
|
+
"version": 1,
|
|
1549
|
+
"qualifiers": [
|
|
1550
|
+
[
|
|
1551
|
+
"over",
|
|
1552
|
+
"unknown"
|
|
1553
|
+
]
|
|
1554
|
+
],
|
|
1555
|
+
"fragment": null,
|
|
1556
|
+
"type": "folder",
|
|
1557
|
+
"locator": "acme-tools"
|
|
1558
|
+
}
|
|
1559
|
+
},
|
|
1560
|
+
{
|
|
1561
|
+
"name": "none is not a population level — a population of zero is not a population nobody recorded",
|
|
1562
|
+
"input": "ref:folder:acme-tools;over=none",
|
|
1563
|
+
"expect": {
|
|
1564
|
+
"status": "malformed",
|
|
1565
|
+
"part": "over"
|
|
1566
|
+
}
|
|
1567
|
+
},
|
|
1568
|
+
{
|
|
1569
|
+
"name": "unknown is not a state level — the fence from the other side",
|
|
1570
|
+
"input": "ref:folder:acme-tools;state=unknown",
|
|
1571
|
+
"expect": {
|
|
1572
|
+
"status": "malformed",
|
|
1573
|
+
"part": "state"
|
|
1574
|
+
}
|
|
1575
|
+
},
|
|
1576
|
+
{
|
|
1577
|
+
"name": "unknown is declared for over alone, never for by",
|
|
1578
|
+
"input": "ref:folder:acme-tools;by=unknown",
|
|
1579
|
+
"expect": {
|
|
1580
|
+
"status": "malformed",
|
|
1581
|
+
"part": "by"
|
|
1582
|
+
}
|
|
1583
|
+
},
|
|
1584
|
+
{
|
|
1585
|
+
"name": "an ai-model id cannot carry a character outside its declared class",
|
|
1586
|
+
"input": "ref:ai-model:a b",
|
|
1587
|
+
"expect": {
|
|
1588
|
+
"status": "malformed",
|
|
1589
|
+
"part": "locator"
|
|
1590
|
+
}
|
|
1591
|
+
},
|
|
1592
|
+
{
|
|
1593
|
+
"name": "an ai-model id carries a quantisation key after @",
|
|
1594
|
+
"input": "ref:ai-model:qwen2.5-7b-instruct@q4_k_m",
|
|
1595
|
+
"expect": {
|
|
1596
|
+
"status": "ok",
|
|
1597
|
+
"version": 1,
|
|
1598
|
+
"type": "ai-model",
|
|
1599
|
+
"locator": "qwen2.5-7b-instruct@q4_k_m",
|
|
1600
|
+
"qualifiers": [],
|
|
1601
|
+
"fragment": null
|
|
1602
|
+
}
|
|
1603
|
+
},
|
|
1604
|
+
{
|
|
1605
|
+
"name": "an ai-model id cannot traverse — every segment opens on an alphanumeric",
|
|
1606
|
+
"input": "ref:ai-model:a/../../etc/passwd",
|
|
1607
|
+
"expect": {
|
|
1608
|
+
"status": "malformed",
|
|
1609
|
+
"part": "locator"
|
|
1610
|
+
}
|
|
1611
|
+
},
|
|
1612
|
+
{
|
|
1613
|
+
"name": "an ai-model id cannot carry an empty segment",
|
|
1614
|
+
"input": "ref:ai-model:a//b",
|
|
1615
|
+
"expect": {
|
|
1616
|
+
"status": "malformed",
|
|
1617
|
+
"part": "locator"
|
|
1618
|
+
}
|
|
1619
|
+
},
|
|
1620
|
+
{
|
|
1621
|
+
"name": "a folder locator names a file, and the fragment names what is inside it",
|
|
1622
|
+
"input": "ref:folder:acme-tools/docs/guide.md#Setup",
|
|
1623
|
+
"expect": {
|
|
1624
|
+
"status": "ok",
|
|
1625
|
+
"version": 1,
|
|
1626
|
+
"qualifiers": [],
|
|
1627
|
+
"fragment": {
|
|
1628
|
+
"path": "Setup",
|
|
1629
|
+
"refinements": []
|
|
1630
|
+
},
|
|
1631
|
+
"type": "folder",
|
|
1632
|
+
"locator": "acme-tools/docs/guide.md"
|
|
1633
|
+
}
|
|
1634
|
+
},
|
|
1635
|
+
{
|
|
1636
|
+
"name": "a trailing separator names no file and is malformed",
|
|
1637
|
+
"input": "ref:folder:acme-tools/docs/",
|
|
1638
|
+
"expect": {
|
|
1639
|
+
"status": "malformed",
|
|
1640
|
+
"part": "locator"
|
|
1641
|
+
}
|
|
1642
|
+
},
|
|
1643
|
+
{
|
|
1644
|
+
"name": "a per-file state is a claim about the file the locator names",
|
|
1645
|
+
"input": "ref:folder:acme-tools/docs/guide.md;state=sha256:a2153e88000000000000000000000000000000000000000000000000000000ff#Setup",
|
|
1646
|
+
"expect": {
|
|
1647
|
+
"status": "ok",
|
|
1648
|
+
"version": 1,
|
|
1649
|
+
"qualifiers": [
|
|
1650
|
+
[
|
|
1651
|
+
"state",
|
|
1652
|
+
"sha256:a2153e88000000000000000000000000000000000000000000000000000000ff"
|
|
1653
|
+
]
|
|
1654
|
+
],
|
|
1655
|
+
"fragment": {
|
|
1656
|
+
"path": "Setup",
|
|
1657
|
+
"refinements": []
|
|
1658
|
+
},
|
|
1659
|
+
"type": "folder",
|
|
1660
|
+
"locator": "acme-tools/docs/guide.md"
|
|
1661
|
+
}
|
|
1662
|
+
},
|
|
1663
|
+
{
|
|
1664
|
+
"name": "a pkg subpath follows the version and reaches purl as its own component",
|
|
1665
|
+
"input": "ref:pkg:npm/x@1.0.0/docs/guide.md#Setup",
|
|
1666
|
+
"expect": {
|
|
1667
|
+
"status": "ok",
|
|
1668
|
+
"version": 1,
|
|
1669
|
+
"qualifiers": [],
|
|
1670
|
+
"fragment": {
|
|
1671
|
+
"path": "Setup",
|
|
1672
|
+
"refinements": []
|
|
1673
|
+
},
|
|
1674
|
+
"type": "pkg",
|
|
1675
|
+
"locator": "npm/x@1.0.0/docs/guide.md",
|
|
1676
|
+
"canonical": "pkg:npm/x@1.0.0#docs/guide.md"
|
|
1677
|
+
}
|
|
1678
|
+
},
|
|
1679
|
+
{
|
|
1680
|
+
"name": "a namespace @ opens a segment and is not the version that a subpath follows",
|
|
1681
|
+
"input": "ref:pkg:npm/@acme/x@1.0.0/docs/guide.md",
|
|
1682
|
+
"expect": {
|
|
1683
|
+
"status": "ok",
|
|
1684
|
+
"version": 1,
|
|
1685
|
+
"qualifiers": [],
|
|
1686
|
+
"fragment": null,
|
|
1687
|
+
"type": "pkg",
|
|
1688
|
+
"locator": "npm/@acme/x@1.0.0/docs/guide.md",
|
|
1689
|
+
"canonical": "pkg:npm/%40acme/x@1.0.0#docs/guide.md"
|
|
1690
|
+
}
|
|
1691
|
+
},
|
|
1692
|
+
{
|
|
1693
|
+
"name": "a namespace without a version carries no subpath and canonicalises as the bare purl",
|
|
1694
|
+
"input": "ref:pkg:npm/@acme/x",
|
|
1695
|
+
"expect": {
|
|
1696
|
+
"status": "ok",
|
|
1697
|
+
"version": 1,
|
|
1698
|
+
"qualifiers": [],
|
|
1699
|
+
"fragment": null,
|
|
1700
|
+
"type": "pkg",
|
|
1701
|
+
"locator": "npm/@acme/x",
|
|
1702
|
+
"canonical": "pkg:npm/%40acme/x"
|
|
1703
|
+
}
|
|
1704
|
+
},
|
|
1705
|
+
{
|
|
1706
|
+
"name": "a mailbox carries the items served under it",
|
|
1707
|
+
"input": "ref:email:alguem@dominio.com/CADx9v7abc123@mail.gmail.com",
|
|
1708
|
+
"expect": {
|
|
1709
|
+
"status": "ok",
|
|
1710
|
+
"version": 1,
|
|
1711
|
+
"qualifiers": [],
|
|
1712
|
+
"fragment": null,
|
|
1713
|
+
"type": "email",
|
|
1714
|
+
"locator": "alguem@dominio.com/CADx9v7abc123@mail.gmail.com"
|
|
1715
|
+
}
|
|
1716
|
+
},
|
|
1717
|
+
{
|
|
1718
|
+
"name": "a message is the item, and the fragment cuts inside it",
|
|
1719
|
+
"input": "ref:email:alguem@dominio.com/CADx9v7abc123@mail.gmail.com#Assunto;para=3",
|
|
1720
|
+
"expect": {
|
|
1721
|
+
"status": "ok",
|
|
1722
|
+
"version": 1,
|
|
1723
|
+
"qualifiers": [],
|
|
1724
|
+
"fragment": {
|
|
1725
|
+
"path": "Assunto",
|
|
1726
|
+
"refinements": [
|
|
1727
|
+
[
|
|
1728
|
+
"para",
|
|
1729
|
+
"3"
|
|
1730
|
+
]
|
|
1731
|
+
]
|
|
1732
|
+
},
|
|
1733
|
+
"type": "email",
|
|
1734
|
+
"locator": "alguem@dominio.com/CADx9v7abc123@mail.gmail.com"
|
|
1735
|
+
}
|
|
1736
|
+
},
|
|
1737
|
+
{
|
|
1738
|
+
"name": "a message is the cut when the mailbox is the item",
|
|
1739
|
+
"input": "ref:email:alguem@dominio.com#CADx9v7abc123@mail.gmail.com",
|
|
1740
|
+
"expect": {
|
|
1741
|
+
"status": "ok",
|
|
1742
|
+
"version": 1,
|
|
1743
|
+
"qualifiers": [],
|
|
1744
|
+
"fragment": {
|
|
1745
|
+
"path": "CADx9v7abc123@mail.gmail.com",
|
|
1746
|
+
"refinements": []
|
|
1747
|
+
},
|
|
1748
|
+
"type": "email",
|
|
1749
|
+
"locator": "alguem@dominio.com"
|
|
1750
|
+
}
|
|
1751
|
+
},
|
|
1752
|
+
{
|
|
1753
|
+
"name": "a trailing separator under a mailbox names no item",
|
|
1754
|
+
"input": "ref:email:alguem@dominio.com/",
|
|
1755
|
+
"expect": {
|
|
1756
|
+
"status": "malformed",
|
|
1757
|
+
"part": "locator"
|
|
1758
|
+
}
|
|
1759
|
+
},
|
|
1760
|
+
{
|
|
1761
|
+
"name": "a name already percent-encoded is not encoded twice",
|
|
1762
|
+
"input": "ref:pkg:npm/%40acme/x@1.0.0",
|
|
1763
|
+
"expect": {
|
|
1764
|
+
"status": "ok",
|
|
1765
|
+
"version": 1,
|
|
1766
|
+
"qualifiers": [],
|
|
1767
|
+
"fragment": null,
|
|
1768
|
+
"type": "pkg",
|
|
1769
|
+
"locator": "npm/%40acme/x@1.0.0",
|
|
1770
|
+
"canonical": "pkg:npm/%40acme/x@1.0.0"
|
|
1771
|
+
}
|
|
1772
|
+
},
|
|
1773
|
+
{
|
|
1774
|
+
"name": "a package type canonicalises in lower case",
|
|
1775
|
+
"input": "ref:pkg:NPM/x@1.0.0",
|
|
1776
|
+
"expect": {
|
|
1777
|
+
"status": "ok",
|
|
1778
|
+
"version": 1,
|
|
1779
|
+
"qualifiers": [],
|
|
1780
|
+
"fragment": null,
|
|
1781
|
+
"type": "pkg",
|
|
1782
|
+
"locator": "NPM/x@1.0.0",
|
|
1783
|
+
"canonical": "pkg:npm/x@1.0.0"
|
|
1784
|
+
}
|
|
1785
|
+
},
|
|
1786
|
+
{
|
|
1787
|
+
"name": "purl qualifiers canonicalise in key order, whatever order they were written",
|
|
1788
|
+
"input": "ref:pkg:npm/x@1.0.0?os=linux&arch=amd64",
|
|
1789
|
+
"expect": {
|
|
1790
|
+
"status": "ok",
|
|
1791
|
+
"version": 1,
|
|
1792
|
+
"qualifiers": [],
|
|
1793
|
+
"fragment": null,
|
|
1794
|
+
"type": "pkg",
|
|
1795
|
+
"locator": "npm/x@1.0.0?os=linux&arch=amd64",
|
|
1796
|
+
"canonical": "pkg:npm/x@1.0.0?arch=amd64&os=linux"
|
|
1797
|
+
}
|
|
1798
|
+
}
|
|
1799
|
+
],
|
|
1800
|
+
"canonical": [
|
|
1801
|
+
{
|
|
1802
|
+
"name": "one qualifier is already canonical",
|
|
1803
|
+
"input": "ref:eita:structured-output@1/validity;when=2026-08-02T18:31:31.870Z",
|
|
1804
|
+
"expect": "ref:eita:structured-output@1/validity;when=2026-08-02T18:31:31.870Z"
|
|
1805
|
+
},
|
|
1806
|
+
{
|
|
1807
|
+
"name": "two qualifiers written out of order sort by key",
|
|
1808
|
+
"input": "ref:eita:structured-output@1/validity;when=2026-08-02T18:31:31.870Z;over=unknown",
|
|
1809
|
+
"expect": "ref:eita:structured-output@1/validity;over=unknown;when=2026-08-02T18:31:31.870Z"
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
"name": "the same qualifiers in the other order reach the same form",
|
|
1813
|
+
"input": "ref:eita:structured-output@1/validity;over=unknown;when=2026-08-02T18:31:31.870Z",
|
|
1814
|
+
"expect": "ref:eita:structured-output@1/validity;over=unknown;when=2026-08-02T18:31:31.870Z"
|
|
1815
|
+
},
|
|
1816
|
+
{
|
|
1817
|
+
"name": "an unknown key sorts beside a declared one, carried through",
|
|
1818
|
+
"input": "ref:eita:citation-fidelity@1/exact;when=2026-08-14T23:38:26.089Z;context-tokens=8000;over=unknown",
|
|
1819
|
+
"expect": "ref:eita:citation-fidelity@1/exact;context-tokens=8000;over=unknown;when=2026-08-14T23:38:26.089Z"
|
|
1820
|
+
},
|
|
1821
|
+
{
|
|
1822
|
+
"name": "sorting is by UTF-16 code unit, so a hyphen precedes a letter",
|
|
1823
|
+
"input": "ref:eita:t@1/o;alphaone=1;alpha-two=2;alpha=3",
|
|
1824
|
+
"expect": "ref:eita:t@1/o;alpha=3;alpha-two=2;alphaone=1"
|
|
1825
|
+
},
|
|
1826
|
+
{
|
|
1827
|
+
"name": "a nested value is not decoded by canonicalisation",
|
|
1828
|
+
"input": "ref:eita:t@1/o;when=2026-08-02T18:31:31.870Z;over=ref:ai-model:Qwen3-4B-Instruct-2507-4bit",
|
|
1829
|
+
"expect": "ref:eita:t@1/o;over=ref:ai-model:Qwen3-4B-Instruct-2507-4bit;when=2026-08-02T18:31:31.870Z"
|
|
1830
|
+
},
|
|
1831
|
+
{
|
|
1832
|
+
"name": "no qualifiers, nothing to sort",
|
|
1833
|
+
"input": "ref:pkg:npm/@acme/scanner-core@0.1.0#Observation",
|
|
1834
|
+
"expect": "ref:pkg:npm/@acme/scanner-core@0.1.0#Observation"
|
|
1835
|
+
},
|
|
1836
|
+
{
|
|
1837
|
+
"name": "an explicit version survives canonicalisation verbatim",
|
|
1838
|
+
"input": "ref:1:pkg:npm/x@1.0.0;state=none;by=sha256:0000000000000000000000000000000000000000000000000000000000000000",
|
|
1839
|
+
"expect": "ref:1:pkg:npm/x@1.0.0;by=sha256:0000000000000000000000000000000000000000000000000000000000000000;state=none"
|
|
1840
|
+
},
|
|
1841
|
+
{
|
|
1842
|
+
"name": "refinements are positional and keep the order they were written",
|
|
1843
|
+
"input": "ref:folder:acme-governance;state=none#AGENTS.md;lines=1,20;item=3",
|
|
1844
|
+
"expect": "ref:folder:acme-governance;state=none#AGENTS.md;lines=1,20;item=3"
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
"name": "qualifiers sort while the fragment beside them is untouched",
|
|
1848
|
+
"input": "ref:folder:acme-governance;when=2026-08-02T18:31:31.870Z;state=none#AGENTS.md;lines=1,20",
|
|
1849
|
+
"expect": "ref:folder:acme-governance;state=none;when=2026-08-02T18:31:31.870Z#AGENTS.md;lines=1,20"
|
|
1850
|
+
},
|
|
1851
|
+
{
|
|
1852
|
+
"name": "a malformed identifier has no canonical form",
|
|
1853
|
+
"input": "ref:eita:t@1/o;state=none;state=none",
|
|
1854
|
+
"expect": {
|
|
1855
|
+
"error": "state"
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
],
|
|
1859
|
+
"roundtrip": [
|
|
1860
|
+
"ref:pkg:npm/@acme/scanner-core@0.1.0#Observation",
|
|
1861
|
+
"ref:1:pkg:npm/x@1.0.0",
|
|
1862
|
+
"ref:folder:acme-tools;zz=1;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
1863
|
+
"ref:folder:acme-tools;by=ref:pkg:npm/@acme/profiles@0.1.0%23profile/conformance@1",
|
|
1864
|
+
"ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000%23S",
|
|
1865
|
+
"ref:pkg:npm/%40acme/x@1.0.0#S",
|
|
1866
|
+
"ref:folder:acme-tools;zz=a%3Bb;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
1867
|
+
"ref:folder:acme-tools;state=swh:1:cnt:3404a00f00000000000000000000000000000000#AGENTS.md;lines=1",
|
|
1868
|
+
"ref:folder:acme-tools#AGENTS.md;zz=q",
|
|
1869
|
+
"ref:doi:10.1000/182",
|
|
1870
|
+
"ref:dot-agent:unknown/MentorUniversitario:1.4.1",
|
|
1871
|
+
"ref:url:portfolio.example/case-xpto@2;state=none#results",
|
|
1872
|
+
"ref:email:someone@mail.example",
|
|
1873
|
+
"ref:2:pkg:npm/x@1.0.0",
|
|
1874
|
+
"ref:01:pkg:npm/x@1.0.0",
|
|
1875
|
+
"ref:pkg:npm/@acme/scanner-core;when=2026-08-12T18:55:27.811Z#governance@0.0.1/markdown-link",
|
|
1876
|
+
"ref:pkg:npm/acme-tools#acme/adr@2/0019",
|
|
1877
|
+
"ref:folder:acme-tools;by=ref:2:pkg:npm/x@1.0.0",
|
|
1878
|
+
"ref:doi:10.1000/182;state=swh:1:rev:7e29bb6000000000000000000000000000000000#S",
|
|
1879
|
+
"ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%2523src/y",
|
|
1880
|
+
"ref:ai-model:mlx-community/Qwen3-1.7B-4bit",
|
|
1881
|
+
"ref:ai-model:llama3:8b",
|
|
1882
|
+
"ref:folder:acme-tools;over=unknown"
|
|
1883
|
+
],
|
|
1884
|
+
"build": [
|
|
1885
|
+
{
|
|
1886
|
+
"name": "same declared name through two paths is one identifier",
|
|
1887
|
+
"parts": {
|
|
1888
|
+
"type": "pkg",
|
|
1889
|
+
"locator": "npm/x@1.0.0",
|
|
1890
|
+
"fragment": "Observation",
|
|
1891
|
+
"location": {
|
|
1892
|
+
"path": "src/a.ts"
|
|
1893
|
+
}
|
|
216
1894
|
},
|
|
217
|
-
"
|
|
218
|
-
|
|
219
|
-
|
|
1895
|
+
"expect": "ref:pkg:npm/x@1.0.0#Observation"
|
|
1896
|
+
},
|
|
1897
|
+
{
|
|
1898
|
+
"name": "same declared name through two paths is one identifier (other path)",
|
|
1899
|
+
"parts": {
|
|
1900
|
+
"type": "pkg",
|
|
1901
|
+
"locator": "npm/x@1.0.0",
|
|
1902
|
+
"fragment": "Observation",
|
|
1903
|
+
"location": {
|
|
1904
|
+
"path": "lib/b.ts",
|
|
1905
|
+
"lines": "4,9"
|
|
1906
|
+
}
|
|
220
1907
|
},
|
|
221
|
-
"
|
|
222
|
-
|
|
223
|
-
|
|
1908
|
+
"expect": "ref:pkg:npm/x@1.0.0#Observation"
|
|
1909
|
+
},
|
|
1910
|
+
{
|
|
1911
|
+
"name": "nested qualifier value is encoded by the builder",
|
|
1912
|
+
"parts": {
|
|
1913
|
+
"type": "folder",
|
|
1914
|
+
"locator": "acme-tools",
|
|
1915
|
+
"qualifiers": [
|
|
1916
|
+
[
|
|
1917
|
+
"by",
|
|
1918
|
+
{
|
|
1919
|
+
"nested": "ref:pkg:npm/x@1.0.0;state=swh:1:rev:7e29bb6000000000000000000000000000000000#S"
|
|
1920
|
+
}
|
|
1921
|
+
]
|
|
1922
|
+
]
|
|
224
1923
|
},
|
|
225
|
-
"
|
|
226
|
-
|
|
227
|
-
|
|
1924
|
+
"expect": "ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000%23S"
|
|
1925
|
+
},
|
|
1926
|
+
{
|
|
1927
|
+
"name": "a pkg locator given as the bare group builds as is",
|
|
1928
|
+
"parts": {
|
|
1929
|
+
"type": "pkg",
|
|
1930
|
+
"locator": "npm/x@1.0.0",
|
|
1931
|
+
"fragment": "Observation"
|
|
228
1932
|
},
|
|
229
|
-
"
|
|
230
|
-
|
|
231
|
-
|
|
1933
|
+
"expect": "ref:pkg:npm/x@1.0.0#Observation"
|
|
1934
|
+
},
|
|
1935
|
+
{
|
|
1936
|
+
"name": "an intact purl given as locator has its scheme folded into the type",
|
|
1937
|
+
"parts": {
|
|
1938
|
+
"type": "pkg",
|
|
1939
|
+
"locator": "pkg:npm/x@1.0.0",
|
|
1940
|
+
"fragment": "S"
|
|
232
1941
|
},
|
|
233
|
-
"
|
|
234
|
-
|
|
235
|
-
|
|
1942
|
+
"expect": "ref:pkg:npm/x@1.0.0#S"
|
|
1943
|
+
},
|
|
1944
|
+
{
|
|
1945
|
+
"name": "a locator carrying a reserved character is refused",
|
|
1946
|
+
"parts": {
|
|
1947
|
+
"type": "pkg",
|
|
1948
|
+
"locator": "pkg:npm/x@1.0.0#src/y",
|
|
1949
|
+
"fragment": "S"
|
|
236
1950
|
},
|
|
237
|
-
"
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
1951
|
+
"expect": {
|
|
1952
|
+
"error": "locator"
|
|
1953
|
+
}
|
|
1954
|
+
},
|
|
1955
|
+
{
|
|
1956
|
+
"name": "a fragment path carrying the separator is refused",
|
|
1957
|
+
"parts": {
|
|
1958
|
+
"type": "folder",
|
|
1959
|
+
"locator": "acme-tools",
|
|
1960
|
+
"fragment": "a;b"
|
|
241
1961
|
},
|
|
242
|
-
"
|
|
243
|
-
|
|
244
|
-
"reference": "the declared level for a population nobody established. Deliberately not `none`, which `state` uses: a state cannot be empty, so `none` is unambiguous there, while a population over zero members is a real and different thing from a population nobody recorded — and an identifier must not let the two read alike. It is a floor, never a destination: a producer that can enumerate its population says so with `sha256`, which names which population rather than admitting there was one"
|
|
1962
|
+
"expect": {
|
|
1963
|
+
"error": "fragment"
|
|
245
1964
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
"
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
1965
|
+
},
|
|
1966
|
+
{
|
|
1967
|
+
"name": "a nested identifier passed as a plain string is refused",
|
|
1968
|
+
"parts": {
|
|
1969
|
+
"type": "folder",
|
|
1970
|
+
"locator": "acme-tools",
|
|
1971
|
+
"qualifiers": [
|
|
1972
|
+
[
|
|
1973
|
+
"by",
|
|
1974
|
+
"ref:pkg:npm/x@1.0.0#S"
|
|
1975
|
+
]
|
|
1976
|
+
]
|
|
253
1977
|
},
|
|
254
|
-
"
|
|
255
|
-
|
|
1978
|
+
"expect": {
|
|
1979
|
+
"error": "by"
|
|
1980
|
+
}
|
|
1981
|
+
},
|
|
1982
|
+
{
|
|
1983
|
+
"name": "a type carrying the field separator is refused",
|
|
1984
|
+
"parts": {
|
|
1985
|
+
"type": "1:folder",
|
|
1986
|
+
"locator": "a"
|
|
256
1987
|
},
|
|
257
|
-
"
|
|
258
|
-
|
|
1988
|
+
"expect": {
|
|
1989
|
+
"error": "type"
|
|
259
1990
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
"
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
],
|
|
273
|
-
"fragmentGrammars": {
|
|
274
|
-
"governed-record": {
|
|
275
|
-
"declaredName": "<provider>/<type>@<template version>/<name>, every part from the record's own front matter stamp; the provider of the type declares the form of <name>",
|
|
276
|
-
"tieBreak": "none"
|
|
1991
|
+
},
|
|
1992
|
+
{
|
|
1993
|
+
"name": "a dot-agent identifier builds with its digest in state",
|
|
1994
|
+
"parts": {
|
|
1995
|
+
"type": "dot-agent",
|
|
1996
|
+
"locator": "acme.example/doctor:v1.0",
|
|
1997
|
+
"qualifiers": [
|
|
1998
|
+
[
|
|
1999
|
+
"state",
|
|
2000
|
+
"git:a1b2c3d4"
|
|
2001
|
+
]
|
|
2002
|
+
]
|
|
277
2003
|
},
|
|
278
|
-
"
|
|
279
|
-
|
|
280
|
-
|
|
2004
|
+
"expect": "ref:dot-agent:acme.example/doctor:v1.0;state=git:a1b2c3d4"
|
|
2005
|
+
},
|
|
2006
|
+
{
|
|
2007
|
+
"name": "a content hash is accepted as a state",
|
|
2008
|
+
"parts": {
|
|
2009
|
+
"type": "url",
|
|
2010
|
+
"locator": "models.example/quant-q4",
|
|
2011
|
+
"qualifiers": [
|
|
2012
|
+
[
|
|
2013
|
+
"state",
|
|
2014
|
+
"sha256:0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
|
|
2015
|
+
]
|
|
2016
|
+
]
|
|
281
2017
|
},
|
|
282
|
-
"
|
|
283
|
-
|
|
284
|
-
|
|
2018
|
+
"expect": "ref:url:models.example/quant-q4;state=sha256:0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
|
|
2019
|
+
},
|
|
2020
|
+
{
|
|
2021
|
+
"name": "a digest value passes through the builder",
|
|
2022
|
+
"parts": {
|
|
2023
|
+
"type": "folder",
|
|
2024
|
+
"locator": "acme-tools",
|
|
2025
|
+
"qualifiers": [
|
|
2026
|
+
[
|
|
2027
|
+
"over",
|
|
2028
|
+
"sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
2029
|
+
]
|
|
2030
|
+
]
|
|
285
2031
|
},
|
|
286
|
-
"
|
|
287
|
-
|
|
288
|
-
|
|
2032
|
+
"expect": "ref:folder:acme-tools;over=sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
2033
|
+
},
|
|
2034
|
+
{
|
|
2035
|
+
"name": "an ai-model locator with a hub-style separator builds as is",
|
|
2036
|
+
"parts": {
|
|
2037
|
+
"type": "ai-model",
|
|
2038
|
+
"locator": "mlx-community/Qwen3-1.7B-4bit"
|
|
289
2039
|
},
|
|
290
|
-
"
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
"over": "identifier-strings",
|
|
298
|
-
"order": "declared",
|
|
299
|
-
"join": "\n",
|
|
300
|
-
"encoding": "utf-8",
|
|
301
|
-
"dedupe": false,
|
|
302
|
-
"output": "sha256:<64 lowercase hex>"
|
|
303
|
-
},
|
|
304
|
-
"identifierEquivalence": {
|
|
305
|
-
"qualifierOrder": "insignificant",
|
|
306
|
-
"refinementOrder": "significant",
|
|
307
|
-
"canonicalForm": "re-serialise the parsed identifier with its qualifiers sorted by key in UTF-16 code unit order; every other part verbatim, refinements included",
|
|
308
|
-
"comparison": "two identifiers name one thing when their canonical forms are equal byte for byte",
|
|
309
|
-
"reserialisation": "SHOULD preserve the order written; MUST NOT be relied on to tell two identifiers apart",
|
|
310
|
-
"note": "distinct from `canonicalisation`, which is the form of THIS FILE for its own digest"
|
|
311
|
-
},
|
|
312
|
-
"canonicalisation": {
|
|
313
|
-
"form": "json-sorted-keys-compact",
|
|
314
|
-
"rules": [
|
|
315
|
-
"object keys sorted by UTF-16 code unit order",
|
|
316
|
-
"no whitespace outside strings",
|
|
317
|
-
"strings escaped as JSON.stringify does",
|
|
318
|
-
"numbers are integers only",
|
|
319
|
-
"UTF-8 bytes of the result are what the digest covers"
|
|
320
|
-
],
|
|
321
|
-
"sidecar": "ref-id.json.sha256 holds the digest of this file; the file never contains its own digest"
|
|
322
|
-
},
|
|
323
|
-
"envelope": {
|
|
324
|
-
"fields": {
|
|
325
|
-
"id": "required",
|
|
326
|
-
"sets": "required when the identifier carries a digest",
|
|
327
|
-
"alsoKnownAs": "optional, a declaration never a similarity match",
|
|
328
|
-
"data": "opaque"
|
|
2040
|
+
"expect": "ref:ai-model:mlx-community/Qwen3-1.7B-4bit"
|
|
2041
|
+
},
|
|
2042
|
+
{
|
|
2043
|
+
"name": "an ai-model locator with an Ollama tag builds as is",
|
|
2044
|
+
"parts": {
|
|
2045
|
+
"type": "ai-model",
|
|
2046
|
+
"locator": "llama3:8b"
|
|
329
2047
|
},
|
|
330
|
-
"
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
"
|
|
334
|
-
"
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
},
|
|
354
|
-
{
|
|
355
|
-
"name": "pkg with versioned declared-name path",
|
|
356
|
-
"input": "ref:pkg:npm/@acme/trait-citation-fidelity@0.0.1#citation-fidelity@1/not-invented",
|
|
357
|
-
"expect": {
|
|
358
|
-
"status": "ok",
|
|
359
|
-
"version": 1,
|
|
360
|
-
"qualifiers": [],
|
|
361
|
-
"fragment": {
|
|
362
|
-
"path": "citation-fidelity@1/not-invented",
|
|
363
|
-
"refinements": []
|
|
364
|
-
},
|
|
365
|
-
"type": "pkg",
|
|
366
|
-
"locator": "npm/@acme/trait-citation-fidelity@0.0.1"
|
|
367
|
-
}
|
|
368
|
-
},
|
|
369
|
-
{
|
|
370
|
-
"name": "folder corpus with declared name",
|
|
371
|
-
"input": "ref:folder:acme-governance#learnings/a-chunk-carrying-no-answer-means-death-or-health",
|
|
372
|
-
"expect": {
|
|
373
|
-
"status": "ok",
|
|
374
|
-
"version": 1,
|
|
375
|
-
"qualifiers": [],
|
|
376
|
-
"fragment": {
|
|
377
|
-
"path": "learnings/a-chunk-carrying-no-answer-means-death-or-health",
|
|
378
|
-
"refinements": []
|
|
379
|
-
},
|
|
380
|
-
"type": "folder",
|
|
381
|
-
"locator": "acme-governance"
|
|
382
|
-
}
|
|
383
|
-
},
|
|
384
|
-
{
|
|
385
|
-
"name": "folder with state and by digest",
|
|
386
|
-
"input": "ref:folder:acme-tools;state=swh:1:rev:7e29bb6000000000000000000000000000000000;by=sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
387
|
-
"expect": {
|
|
388
|
-
"status": "ok",
|
|
389
|
-
"version": 1,
|
|
390
|
-
"qualifiers": [
|
|
391
|
-
[
|
|
392
|
-
"state",
|
|
393
|
-
"swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
394
|
-
],
|
|
395
|
-
[
|
|
396
|
-
"by",
|
|
397
|
-
"sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
398
|
-
]
|
|
399
|
-
],
|
|
400
|
-
"fragment": null,
|
|
401
|
-
"type": "folder",
|
|
402
|
-
"locator": "acme-tools"
|
|
403
|
-
}
|
|
404
|
-
},
|
|
405
|
-
{
|
|
406
|
-
"name": "explicit version 1 is version 1",
|
|
407
|
-
"input": "ref:1:pkg:npm/x@1.0.0",
|
|
408
|
-
"expect": {
|
|
409
|
-
"status": "ok",
|
|
410
|
-
"version": 1,
|
|
411
|
-
"qualifiers": [],
|
|
412
|
-
"fragment": null,
|
|
413
|
-
"type": "pkg",
|
|
414
|
-
"locator": "npm/x@1.0.0",
|
|
415
|
-
"delegated": "pkg:npm/x@1.0.0",
|
|
416
|
-
"explicitVersion": true
|
|
417
|
-
}
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
"name": "version outside the supported range is unsupported, not malformed",
|
|
421
|
-
"input": "ref:2:pkg:npm/x@1.0.0",
|
|
422
|
-
"expect": {
|
|
423
|
-
"status": "unsupported",
|
|
424
|
-
"version": 2,
|
|
425
|
-
"type": "pkg",
|
|
426
|
-
"locator": "npm/x@1.0.0"
|
|
427
|
-
}
|
|
428
|
-
},
|
|
429
|
-
{
|
|
430
|
-
"name": "letter-led token is a type, not a version",
|
|
431
|
-
"input": "ref:v2:pkg:npm/x",
|
|
432
|
-
"expect": {
|
|
433
|
-
"status": "uncovered",
|
|
434
|
-
"version": 1,
|
|
435
|
-
"type": "v2",
|
|
436
|
-
"locator": "pkg:npm/x"
|
|
437
|
-
}
|
|
438
|
-
},
|
|
439
|
-
{
|
|
440
|
-
"name": "unknown type is uncovered, never an exception",
|
|
441
|
-
"input": "ref:doi:10.1000/182",
|
|
442
|
-
"expect": {
|
|
443
|
-
"status": "uncovered",
|
|
444
|
-
"version": 1,
|
|
445
|
-
"type": "doi",
|
|
446
|
-
"locator": "10.1000/182"
|
|
447
|
-
}
|
|
448
|
-
},
|
|
449
|
-
{
|
|
450
|
-
"name": "unknown qualifier key is carried through",
|
|
451
|
-
"input": "ref:folder:acme-tools;zz=1;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
452
|
-
"expect": {
|
|
453
|
-
"status": "ok",
|
|
454
|
-
"version": 1,
|
|
455
|
-
"qualifiers": [
|
|
456
|
-
[
|
|
457
|
-
"zz",
|
|
458
|
-
"1"
|
|
459
|
-
],
|
|
460
|
-
[
|
|
461
|
-
"state",
|
|
462
|
-
"swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
463
|
-
]
|
|
464
|
-
],
|
|
465
|
-
"fragment": null,
|
|
466
|
-
"type": "folder",
|
|
467
|
-
"locator": "acme-tools"
|
|
468
|
-
}
|
|
469
|
-
},
|
|
470
|
-
{
|
|
471
|
-
"name": "nested by carrying a fragment",
|
|
472
|
-
"input": "ref:folder:acme-tools;by=ref:pkg:npm/@acme/profiles@0.1.0%23profile/conformance@1",
|
|
473
|
-
"expect": {
|
|
474
|
-
"status": "ok",
|
|
475
|
-
"version": 1,
|
|
476
|
-
"qualifiers": [
|
|
477
|
-
[
|
|
478
|
-
"by",
|
|
479
|
-
"ref:pkg:npm/@acme/profiles@0.1.0%23profile/conformance@1"
|
|
480
|
-
]
|
|
481
|
-
],
|
|
482
|
-
"fragment": null,
|
|
483
|
-
"type": "folder",
|
|
484
|
-
"locator": "acme-tools",
|
|
485
|
-
"nested": {
|
|
486
|
-
"by": "ref:pkg:npm/@acme/profiles@0.1.0#profile/conformance@1"
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
},
|
|
490
|
-
{
|
|
491
|
-
"name": "nested by carrying its own qualifier",
|
|
492
|
-
"input": "ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000%23S",
|
|
493
|
-
"expect": {
|
|
494
|
-
"status": "ok",
|
|
495
|
-
"version": 1,
|
|
496
|
-
"qualifiers": [
|
|
497
|
-
[
|
|
498
|
-
"by",
|
|
499
|
-
"ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000%23S"
|
|
500
|
-
]
|
|
501
|
-
],
|
|
502
|
-
"fragment": null,
|
|
503
|
-
"type": "folder",
|
|
504
|
-
"locator": "acme-tools",
|
|
505
|
-
"nested": {
|
|
506
|
-
"by": "ref:pkg:npm/x@1.0.0;state=swh:1:rev:7e29bb6000000000000000000000000000000000#S"
|
|
507
|
-
}
|
|
508
|
-
}
|
|
509
|
-
},
|
|
510
|
-
{
|
|
511
|
-
"name": "two different nested values are two different identifiers",
|
|
512
|
-
"input": "ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
513
|
-
"expect": {
|
|
514
|
-
"status": "ok",
|
|
515
|
-
"version": 1,
|
|
516
|
-
"qualifiers": [
|
|
517
|
-
[
|
|
518
|
-
"by",
|
|
519
|
-
"ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
520
|
-
]
|
|
521
|
-
],
|
|
522
|
-
"fragment": null,
|
|
523
|
-
"type": "folder",
|
|
524
|
-
"locator": "acme-tools",
|
|
525
|
-
"nested": {
|
|
526
|
-
"by": "ref:pkg:npm/x@1.0.0;state=swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
},
|
|
530
|
-
{
|
|
531
|
-
"name": "a purl keeps its own percent-encoding intact",
|
|
532
|
-
"input": "ref:pkg:npm/%40acme/x@1.0.0#S",
|
|
533
|
-
"expect": {
|
|
534
|
-
"status": "ok",
|
|
535
|
-
"version": 1,
|
|
536
|
-
"qualifiers": [],
|
|
537
|
-
"fragment": {
|
|
538
|
-
"path": "S",
|
|
539
|
-
"refinements": []
|
|
540
|
-
},
|
|
541
|
-
"type": "pkg",
|
|
542
|
-
"locator": "npm/%40acme/x@1.0.0",
|
|
543
|
-
"delegated": "pkg:npm/%40acme/x@1.0.0"
|
|
544
|
-
}
|
|
545
|
-
},
|
|
546
|
-
{
|
|
547
|
-
"name": "an identifier is one line",
|
|
548
|
-
"input": "ref:folder:acme-tools\nx",
|
|
549
|
-
"expect": {
|
|
550
|
-
"status": "malformed",
|
|
551
|
-
"part": "grammar"
|
|
552
|
-
}
|
|
553
|
-
},
|
|
554
|
-
{
|
|
555
|
-
"name": "nesting deeper than one level is malformed",
|
|
556
|
-
"input": "ref:folder:b;by=ref:folder:a%3Bby=ref:pkg:npm/x@1.0.0%2523S",
|
|
557
|
-
"expect": {
|
|
558
|
-
"status": "malformed",
|
|
559
|
-
"part": "by"
|
|
560
|
-
}
|
|
561
|
-
},
|
|
562
|
-
{
|
|
563
|
-
"name": "a reversed line range is malformed",
|
|
564
|
-
"input": "ref:folder:acme-tools#AGENTS.md;lines=20,10",
|
|
565
|
-
"expect": {
|
|
566
|
-
"status": "malformed",
|
|
567
|
-
"part": "lines"
|
|
568
|
-
}
|
|
569
|
-
},
|
|
570
|
-
{
|
|
571
|
-
"name": "an unknown key keeps an encoded separator in its value",
|
|
572
|
-
"input": "ref:folder:acme-tools;zz=a%3Bb;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
573
|
-
"expect": {
|
|
574
|
-
"status": "ok",
|
|
575
|
-
"version": 1,
|
|
576
|
-
"qualifiers": [
|
|
577
|
-
[
|
|
578
|
-
"zz",
|
|
579
|
-
"a%3Bb"
|
|
580
|
-
],
|
|
581
|
-
[
|
|
582
|
-
"state",
|
|
583
|
-
"swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
584
|
-
]
|
|
585
|
-
],
|
|
586
|
-
"fragment": null,
|
|
587
|
-
"type": "folder",
|
|
588
|
-
"locator": "acme-tools"
|
|
589
|
-
}
|
|
590
|
-
},
|
|
591
|
-
{
|
|
592
|
-
"name": "refinement after the declared-name path",
|
|
593
|
-
"input": "ref:folder:acme-tools#AGENTS.md;lines=10,20",
|
|
594
|
-
"expect": {
|
|
595
|
-
"status": "ok",
|
|
596
|
-
"version": 1,
|
|
597
|
-
"qualifiers": [],
|
|
598
|
-
"fragment": {
|
|
599
|
-
"path": "AGENTS.md",
|
|
600
|
-
"refinements": [
|
|
601
|
-
[
|
|
602
|
-
"lines",
|
|
603
|
-
"10,20"
|
|
604
|
-
]
|
|
605
|
-
]
|
|
606
|
-
},
|
|
607
|
-
"type": "folder",
|
|
608
|
-
"locator": "acme-tools"
|
|
609
|
-
}
|
|
610
|
-
},
|
|
611
|
-
{
|
|
612
|
-
"name": "qualifier before the hash, refinement after it",
|
|
613
|
-
"input": "ref:folder:acme-tools;state=swh:1:cnt:3404a00f00000000000000000000000000000000#AGENTS.md;lines=1",
|
|
614
|
-
"expect": {
|
|
615
|
-
"status": "ok",
|
|
616
|
-
"version": 1,
|
|
617
|
-
"qualifiers": [
|
|
618
|
-
[
|
|
619
|
-
"state",
|
|
620
|
-
"swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
621
|
-
]
|
|
622
|
-
],
|
|
623
|
-
"fragment": {
|
|
624
|
-
"path": "AGENTS.md",
|
|
625
|
-
"refinements": [
|
|
626
|
-
[
|
|
627
|
-
"lines",
|
|
628
|
-
"1"
|
|
629
|
-
]
|
|
630
|
-
]
|
|
631
|
-
},
|
|
632
|
-
"type": "folder",
|
|
633
|
-
"locator": "acme-tools"
|
|
634
|
-
}
|
|
635
|
-
},
|
|
636
|
-
{
|
|
637
|
-
"name": "unknown refinement key is carried through",
|
|
638
|
-
"input": "ref:folder:acme-tools#AGENTS.md;zz=q",
|
|
639
|
-
"expect": {
|
|
640
|
-
"status": "ok",
|
|
641
|
-
"version": 1,
|
|
642
|
-
"qualifiers": [],
|
|
643
|
-
"fragment": {
|
|
644
|
-
"path": "AGENTS.md",
|
|
645
|
-
"refinements": [
|
|
646
|
-
[
|
|
647
|
-
"zz",
|
|
648
|
-
"q"
|
|
649
|
-
]
|
|
650
|
-
]
|
|
651
|
-
},
|
|
652
|
-
"type": "folder",
|
|
653
|
-
"locator": "acme-tools"
|
|
654
|
-
}
|
|
655
|
-
},
|
|
656
|
-
{
|
|
657
|
-
"name": "over as a digest",
|
|
658
|
-
"input": "ref:folder:acme-tools;over=sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
659
|
-
"expect": {
|
|
660
|
-
"status": "ok",
|
|
661
|
-
"version": 1,
|
|
662
|
-
"qualifiers": [
|
|
663
|
-
[
|
|
664
|
-
"over",
|
|
665
|
-
"sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
666
|
-
]
|
|
667
|
-
],
|
|
668
|
-
"fragment": null,
|
|
669
|
-
"type": "folder",
|
|
670
|
-
"locator": "acme-tools"
|
|
671
|
-
}
|
|
672
|
-
},
|
|
673
|
-
{
|
|
674
|
-
"name": "a validator failure outranks an unknown type",
|
|
675
|
-
"input": "ref:doi:10.1000/182;state=swh:1:rev:7e29bb6",
|
|
676
|
-
"expect": {
|
|
677
|
-
"status": "malformed",
|
|
678
|
-
"part": "state"
|
|
679
|
-
}
|
|
680
|
-
},
|
|
681
|
-
{
|
|
682
|
-
"name": "an unsupported version is not validated further",
|
|
683
|
-
"input": "ref:2:pkg:npm/x@1.0.0;state=swh:1:rev:7e29bb6",
|
|
684
|
-
"expect": {
|
|
685
|
-
"status": "unsupported",
|
|
686
|
-
"version": 2,
|
|
687
|
-
"type": "pkg",
|
|
688
|
-
"locator": "npm/x@1.0.0",
|
|
689
|
-
"qualifiers": [
|
|
690
|
-
[
|
|
691
|
-
"state",
|
|
692
|
-
"swh:1:rev:7e29bb6"
|
|
693
|
-
]
|
|
694
|
-
]
|
|
695
|
-
}
|
|
696
|
-
},
|
|
697
|
-
{
|
|
698
|
-
"name": "an uncovered type still carries its qualifiers and fragment",
|
|
699
|
-
"input": "ref:doi:10.1000/182;state=swh:1:rev:7e29bb6000000000000000000000000000000000#S",
|
|
700
|
-
"expect": {
|
|
701
|
-
"status": "uncovered",
|
|
702
|
-
"version": 1,
|
|
703
|
-
"type": "doi",
|
|
704
|
-
"locator": "10.1000/182",
|
|
705
|
-
"qualifiers": [
|
|
706
|
-
[
|
|
707
|
-
"state",
|
|
708
|
-
"swh:1:rev:7e29bb6000000000000000000000000000000000"
|
|
709
|
-
]
|
|
710
|
-
],
|
|
711
|
-
"fragment": {
|
|
712
|
-
"path": "S",
|
|
713
|
-
"refinements": []
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
},
|
|
717
|
-
{
|
|
718
|
-
"name": "percent in a nested value is itself encoded",
|
|
719
|
-
"input": "ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%2523src/y",
|
|
720
|
-
"expect": {
|
|
721
|
-
"status": "ok",
|
|
722
|
-
"version": 1,
|
|
723
|
-
"qualifiers": [
|
|
724
|
-
[
|
|
725
|
-
"by",
|
|
726
|
-
"ref:pkg:npm/x@1.0.0%2523src/y"
|
|
727
|
-
]
|
|
728
|
-
],
|
|
729
|
-
"fragment": null,
|
|
730
|
-
"type": "folder",
|
|
731
|
-
"locator": "acme-tools",
|
|
732
|
-
"nested": {
|
|
733
|
-
"by": "ref:pkg:npm/x@1.0.0%23src/y"
|
|
734
|
-
}
|
|
735
|
-
}
|
|
736
|
-
},
|
|
737
|
-
{
|
|
738
|
-
"name": "empty fragment is malformed",
|
|
739
|
-
"input": "ref:folder:acme-tools#",
|
|
740
|
-
"expect": {
|
|
741
|
-
"status": "malformed",
|
|
742
|
-
"part": "fragment"
|
|
743
|
-
}
|
|
744
|
-
},
|
|
745
|
-
{
|
|
746
|
-
"name": "empty qualifier is malformed",
|
|
747
|
-
"input": "ref:folder:acme-tools;",
|
|
748
|
-
"expect": {
|
|
749
|
-
"status": "malformed",
|
|
750
|
-
"part": "state"
|
|
751
|
-
}
|
|
752
|
-
},
|
|
753
|
-
{
|
|
754
|
-
"name": "qualifier without a value separator is malformed",
|
|
755
|
-
"input": "ref:folder:acme-tools;at",
|
|
756
|
-
"expect": {
|
|
757
|
-
"status": "malformed",
|
|
758
|
-
"part": "state"
|
|
759
|
-
}
|
|
760
|
-
},
|
|
761
|
-
{
|
|
762
|
-
"name": "a nested value that is not a ref and not a digest fails the by validator",
|
|
763
|
-
"input": "ref:folder:acme-tools;by=rumdl",
|
|
764
|
-
"expect": {
|
|
765
|
-
"status": "malformed",
|
|
766
|
-
"part": "by"
|
|
767
|
-
}
|
|
768
|
-
},
|
|
769
|
-
{
|
|
770
|
-
"name": "a refinement key on the qualifier side is malformed",
|
|
771
|
-
"input": "ref:folder:acme-tools;lines=1#AGENTS.md",
|
|
772
|
-
"expect": {
|
|
773
|
-
"status": "malformed",
|
|
774
|
-
"part": "lines"
|
|
775
|
-
}
|
|
776
|
-
},
|
|
777
|
-
{
|
|
778
|
-
"name": "a qualifier key on the fragment side is malformed",
|
|
779
|
-
"input": "ref:folder:acme-tools#AGENTS.md;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
780
|
-
"expect": {
|
|
781
|
-
"status": "malformed",
|
|
782
|
-
"part": "state"
|
|
783
|
-
}
|
|
784
|
-
},
|
|
785
|
-
{
|
|
786
|
-
"name": "an empty path before a refinement is malformed",
|
|
787
|
-
"input": "ref:folder:acme-tools#;lines=1",
|
|
788
|
-
"expect": {
|
|
789
|
-
"status": "malformed",
|
|
790
|
-
"part": "fragment"
|
|
791
|
-
}
|
|
792
|
-
},
|
|
793
|
-
{
|
|
794
|
-
"name": "a nested identifier of an unsupported version is carried, not rejected",
|
|
795
|
-
"input": "ref:folder:acme-tools;by=ref:2:pkg:npm/x@1.0.0",
|
|
796
|
-
"expect": {
|
|
797
|
-
"status": "ok",
|
|
798
|
-
"version": 1,
|
|
799
|
-
"qualifiers": [
|
|
800
|
-
[
|
|
801
|
-
"by",
|
|
802
|
-
"ref:2:pkg:npm/x@1.0.0"
|
|
803
|
-
]
|
|
804
|
-
],
|
|
805
|
-
"fragment": null,
|
|
806
|
-
"type": "folder",
|
|
807
|
-
"locator": "acme-tools",
|
|
808
|
-
"nested": {
|
|
809
|
-
"by": "ref:2:pkg:npm/x@1.0.0"
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
},
|
|
813
|
-
{
|
|
814
|
-
"name": "a version token round-trips as written",
|
|
815
|
-
"input": "ref:01:pkg:npm/x@1.0.0",
|
|
816
|
-
"expect": {
|
|
817
|
-
"status": "ok",
|
|
818
|
-
"version": 1,
|
|
819
|
-
"qualifiers": [],
|
|
820
|
-
"fragment": null,
|
|
821
|
-
"type": "pkg",
|
|
822
|
-
"locator": "npm/x@1.0.0",
|
|
823
|
-
"explicitVersion": true,
|
|
824
|
-
"versionText": "01"
|
|
825
|
-
}
|
|
826
|
-
},
|
|
827
|
-
{
|
|
828
|
-
"name": "a trailing line break is malformed in every engine",
|
|
829
|
-
"input": "ref:folder:acme-tools\n",
|
|
830
|
-
"expect": {
|
|
831
|
-
"status": "malformed",
|
|
832
|
-
"part": "grammar"
|
|
833
|
-
}
|
|
834
|
-
},
|
|
835
|
-
{
|
|
836
|
-
"name": "a repeated qualifier key is malformed at that key",
|
|
837
|
-
"input": "ref:folder:acme-tools;state=swh:1:rev:7e29bb6000000000000000000000000000000000;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
838
|
-
"expect": {
|
|
839
|
-
"status": "malformed",
|
|
840
|
-
"part": "state"
|
|
841
|
-
}
|
|
842
|
-
},
|
|
843
|
-
{
|
|
844
|
-
"name": "a repeated refinement key is malformed at that key",
|
|
845
|
-
"input": "ref:folder:acme-tools#AGENTS.md;lines=1;lines=2",
|
|
846
|
-
"expect": {
|
|
847
|
-
"status": "malformed",
|
|
848
|
-
"part": "lines"
|
|
849
|
-
}
|
|
850
|
-
},
|
|
851
|
-
{
|
|
852
|
-
"name": "a raw percent in a nested value is malformed at the key",
|
|
853
|
-
"input": "ref:folder:acme-tools;by=ref:pkg:npm/%40acme/x@1.0.0",
|
|
854
|
-
"expect": {
|
|
855
|
-
"status": "malformed",
|
|
856
|
-
"part": "by"
|
|
857
|
-
}
|
|
858
|
-
},
|
|
859
|
-
{
|
|
860
|
-
"name": "a nested value carries the inner percent-encoding doubled",
|
|
861
|
-
"input": "ref:folder:acme-tools;by=ref:pkg:npm/%2540acme/x@1.0.0",
|
|
862
|
-
"expect": {
|
|
863
|
-
"status": "ok",
|
|
864
|
-
"version": 1,
|
|
865
|
-
"qualifiers": [
|
|
866
|
-
[
|
|
867
|
-
"by",
|
|
868
|
-
"ref:pkg:npm/%2540acme/x@1.0.0"
|
|
869
|
-
]
|
|
870
|
-
],
|
|
871
|
-
"fragment": null,
|
|
872
|
-
"type": "folder",
|
|
873
|
-
"locator": "acme-tools",
|
|
874
|
-
"nested": {
|
|
875
|
-
"by": "ref:pkg:npm/%40acme/x@1.0.0"
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
},
|
|
879
|
-
{
|
|
880
|
-
"name": "when carries a moment in UTC",
|
|
881
|
-
"input": "ref:pkg:npm/@acme/scanner-core;when=2026-08-12T18:55:27.811Z#governance@0.0.1/markdown-link",
|
|
882
|
-
"expect": {
|
|
883
|
-
"status": "ok",
|
|
884
|
-
"version": 1,
|
|
885
|
-
"qualifiers": [
|
|
886
|
-
[
|
|
887
|
-
"when",
|
|
888
|
-
"2026-08-12T18:55:27.811Z"
|
|
889
|
-
]
|
|
890
|
-
],
|
|
891
|
-
"fragment": {
|
|
892
|
-
"path": "governance@0.0.1/markdown-link",
|
|
893
|
-
"refinements": []
|
|
894
|
-
},
|
|
895
|
-
"type": "pkg",
|
|
896
|
-
"locator": "npm/@acme/scanner-core",
|
|
897
|
-
"delegated": "pkg:npm/@acme/scanner-core"
|
|
898
|
-
}
|
|
899
|
-
},
|
|
900
|
-
{
|
|
901
|
-
"name": "a moment with an offset is malformed at when",
|
|
902
|
-
"input": "ref:folder:acme-tools;when=2026-08-12T15:55:27-03:00",
|
|
903
|
-
"expect": {
|
|
904
|
-
"status": "malformed",
|
|
905
|
-
"part": "when"
|
|
906
|
-
}
|
|
907
|
-
},
|
|
908
|
-
{
|
|
909
|
-
"name": "a typed governed-record fragment on an unversioned package corpus",
|
|
910
|
-
"input": "ref:pkg:npm/acme-tools#acme/adr@2/0019",
|
|
911
|
-
"expect": {
|
|
912
|
-
"status": "ok",
|
|
913
|
-
"version": 1,
|
|
914
|
-
"qualifiers": [],
|
|
915
|
-
"fragment": {
|
|
916
|
-
"path": "acme/adr@2/0019",
|
|
917
|
-
"refinements": []
|
|
918
|
-
},
|
|
919
|
-
"type": "pkg",
|
|
920
|
-
"locator": "npm/acme-tools",
|
|
921
|
-
"delegated": "pkg:npm/acme-tools"
|
|
922
|
-
}
|
|
923
|
-
},
|
|
924
|
-
{
|
|
925
|
-
"name": "dot-agent id in the unknown namespace tier",
|
|
926
|
-
"input": "ref:dot-agent:unknown/MentorUniversitario:1.4.1",
|
|
927
|
-
"expect": {
|
|
928
|
-
"status": "ok",
|
|
929
|
-
"version": 1,
|
|
930
|
-
"qualifiers": [],
|
|
931
|
-
"fragment": null,
|
|
932
|
-
"type": "dot-agent",
|
|
933
|
-
"locator": "unknown/MentorUniversitario:1.4.1"
|
|
934
|
-
}
|
|
935
|
-
},
|
|
936
|
-
{
|
|
937
|
-
"name": "dot-agent id under a domain, its digest carried by state",
|
|
938
|
-
"input": "ref:dot-agent:acme.example/doctor:v1.0;state=git:a1b2c3d4",
|
|
939
|
-
"expect": {
|
|
940
|
-
"status": "ok",
|
|
941
|
-
"version": 1,
|
|
942
|
-
"qualifiers": [
|
|
943
|
-
[
|
|
944
|
-
"state",
|
|
945
|
-
"git:a1b2c3d4"
|
|
946
|
-
]
|
|
947
|
-
],
|
|
948
|
-
"fragment": null,
|
|
949
|
-
"type": "dot-agent",
|
|
950
|
-
"locator": "acme.example/doctor:v1.0"
|
|
951
|
-
}
|
|
952
|
-
},
|
|
953
|
-
{
|
|
954
|
-
"name": "dot-agent id under a platform user and under a mailbox",
|
|
955
|
-
"input": "ref:dot-agent:github.example/someone/doctor",
|
|
956
|
-
"expect": {
|
|
957
|
-
"status": "ok",
|
|
958
|
-
"version": 1,
|
|
959
|
-
"qualifiers": [],
|
|
960
|
-
"fragment": null,
|
|
961
|
-
"type": "dot-agent",
|
|
962
|
-
"locator": "github.example/someone/doctor"
|
|
963
|
-
}
|
|
964
|
-
},
|
|
965
|
-
{
|
|
966
|
-
"name": "dot-agent id with a mailbox namespace",
|
|
967
|
-
"input": "ref:dot-agent:someone@mail.example/doctor:v2",
|
|
968
|
-
"expect": {
|
|
969
|
-
"status": "ok",
|
|
970
|
-
"version": 1,
|
|
971
|
-
"qualifiers": [],
|
|
972
|
-
"fragment": null,
|
|
973
|
-
"type": "dot-agent",
|
|
974
|
-
"locator": "someone@mail.example/doctor:v2"
|
|
975
|
-
}
|
|
976
|
-
},
|
|
977
|
-
{
|
|
978
|
-
"name": "a dotted namespace reads as the domain tier — whether the domain exists is the ecosystem's check, never the grammar's",
|
|
979
|
-
"input": "ref:dot-agent:mentor.pessoal.agent/MentorUniversitario:1.4.1",
|
|
980
|
-
"expect": {
|
|
981
|
-
"status": "ok",
|
|
982
|
-
"version": 1,
|
|
983
|
-
"qualifiers": [],
|
|
984
|
-
"fragment": null,
|
|
985
|
-
"type": "dot-agent",
|
|
986
|
-
"locator": "mentor.pessoal.agent/MentorUniversitario:1.4.1"
|
|
987
|
-
}
|
|
988
|
-
},
|
|
989
|
-
{
|
|
990
|
-
"name": "a domain names a corpus",
|
|
991
|
-
"input": "ref:domain:portfolio.example",
|
|
992
|
-
"expect": {
|
|
993
|
-
"status": "ok",
|
|
994
|
-
"version": 1,
|
|
995
|
-
"qualifiers": [],
|
|
996
|
-
"fragment": null,
|
|
997
|
-
"type": "domain",
|
|
998
|
-
"locator": "portfolio.example"
|
|
999
|
-
}
|
|
1000
|
-
},
|
|
1001
|
-
{
|
|
1002
|
-
"name": "a declared name under a domain, versioned, with a section fragment",
|
|
1003
|
-
"input": "ref:domain:portfolio.example/case-xpto@2#results",
|
|
1004
|
-
"expect": {
|
|
1005
|
-
"status": "ok",
|
|
1006
|
-
"version": 1,
|
|
1007
|
-
"qualifiers": [],
|
|
1008
|
-
"fragment": {
|
|
1009
|
-
"path": "results",
|
|
1010
|
-
"refinements": []
|
|
1011
|
-
},
|
|
1012
|
-
"type": "domain",
|
|
1013
|
-
"locator": "portfolio.example/case-xpto@2"
|
|
1014
|
-
}
|
|
1015
|
-
},
|
|
1016
|
-
{
|
|
1017
|
-
"name": "an uppercase host is malformed at the locator",
|
|
1018
|
-
"input": "ref:domain:Portfolio.example/case",
|
|
1019
|
-
"expect": {
|
|
1020
|
-
"status": "malformed",
|
|
1021
|
-
"part": "locator"
|
|
1022
|
-
}
|
|
1023
|
-
},
|
|
1024
|
-
{
|
|
1025
|
-
"name": "a mailbox identifies a person",
|
|
1026
|
-
"input": "ref:email:someone@mail.example",
|
|
1027
|
-
"expect": {
|
|
1028
|
-
"status": "ok",
|
|
1029
|
-
"version": 1,
|
|
1030
|
-
"qualifiers": [],
|
|
1031
|
-
"fragment": null,
|
|
1032
|
-
"type": "email",
|
|
1033
|
-
"locator": "someone@mail.example"
|
|
1034
|
-
}
|
|
1035
|
-
},
|
|
1036
|
-
{
|
|
1037
|
-
"name": "nothing lives under a mailbox",
|
|
1038
|
-
"input": "ref:email:someone@mail.example/doctor",
|
|
1039
|
-
"expect": {
|
|
1040
|
-
"status": "malformed",
|
|
1041
|
-
"part": "locator"
|
|
1042
|
-
}
|
|
1043
|
-
},
|
|
1044
|
-
{
|
|
1045
|
-
"name": "an unregistered naming system is uncovered",
|
|
1046
|
-
"input": "ref:spotify:track/4uLU6hMCjMI75M1A2tKUQC",
|
|
1047
|
-
"expect": {
|
|
1048
|
-
"status": "uncovered",
|
|
1049
|
-
"version": 1,
|
|
1050
|
-
"type": "spotify",
|
|
1051
|
-
"locator": "track/4uLU6hMCjMI75M1A2tKUQC"
|
|
1052
|
-
}
|
|
1053
|
-
},
|
|
1054
|
-
{
|
|
1055
|
-
"name": "a content hash freezes what no version control holds",
|
|
1056
|
-
"input": "ref:domain:models.example/quant-q4;state=blake3:0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f",
|
|
1057
|
-
"expect": {
|
|
1058
|
-
"status": "ok",
|
|
1059
|
-
"version": 1,
|
|
1060
|
-
"qualifiers": [
|
|
1061
|
-
[
|
|
1062
|
-
"state",
|
|
1063
|
-
"blake3:0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
|
|
1064
|
-
]
|
|
1065
|
-
],
|
|
1066
|
-
"fragment": null,
|
|
1067
|
-
"type": "domain",
|
|
1068
|
-
"locator": "models.example/quant-q4"
|
|
1069
|
-
}
|
|
1070
|
-
},
|
|
1071
|
-
{
|
|
1072
|
-
"name": "none is a declared state level",
|
|
1073
|
-
"input": "ref:domain:models.example/quant-q4;state=none",
|
|
1074
|
-
"expect": {
|
|
1075
|
-
"status": "ok",
|
|
1076
|
-
"version": 1,
|
|
1077
|
-
"qualifiers": [
|
|
1078
|
-
[
|
|
1079
|
-
"state",
|
|
1080
|
-
"none"
|
|
1081
|
-
]
|
|
1082
|
-
],
|
|
1083
|
-
"fragment": null,
|
|
1084
|
-
"type": "domain",
|
|
1085
|
-
"locator": "models.example/quant-q4"
|
|
1086
|
-
}
|
|
1087
|
-
},
|
|
1088
|
-
{
|
|
1089
|
-
"name": "a state in an undeclared form is malformed at state",
|
|
1090
|
-
"input": "ref:domain:models.example/quant-q4;state=sha1:0f0f0f0f",
|
|
1091
|
-
"expect": {
|
|
1092
|
-
"status": "malformed",
|
|
1093
|
-
"part": "state"
|
|
1094
|
-
}
|
|
1095
|
-
},
|
|
1096
|
-
{
|
|
1097
|
-
"name": "uppercase type is malformed",
|
|
1098
|
-
"input": "ref:Pkg:npm/x@1.0.0",
|
|
1099
|
-
"expect": {
|
|
1100
|
-
"status": "malformed",
|
|
1101
|
-
"part": "grammar"
|
|
1102
|
-
}
|
|
1103
|
-
},
|
|
1104
|
-
{
|
|
1105
|
-
"name": "missing scheme is malformed",
|
|
1106
|
-
"input": "pkg:npm/x@1.0.0",
|
|
1107
|
-
"expect": {
|
|
1108
|
-
"status": "malformed",
|
|
1109
|
-
"part": "grammar"
|
|
1110
|
-
}
|
|
1111
|
-
},
|
|
1112
|
-
{
|
|
1113
|
-
"name": "empty locator is malformed",
|
|
1114
|
-
"input": "ref:pkg:",
|
|
1115
|
-
"expect": {
|
|
1116
|
-
"status": "malformed",
|
|
1117
|
-
"part": "grammar"
|
|
1118
|
-
}
|
|
1119
|
-
},
|
|
1120
|
-
{
|
|
1121
|
-
"name": "abbreviated SWHID fails the state validator",
|
|
1122
|
-
"input": "ref:folder:acme-tools;state=swh:1:rev:7e29bb6",
|
|
1123
|
-
"expect": {
|
|
1124
|
-
"status": "malformed",
|
|
1125
|
-
"part": "state"
|
|
1126
|
-
}
|
|
1127
|
-
},
|
|
1128
|
-
{
|
|
1129
|
-
"name": "invalid purl fails the locator validator",
|
|
1130
|
-
"input": "ref:pkg:not-a-purl",
|
|
1131
|
-
"expect": {
|
|
1132
|
-
"status": "malformed",
|
|
1133
|
-
"part": "locator"
|
|
1134
|
-
}
|
|
1135
|
-
},
|
|
1136
|
-
{
|
|
1137
|
-
"name": "malformed refinement value",
|
|
1138
|
-
"input": "ref:folder:acme-tools#AGENTS.md;lines=ten",
|
|
1139
|
-
"expect": {
|
|
1140
|
-
"status": "malformed",
|
|
1141
|
-
"part": "lines"
|
|
1142
|
-
}
|
|
1143
|
-
},
|
|
1144
|
-
{
|
|
1145
|
-
"name": "corpus name with a path separator is malformed",
|
|
1146
|
-
"input": "ref:folder:acme-tools/docs#AGENTS.md",
|
|
1147
|
-
"expect": {
|
|
1148
|
-
"status": "malformed",
|
|
1149
|
-
"part": "locator"
|
|
1150
|
-
}
|
|
1151
|
-
},
|
|
1152
|
-
{
|
|
1153
|
-
"name": "ai-model served id is admitted: Qwen3-4B-Instruct-2507-4bit",
|
|
1154
|
-
"input": "ref:ai-model:Qwen3-4B-Instruct-2507-4bit",
|
|
1155
|
-
"expect": {
|
|
1156
|
-
"status": "ok",
|
|
1157
|
-
"version": 1,
|
|
1158
|
-
"qualifiers": [],
|
|
1159
|
-
"fragment": null,
|
|
1160
|
-
"type": "ai-model",
|
|
1161
|
-
"locator": "Qwen3-4B-Instruct-2507-4bit"
|
|
1162
|
-
}
|
|
1163
|
-
},
|
|
1164
|
-
{
|
|
1165
|
-
"name": "ai-model served id is admitted: gemma-4-26b-a4b-it-4bit",
|
|
1166
|
-
"input": "ref:ai-model:gemma-4-26b-a4b-it-4bit",
|
|
1167
|
-
"expect": {
|
|
1168
|
-
"status": "ok",
|
|
1169
|
-
"version": 1,
|
|
1170
|
-
"qualifiers": [],
|
|
1171
|
-
"fragment": null,
|
|
1172
|
-
"type": "ai-model",
|
|
1173
|
-
"locator": "gemma-4-26b-a4b-it-4bit"
|
|
1174
|
-
}
|
|
1175
|
-
},
|
|
1176
|
-
{
|
|
1177
|
-
"name": "ai-model served id is admitted: Qwen3.5-9B-OptiQ-4bit",
|
|
1178
|
-
"input": "ref:ai-model:Qwen3.5-9B-OptiQ-4bit",
|
|
1179
|
-
"expect": {
|
|
1180
|
-
"status": "ok",
|
|
1181
|
-
"version": 1,
|
|
1182
|
-
"qualifiers": [],
|
|
1183
|
-
"fragment": null,
|
|
1184
|
-
"type": "ai-model",
|
|
1185
|
-
"locator": "Qwen3.5-9B-OptiQ-4bit"
|
|
1186
|
-
}
|
|
1187
|
-
},
|
|
1188
|
-
{
|
|
1189
|
-
"name": "ai-model served id is admitted: gpt-oss-20b-MXFP4-Q8",
|
|
1190
|
-
"input": "ref:ai-model:gpt-oss-20b-MXFP4-Q8",
|
|
1191
|
-
"expect": {
|
|
1192
|
-
"status": "ok",
|
|
1193
|
-
"version": 1,
|
|
1194
|
-
"qualifiers": [],
|
|
1195
|
-
"fragment": null,
|
|
1196
|
-
"type": "ai-model",
|
|
1197
|
-
"locator": "gpt-oss-20b-MXFP4-Q8"
|
|
1198
|
-
}
|
|
1199
|
-
},
|
|
1200
|
-
{
|
|
1201
|
-
"name": "ai-model served id is admitted: Llama-3.2-1B-Instruct-4bit",
|
|
1202
|
-
"input": "ref:ai-model:Llama-3.2-1B-Instruct-4bit",
|
|
1203
|
-
"expect": {
|
|
1204
|
-
"status": "ok",
|
|
1205
|
-
"version": 1,
|
|
1206
|
-
"qualifiers": [],
|
|
1207
|
-
"fragment": null,
|
|
1208
|
-
"type": "ai-model",
|
|
1209
|
-
"locator": "Llama-3.2-1B-Instruct-4bit"
|
|
1210
|
-
}
|
|
1211
|
-
},
|
|
1212
|
-
{
|
|
1213
|
-
"name": "ai-model served id is admitted: Qwen3.5-27B-Claude-4.6-Opus-Distilled-MLX-4bit",
|
|
1214
|
-
"input": "ref:ai-model:Qwen3.5-27B-Claude-4.6-Opus-Distilled-MLX-4bit",
|
|
1215
|
-
"expect": {
|
|
1216
|
-
"status": "ok",
|
|
1217
|
-
"version": 1,
|
|
1218
|
-
"qualifiers": [],
|
|
1219
|
-
"fragment": null,
|
|
1220
|
-
"type": "ai-model",
|
|
1221
|
-
"locator": "Qwen3.5-27B-Claude-4.6-Opus-Distilled-MLX-4bit"
|
|
1222
|
-
}
|
|
1223
|
-
},
|
|
1224
|
-
{
|
|
1225
|
-
"name": "ai-model served id is admitted: SmolLM3-3B-4bit",
|
|
1226
|
-
"input": "ref:ai-model:SmolLM3-3B-4bit",
|
|
1227
|
-
"expect": {
|
|
1228
|
-
"status": "ok",
|
|
1229
|
-
"version": 1,
|
|
1230
|
-
"qualifiers": [],
|
|
1231
|
-
"fragment": null,
|
|
1232
|
-
"type": "ai-model",
|
|
1233
|
-
"locator": "SmolLM3-3B-4bit"
|
|
1234
|
-
}
|
|
1235
|
-
},
|
|
1236
|
-
{
|
|
1237
|
-
"name": "ai-model served id is admitted: T-mixed-gemma-4-12B-it-OptiQ-4bit",
|
|
1238
|
-
"input": "ref:ai-model:T-mixed-gemma-4-12B-it-OptiQ-4bit",
|
|
1239
|
-
"expect": {
|
|
1240
|
-
"status": "ok",
|
|
1241
|
-
"version": 1,
|
|
1242
|
-
"qualifiers": [],
|
|
1243
|
-
"fragment": null,
|
|
1244
|
-
"type": "ai-model",
|
|
1245
|
-
"locator": "T-mixed-gemma-4-12B-it-OptiQ-4bit"
|
|
1246
|
-
}
|
|
1247
|
-
},
|
|
1248
|
-
{
|
|
1249
|
-
"name": "ai-model served id is admitted: claude-opus-5",
|
|
1250
|
-
"input": "ref:ai-model:claude-opus-5",
|
|
1251
|
-
"expect": {
|
|
1252
|
-
"status": "ok",
|
|
1253
|
-
"version": 1,
|
|
1254
|
-
"qualifiers": [],
|
|
1255
|
-
"fragment": null,
|
|
1256
|
-
"type": "ai-model",
|
|
1257
|
-
"locator": "claude-opus-5"
|
|
1258
|
-
}
|
|
1259
|
-
},
|
|
1260
|
-
{
|
|
1261
|
-
"name": "ai-model served id is admitted: Ternary-Bonsai-27B-mlx-2bit",
|
|
1262
|
-
"input": "ref:ai-model:Ternary-Bonsai-27B-mlx-2bit",
|
|
1263
|
-
"expect": {
|
|
1264
|
-
"status": "ok",
|
|
1265
|
-
"version": 1,
|
|
1266
|
-
"qualifiers": [],
|
|
1267
|
-
"fragment": null,
|
|
1268
|
-
"type": "ai-model",
|
|
1269
|
-
"locator": "Ternary-Bonsai-27B-mlx-2bit"
|
|
1270
|
-
}
|
|
1271
|
-
},
|
|
1272
|
-
{
|
|
1273
|
-
"name": "ai-model served id is admitted: gemini-2.5-flash",
|
|
1274
|
-
"input": "ref:ai-model:gemini-2.5-flash",
|
|
1275
|
-
"expect": {
|
|
1276
|
-
"status": "ok",
|
|
1277
|
-
"version": 1,
|
|
1278
|
-
"qualifiers": [],
|
|
1279
|
-
"fragment": null,
|
|
1280
|
-
"type": "ai-model",
|
|
1281
|
-
"locator": "gemini-2.5-flash"
|
|
1282
|
-
}
|
|
1283
|
-
},
|
|
1284
|
-
{
|
|
1285
|
-
"name": "ai-model served id is admitted: llama3:8b",
|
|
1286
|
-
"input": "ref:ai-model:llama3:8b",
|
|
1287
|
-
"expect": {
|
|
1288
|
-
"status": "ok",
|
|
1289
|
-
"version": 1,
|
|
1290
|
-
"qualifiers": [],
|
|
1291
|
-
"fragment": null,
|
|
1292
|
-
"type": "ai-model",
|
|
1293
|
-
"locator": "llama3:8b"
|
|
1294
|
-
}
|
|
1295
|
-
},
|
|
1296
|
-
{
|
|
1297
|
-
"name": "ai-model served id is admitted: gpt-4o-2024-08-06",
|
|
1298
|
-
"input": "ref:ai-model:gpt-4o-2024-08-06",
|
|
1299
|
-
"expect": {
|
|
1300
|
-
"status": "ok",
|
|
1301
|
-
"version": 1,
|
|
1302
|
-
"qualifiers": [],
|
|
1303
|
-
"fragment": null,
|
|
1304
|
-
"type": "ai-model",
|
|
1305
|
-
"locator": "gpt-4o-2024-08-06"
|
|
1306
|
-
}
|
|
1307
|
-
},
|
|
1308
|
-
{
|
|
1309
|
-
"name": "ai-model served id is admitted: mlx-community/Qwen3-1.7B-4bit",
|
|
1310
|
-
"input": "ref:ai-model:mlx-community/Qwen3-1.7B-4bit",
|
|
1311
|
-
"expect": {
|
|
1312
|
-
"status": "ok",
|
|
1313
|
-
"version": 1,
|
|
1314
|
-
"qualifiers": [],
|
|
1315
|
-
"fragment": null,
|
|
1316
|
-
"type": "ai-model",
|
|
1317
|
-
"locator": "mlx-community/Qwen3-1.7B-4bit"
|
|
1318
|
-
}
|
|
1319
|
-
},
|
|
1320
|
-
{
|
|
1321
|
-
"name": "an ai-model id cannot open on a separator",
|
|
1322
|
-
"input": "ref:ai-model:-Qwen3-4B",
|
|
1323
|
-
"expect": {
|
|
1324
|
-
"status": "malformed",
|
|
1325
|
-
"part": "locator"
|
|
1326
|
-
}
|
|
1327
|
-
},
|
|
1328
|
-
{
|
|
1329
|
-
"name": "unknown is a declared population level",
|
|
1330
|
-
"input": "ref:folder:acme-tools;over=unknown",
|
|
1331
|
-
"expect": {
|
|
1332
|
-
"status": "ok",
|
|
1333
|
-
"version": 1,
|
|
1334
|
-
"qualifiers": [
|
|
1335
|
-
[
|
|
1336
|
-
"over",
|
|
1337
|
-
"unknown"
|
|
1338
|
-
]
|
|
1339
|
-
],
|
|
1340
|
-
"fragment": null,
|
|
1341
|
-
"type": "folder",
|
|
1342
|
-
"locator": "acme-tools"
|
|
1343
|
-
}
|
|
1344
|
-
},
|
|
1345
|
-
{
|
|
1346
|
-
"name": "none is not a population level — a population of zero is not a population nobody recorded",
|
|
1347
|
-
"input": "ref:folder:acme-tools;over=none",
|
|
1348
|
-
"expect": {
|
|
1349
|
-
"status": "malformed",
|
|
1350
|
-
"part": "over"
|
|
1351
|
-
}
|
|
1352
|
-
},
|
|
1353
|
-
{
|
|
1354
|
-
"name": "unknown is not a state level — the fence from the other side",
|
|
1355
|
-
"input": "ref:folder:acme-tools;state=unknown",
|
|
1356
|
-
"expect": {
|
|
1357
|
-
"status": "malformed",
|
|
1358
|
-
"part": "state"
|
|
1359
|
-
}
|
|
1360
|
-
},
|
|
1361
|
-
{
|
|
1362
|
-
"name": "unknown is declared for over alone, never for by",
|
|
1363
|
-
"input": "ref:folder:acme-tools;by=unknown",
|
|
1364
|
-
"expect": {
|
|
1365
|
-
"status": "malformed",
|
|
1366
|
-
"part": "by"
|
|
1367
|
-
}
|
|
1368
|
-
},
|
|
1369
|
-
{
|
|
1370
|
-
"name": "an ai-model id cannot carry a character outside its declared class",
|
|
1371
|
-
"input": "ref:ai-model:a b",
|
|
1372
|
-
"expect": {
|
|
1373
|
-
"status": "malformed",
|
|
1374
|
-
"part": "locator"
|
|
1375
|
-
}
|
|
1376
|
-
},
|
|
1377
|
-
{
|
|
1378
|
-
"name": "an ai-model id carries a quantisation key after @",
|
|
1379
|
-
"input": "ref:ai-model:qwen2.5-7b-instruct@q4_k_m",
|
|
1380
|
-
"expect": {
|
|
1381
|
-
"status": "ok",
|
|
1382
|
-
"version": 1,
|
|
1383
|
-
"type": "ai-model",
|
|
1384
|
-
"locator": "qwen2.5-7b-instruct@q4_k_m",
|
|
1385
|
-
"qualifiers": [],
|
|
1386
|
-
"fragment": null
|
|
1387
|
-
}
|
|
1388
|
-
},
|
|
1389
|
-
{
|
|
1390
|
-
"name": "an ai-model id cannot traverse — every segment opens on an alphanumeric",
|
|
1391
|
-
"input": "ref:ai-model:a/../../etc/passwd",
|
|
1392
|
-
"expect": {
|
|
1393
|
-
"status": "malformed",
|
|
1394
|
-
"part": "locator"
|
|
1395
|
-
}
|
|
1396
|
-
},
|
|
1397
|
-
{
|
|
1398
|
-
"name": "an ai-model id cannot carry an empty segment",
|
|
1399
|
-
"input": "ref:ai-model:a//b",
|
|
1400
|
-
"expect": {
|
|
1401
|
-
"status": "malformed",
|
|
1402
|
-
"part": "locator"
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
2048
|
+
"expect": "ref:ai-model:llama3:8b"
|
|
2049
|
+
},
|
|
2050
|
+
{
|
|
2051
|
+
"name": "over=unknown builds as the declared level for an unestablished population",
|
|
2052
|
+
"parts": {
|
|
2053
|
+
"type": "folder",
|
|
2054
|
+
"locator": "acme-tools",
|
|
2055
|
+
"qualifiers": [
|
|
2056
|
+
[
|
|
2057
|
+
"over",
|
|
2058
|
+
"unknown"
|
|
2059
|
+
]
|
|
2060
|
+
]
|
|
2061
|
+
},
|
|
2062
|
+
"expect": "ref:folder:acme-tools;over=unknown"
|
|
2063
|
+
}
|
|
2064
|
+
],
|
|
2065
|
+
"digest": [
|
|
2066
|
+
{
|
|
2067
|
+
"name": "two members in declared order",
|
|
2068
|
+
"members": [
|
|
2069
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000",
|
|
2070
|
+
"ref:folder:acme-tools#GOVERNANCE.md;state=swh:1:cnt:48db124700000000000000000000000000000000"
|
|
1405
2071
|
],
|
|
1406
|
-
"
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
"name": "two qualifiers written out of order sort by key",
|
|
1414
|
-
"input": "ref:eita:structured-output@1/validity;when=2026-08-02T18:31:31.870Z;over=unknown",
|
|
1415
|
-
"expect": "ref:eita:structured-output@1/validity;over=unknown;when=2026-08-02T18:31:31.870Z"
|
|
1416
|
-
},
|
|
1417
|
-
{
|
|
1418
|
-
"name": "the same qualifiers in the other order reach the same form",
|
|
1419
|
-
"input": "ref:eita:structured-output@1/validity;over=unknown;when=2026-08-02T18:31:31.870Z",
|
|
1420
|
-
"expect": "ref:eita:structured-output@1/validity;over=unknown;when=2026-08-02T18:31:31.870Z"
|
|
1421
|
-
},
|
|
1422
|
-
{
|
|
1423
|
-
"name": "an unknown key sorts beside a declared one, carried through",
|
|
1424
|
-
"input": "ref:eita:citation-fidelity@1/exact;when=2026-08-14T23:38:26.089Z;context-tokens=8000;over=unknown",
|
|
1425
|
-
"expect": "ref:eita:citation-fidelity@1/exact;context-tokens=8000;over=unknown;when=2026-08-14T23:38:26.089Z"
|
|
1426
|
-
},
|
|
1427
|
-
{
|
|
1428
|
-
"name": "sorting is by UTF-16 code unit, so a hyphen precedes a letter",
|
|
1429
|
-
"input": "ref:eita:t@1/o;alphaone=1;alpha-two=2;alpha=3",
|
|
1430
|
-
"expect": "ref:eita:t@1/o;alpha=3;alpha-two=2;alphaone=1"
|
|
1431
|
-
},
|
|
1432
|
-
{
|
|
1433
|
-
"name": "a nested value is not decoded by canonicalisation",
|
|
1434
|
-
"input": "ref:eita:t@1/o;when=2026-08-02T18:31:31.870Z;over=ref:ai-model:Qwen3-4B-Instruct-2507-4bit",
|
|
1435
|
-
"expect": "ref:eita:t@1/o;over=ref:ai-model:Qwen3-4B-Instruct-2507-4bit;when=2026-08-02T18:31:31.870Z"
|
|
1436
|
-
},
|
|
1437
|
-
{
|
|
1438
|
-
"name": "no qualifiers, nothing to sort",
|
|
1439
|
-
"input": "ref:pkg:npm/@acme/scanner-core@0.1.0#Observation",
|
|
1440
|
-
"expect": "ref:pkg:npm/@acme/scanner-core@0.1.0#Observation"
|
|
1441
|
-
},
|
|
1442
|
-
{
|
|
1443
|
-
"name": "an explicit version survives canonicalisation verbatim",
|
|
1444
|
-
"input": "ref:1:pkg:npm/x@1.0.0;state=none;by=sha256:0000000000000000000000000000000000000000000000000000000000000000",
|
|
1445
|
-
"expect": "ref:1:pkg:npm/x@1.0.0;by=sha256:0000000000000000000000000000000000000000000000000000000000000000;state=none"
|
|
1446
|
-
},
|
|
1447
|
-
{
|
|
1448
|
-
"name": "refinements are positional and keep the order they were written",
|
|
1449
|
-
"input": "ref:folder:acme-governance;state=none#AGENTS.md;lines=1,20;item=3",
|
|
1450
|
-
"expect": "ref:folder:acme-governance;state=none#AGENTS.md;lines=1,20;item=3"
|
|
1451
|
-
},
|
|
1452
|
-
{
|
|
1453
|
-
"name": "qualifiers sort while the fragment beside them is untouched",
|
|
1454
|
-
"input": "ref:folder:acme-governance;when=2026-08-02T18:31:31.870Z;state=none#AGENTS.md;lines=1,20",
|
|
1455
|
-
"expect": "ref:folder:acme-governance;state=none;when=2026-08-02T18:31:31.870Z#AGENTS.md;lines=1,20"
|
|
1456
|
-
},
|
|
1457
|
-
{
|
|
1458
|
-
"name": "a malformed identifier has no canonical form",
|
|
1459
|
-
"input": "ref:eita:t@1/o;state=none;state=none",
|
|
1460
|
-
"expect": { "error": "state" }
|
|
1461
|
-
}
|
|
2072
|
+
"expect": "sha256:75433bb5329808aa4064084a54173f0328926eb38ddce742f61cbd4f0ebba71e"
|
|
2073
|
+
},
|
|
2074
|
+
{
|
|
2075
|
+
"name": "same members, other order, different digest",
|
|
2076
|
+
"members": [
|
|
2077
|
+
"ref:folder:acme-tools#GOVERNANCE.md;state=swh:1:cnt:48db124700000000000000000000000000000000",
|
|
2078
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
1462
2079
|
],
|
|
1463
|
-
"
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
"ref:folder:acme-tools;zz=a%3Bb;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
1471
|
-
"ref:folder:acme-tools;state=swh:1:cnt:3404a00f00000000000000000000000000000000#AGENTS.md;lines=1",
|
|
1472
|
-
"ref:folder:acme-tools#AGENTS.md;zz=q",
|
|
1473
|
-
"ref:doi:10.1000/182",
|
|
1474
|
-
"ref:dot-agent:unknown/MentorUniversitario:1.4.1",
|
|
1475
|
-
"ref:domain:portfolio.example/case-xpto@2;state=none#results",
|
|
1476
|
-
"ref:email:someone@mail.example",
|
|
1477
|
-
"ref:2:pkg:npm/x@1.0.0",
|
|
1478
|
-
"ref:01:pkg:npm/x@1.0.0",
|
|
1479
|
-
"ref:pkg:npm/@acme/scanner-core;when=2026-08-12T18:55:27.811Z#governance@0.0.1/markdown-link",
|
|
1480
|
-
"ref:pkg:npm/acme-tools#acme/adr@2/0019",
|
|
1481
|
-
"ref:folder:acme-tools;by=ref:2:pkg:npm/x@1.0.0",
|
|
1482
|
-
"ref:doi:10.1000/182;state=swh:1:rev:7e29bb6000000000000000000000000000000000#S",
|
|
1483
|
-
"ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%2523src/y",
|
|
1484
|
-
"ref:ai-model:mlx-community/Qwen3-1.7B-4bit",
|
|
1485
|
-
"ref:ai-model:llama3:8b",
|
|
1486
|
-
"ref:folder:acme-tools;over=unknown"
|
|
2080
|
+
"expect": "sha256:83eee8e9bcff34577a3d305bddebef2685a2e6bb20644e5a2ff29c9a8602a25b"
|
|
2081
|
+
},
|
|
2082
|
+
{
|
|
2083
|
+
"name": "a repeated member is not deduplicated",
|
|
2084
|
+
"members": [
|
|
2085
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000",
|
|
2086
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
1487
2087
|
],
|
|
1488
|
-
"
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
"fragment": "Observation",
|
|
1495
|
-
"location": {
|
|
1496
|
-
"path": "src/a.ts"
|
|
1497
|
-
}
|
|
1498
|
-
},
|
|
1499
|
-
"expect": "ref:pkg:npm/x@1.0.0#Observation"
|
|
1500
|
-
},
|
|
1501
|
-
{
|
|
1502
|
-
"name": "same declared name through two paths is one identifier (other path)",
|
|
1503
|
-
"parts": {
|
|
1504
|
-
"type": "pkg",
|
|
1505
|
-
"locator": "npm/x@1.0.0",
|
|
1506
|
-
"fragment": "Observation",
|
|
1507
|
-
"location": {
|
|
1508
|
-
"path": "lib/b.ts",
|
|
1509
|
-
"lines": "4,9"
|
|
1510
|
-
}
|
|
1511
|
-
},
|
|
1512
|
-
"expect": "ref:pkg:npm/x@1.0.0#Observation"
|
|
1513
|
-
},
|
|
1514
|
-
{
|
|
1515
|
-
"name": "nested qualifier value is encoded by the builder",
|
|
1516
|
-
"parts": {
|
|
1517
|
-
"type": "folder",
|
|
1518
|
-
"locator": "acme-tools",
|
|
1519
|
-
"qualifiers": [
|
|
1520
|
-
[
|
|
1521
|
-
"by",
|
|
1522
|
-
{
|
|
1523
|
-
"nested": "ref:pkg:npm/x@1.0.0;state=swh:1:rev:7e29bb6000000000000000000000000000000000#S"
|
|
1524
|
-
}
|
|
1525
|
-
]
|
|
1526
|
-
]
|
|
1527
|
-
},
|
|
1528
|
-
"expect": "ref:folder:acme-tools;by=ref:pkg:npm/x@1.0.0%3Bstate=swh:1:rev:7e29bb6000000000000000000000000000000000%23S"
|
|
1529
|
-
},
|
|
1530
|
-
{
|
|
1531
|
-
"name": "a pkg locator given as the bare group builds as is",
|
|
1532
|
-
"parts": {
|
|
1533
|
-
"type": "pkg",
|
|
1534
|
-
"locator": "npm/x@1.0.0",
|
|
1535
|
-
"fragment": "Observation"
|
|
1536
|
-
},
|
|
1537
|
-
"expect": "ref:pkg:npm/x@1.0.0#Observation"
|
|
1538
|
-
},
|
|
1539
|
-
{
|
|
1540
|
-
"name": "an intact purl given as locator has its scheme folded into the type",
|
|
1541
|
-
"parts": {
|
|
1542
|
-
"type": "pkg",
|
|
1543
|
-
"locator": "pkg:npm/x@1.0.0",
|
|
1544
|
-
"fragment": "S"
|
|
1545
|
-
},
|
|
1546
|
-
"expect": "ref:pkg:npm/x@1.0.0#S"
|
|
1547
|
-
},
|
|
1548
|
-
{
|
|
1549
|
-
"name": "a locator carrying a reserved character is refused",
|
|
1550
|
-
"parts": {
|
|
1551
|
-
"type": "pkg",
|
|
1552
|
-
"locator": "pkg:npm/x@1.0.0#src/y",
|
|
1553
|
-
"fragment": "S"
|
|
1554
|
-
},
|
|
1555
|
-
"expect": {
|
|
1556
|
-
"error": "locator"
|
|
1557
|
-
}
|
|
1558
|
-
},
|
|
1559
|
-
{
|
|
1560
|
-
"name": "a fragment path carrying the separator is refused",
|
|
1561
|
-
"parts": {
|
|
1562
|
-
"type": "folder",
|
|
1563
|
-
"locator": "acme-tools",
|
|
1564
|
-
"fragment": "a;b"
|
|
1565
|
-
},
|
|
1566
|
-
"expect": {
|
|
1567
|
-
"error": "fragment"
|
|
1568
|
-
}
|
|
1569
|
-
},
|
|
1570
|
-
{
|
|
1571
|
-
"name": "a nested identifier passed as a plain string is refused",
|
|
1572
|
-
"parts": {
|
|
1573
|
-
"type": "folder",
|
|
1574
|
-
"locator": "acme-tools",
|
|
1575
|
-
"qualifiers": [
|
|
1576
|
-
[
|
|
1577
|
-
"by",
|
|
1578
|
-
"ref:pkg:npm/x@1.0.0#S"
|
|
1579
|
-
]
|
|
1580
|
-
]
|
|
1581
|
-
},
|
|
1582
|
-
"expect": {
|
|
1583
|
-
"error": "by"
|
|
1584
|
-
}
|
|
1585
|
-
},
|
|
1586
|
-
{
|
|
1587
|
-
"name": "a type carrying the field separator is refused",
|
|
1588
|
-
"parts": {
|
|
1589
|
-
"type": "1:folder",
|
|
1590
|
-
"locator": "a"
|
|
1591
|
-
},
|
|
1592
|
-
"expect": {
|
|
1593
|
-
"error": "type"
|
|
1594
|
-
}
|
|
1595
|
-
},
|
|
1596
|
-
{
|
|
1597
|
-
"name": "a dot-agent identifier builds with its digest in state",
|
|
1598
|
-
"parts": {
|
|
1599
|
-
"type": "dot-agent",
|
|
1600
|
-
"locator": "acme.example/doctor:v1.0",
|
|
1601
|
-
"qualifiers": [
|
|
1602
|
-
[
|
|
1603
|
-
"state",
|
|
1604
|
-
"git:a1b2c3d4"
|
|
1605
|
-
]
|
|
1606
|
-
]
|
|
1607
|
-
},
|
|
1608
|
-
"expect": "ref:dot-agent:acme.example/doctor:v1.0;state=git:a1b2c3d4"
|
|
1609
|
-
},
|
|
1610
|
-
{
|
|
1611
|
-
"name": "a content hash is accepted as a state",
|
|
1612
|
-
"parts": {
|
|
1613
|
-
"type": "domain",
|
|
1614
|
-
"locator": "models.example/quant-q4",
|
|
1615
|
-
"qualifiers": [
|
|
1616
|
-
[
|
|
1617
|
-
"state",
|
|
1618
|
-
"sha256:0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
|
|
1619
|
-
]
|
|
1620
|
-
]
|
|
1621
|
-
},
|
|
1622
|
-
"expect": "ref:domain:models.example/quant-q4;state=sha256:0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f"
|
|
1623
|
-
},
|
|
1624
|
-
{
|
|
1625
|
-
"name": "a digest value passes through the builder",
|
|
1626
|
-
"parts": {
|
|
1627
|
-
"type": "folder",
|
|
1628
|
-
"locator": "acme-tools",
|
|
1629
|
-
"qualifiers": [
|
|
1630
|
-
[
|
|
1631
|
-
"over",
|
|
1632
|
-
"sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
1633
|
-
]
|
|
1634
|
-
]
|
|
1635
|
-
},
|
|
1636
|
-
"expect": "ref:folder:acme-tools;over=sha256:41b9caaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
|
|
1637
|
-
},
|
|
1638
|
-
{
|
|
1639
|
-
"name": "an ai-model locator with a hub-style separator builds as is",
|
|
1640
|
-
"parts": {
|
|
1641
|
-
"type": "ai-model",
|
|
1642
|
-
"locator": "mlx-community/Qwen3-1.7B-4bit"
|
|
1643
|
-
},
|
|
1644
|
-
"expect": "ref:ai-model:mlx-community/Qwen3-1.7B-4bit"
|
|
1645
|
-
},
|
|
1646
|
-
{
|
|
1647
|
-
"name": "an ai-model locator with an Ollama tag builds as is",
|
|
1648
|
-
"parts": {
|
|
1649
|
-
"type": "ai-model",
|
|
1650
|
-
"locator": "llama3:8b"
|
|
1651
|
-
},
|
|
1652
|
-
"expect": "ref:ai-model:llama3:8b"
|
|
1653
|
-
},
|
|
1654
|
-
{
|
|
1655
|
-
"name": "over=unknown builds as the declared level for an unestablished population",
|
|
1656
|
-
"parts": {
|
|
1657
|
-
"type": "folder",
|
|
1658
|
-
"locator": "acme-tools",
|
|
1659
|
-
"qualifiers": [
|
|
1660
|
-
[
|
|
1661
|
-
"over",
|
|
1662
|
-
"unknown"
|
|
1663
|
-
]
|
|
1664
|
-
]
|
|
1665
|
-
},
|
|
1666
|
-
"expect": "ref:folder:acme-tools;over=unknown"
|
|
1667
|
-
}
|
|
2088
|
+
"expect": "sha256:32e30e39f2ea3cf01cc2602487229fb097846ba1a9f1037e738f61757eb3e8b6"
|
|
2089
|
+
},
|
|
2090
|
+
{
|
|
2091
|
+
"name": "a single member",
|
|
2092
|
+
"members": [
|
|
2093
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
1668
2094
|
],
|
|
1669
|
-
"
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
"expect": "sha256:75433bb5329808aa4064084a54173f0328926eb38ddce742f61cbd4f0ebba71e"
|
|
1677
|
-
},
|
|
1678
|
-
{
|
|
1679
|
-
"name": "same members, other order, different digest",
|
|
1680
|
-
"members": [
|
|
1681
|
-
"ref:folder:acme-tools#GOVERNANCE.md;state=swh:1:cnt:48db124700000000000000000000000000000000",
|
|
1682
|
-
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
1683
|
-
],
|
|
1684
|
-
"expect": "sha256:83eee8e9bcff34577a3d305bddebef2685a2e6bb20644e5a2ff29c9a8602a25b"
|
|
1685
|
-
},
|
|
1686
|
-
{
|
|
1687
|
-
"name": "a repeated member is not deduplicated",
|
|
1688
|
-
"members": [
|
|
1689
|
-
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000",
|
|
1690
|
-
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
1691
|
-
],
|
|
1692
|
-
"expect": "sha256:32e30e39f2ea3cf01cc2602487229fb097846ba1a9f1037e738f61757eb3e8b6"
|
|
1693
|
-
},
|
|
1694
|
-
{
|
|
1695
|
-
"name": "a single member",
|
|
1696
|
-
"members": [
|
|
1697
|
-
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
1698
|
-
],
|
|
1699
|
-
"expect": "sha256:b89a7d58a6ed779ac53f03eafd0b9cddfac76aad11bfe510688680bfeff45a5f"
|
|
1700
|
-
},
|
|
1701
|
-
{
|
|
1702
|
-
"name": "a member whose content changed changes the digest",
|
|
1703
|
-
"members": [
|
|
1704
|
-
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a01000000000000000000000000000000000",
|
|
1705
|
-
"ref:folder:acme-tools#GOVERNANCE.md;state=swh:1:cnt:48db124700000000000000000000000000000000"
|
|
1706
|
-
],
|
|
1707
|
-
"expect": "sha256:59ecd4cdaa3ffcaf60103a20f555c4b9fa5755a0705c83a3748f60557c2c3518"
|
|
1708
|
-
},
|
|
1709
|
-
{
|
|
1710
|
-
"name": "empty sequence",
|
|
1711
|
-
"members": [],
|
|
1712
|
-
"expect": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
1713
|
-
},
|
|
1714
|
-
{
|
|
1715
|
-
"name": "a member carrying the join character is refused",
|
|
1716
|
-
"members": [
|
|
1717
|
-
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000\nref:folder:acme-tools#GOVERNANCE.md;state=swh:1:cnt:48db124700000000000000000000000000000000"
|
|
1718
|
-
],
|
|
1719
|
-
"expect": {
|
|
1720
|
-
"error": "member"
|
|
1721
|
-
}
|
|
1722
|
-
}
|
|
2095
|
+
"expect": "sha256:b89a7d58a6ed779ac53f03eafd0b9cddfac76aad11bfe510688680bfeff45a5f"
|
|
2096
|
+
},
|
|
2097
|
+
{
|
|
2098
|
+
"name": "a member whose content changed changes the digest",
|
|
2099
|
+
"members": [
|
|
2100
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a01000000000000000000000000000000000",
|
|
2101
|
+
"ref:folder:acme-tools#GOVERNANCE.md;state=swh:1:cnt:48db124700000000000000000000000000000000"
|
|
1723
2102
|
],
|
|
1724
|
-
"
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
2103
|
+
"expect": "sha256:59ecd4cdaa3ffcaf60103a20f555c4b9fa5755a0705c83a3748f60557c2c3518"
|
|
2104
|
+
},
|
|
2105
|
+
{
|
|
2106
|
+
"name": "empty sequence",
|
|
2107
|
+
"members": [],
|
|
2108
|
+
"expect": "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
|
|
2109
|
+
},
|
|
2110
|
+
{
|
|
2111
|
+
"name": "a member carrying the join character is refused",
|
|
2112
|
+
"members": [
|
|
2113
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000\nref:folder:acme-tools#GOVERNANCE.md;state=swh:1:cnt:48db124700000000000000000000000000000000"
|
|
2114
|
+
],
|
|
2115
|
+
"expect": {
|
|
2116
|
+
"error": "member"
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
],
|
|
2120
|
+
"envelope": [
|
|
2121
|
+
{
|
|
2122
|
+
"name": "members recompute to the digest",
|
|
2123
|
+
"requestedId": "ref:folder:acme-tools;over=sha256:75433bb5329808aa4064084a54173f0328926eb38ddce742f61cbd4f0ebba71e",
|
|
2124
|
+
"envelope": {
|
|
2125
|
+
"id": "ref:folder:acme-tools;over=sha256:75433bb5329808aa4064084a54173f0328926eb38ddce742f61cbd4f0ebba71e",
|
|
2126
|
+
"sets": {
|
|
2127
|
+
"over": [
|
|
2128
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000",
|
|
2129
|
+
"ref:folder:acme-tools#GOVERNANCE.md;state=swh:1:cnt:48db124700000000000000000000000000000000"
|
|
2130
|
+
]
|
|
2131
|
+
}
|
|
2132
|
+
},
|
|
2133
|
+
"expect": "admissible"
|
|
2134
|
+
},
|
|
2135
|
+
{
|
|
2136
|
+
"name": "a member changed and the digest did not",
|
|
2137
|
+
"requestedId": "ref:folder:acme-tools;over=sha256:75433bb5329808aa4064084a54173f0328926eb38ddce742f61cbd4f0ebba71e",
|
|
2138
|
+
"envelope": {
|
|
2139
|
+
"id": "ref:folder:acme-tools;over=sha256:75433bb5329808aa4064084a54173f0328926eb38ddce742f61cbd4f0ebba71e",
|
|
2140
|
+
"sets": {
|
|
2141
|
+
"over": [
|
|
2142
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a01000000000000000000000000000000000",
|
|
2143
|
+
"ref:folder:acme-tools#GOVERNANCE.md;state=swh:1:cnt:48db124700000000000000000000000000000000"
|
|
2144
|
+
]
|
|
2145
|
+
}
|
|
2146
|
+
},
|
|
2147
|
+
"expect": "refused"
|
|
2148
|
+
},
|
|
2149
|
+
{
|
|
2150
|
+
"name": "members reordered",
|
|
2151
|
+
"requestedId": "ref:folder:acme-tools;over=sha256:75433bb5329808aa4064084a54173f0328926eb38ddce742f61cbd4f0ebba71e",
|
|
2152
|
+
"envelope": {
|
|
2153
|
+
"id": "ref:folder:acme-tools;over=sha256:75433bb5329808aa4064084a54173f0328926eb38ddce742f61cbd4f0ebba71e",
|
|
2154
|
+
"sets": {
|
|
2155
|
+
"over": [
|
|
2156
|
+
"ref:folder:acme-tools#GOVERNANCE.md;state=swh:1:cnt:48db124700000000000000000000000000000000",
|
|
2157
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
2158
|
+
]
|
|
2159
|
+
}
|
|
2160
|
+
},
|
|
2161
|
+
"expect": "refused"
|
|
2162
|
+
},
|
|
2163
|
+
{
|
|
2164
|
+
"name": "sets missing for a digest-carrying qualifier",
|
|
2165
|
+
"requestedId": "ref:folder:acme-tools;over=sha256:75433bb5329808aa4064084a54173f0328926eb38ddce742f61cbd4f0ebba71e",
|
|
2166
|
+
"envelope": {
|
|
2167
|
+
"id": "ref:folder:acme-tools;over=sha256:75433bb5329808aa4064084a54173f0328926eb38ddce742f61cbd4f0ebba71e"
|
|
2168
|
+
},
|
|
2169
|
+
"expect": "refused"
|
|
2170
|
+
},
|
|
2171
|
+
{
|
|
2172
|
+
"name": "served under an identifier that is not its own",
|
|
2173
|
+
"requestedId": "ref:folder:acme-tools#AGENTS.md",
|
|
2174
|
+
"envelope": {
|
|
2175
|
+
"id": "ref:folder:acme-tools#GOVERNANCE.md"
|
|
2176
|
+
},
|
|
2177
|
+
"expect": "refused"
|
|
2178
|
+
},
|
|
2179
|
+
{
|
|
2180
|
+
"name": "no digest, no sets required",
|
|
2181
|
+
"requestedId": "ref:folder:acme-tools;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
2182
|
+
"envelope": {
|
|
2183
|
+
"id": "ref:folder:acme-tools;state=swh:1:rev:7e29bb6000000000000000000000000000000000",
|
|
2184
|
+
"data": {
|
|
2185
|
+
"anything": true
|
|
2186
|
+
}
|
|
2187
|
+
},
|
|
2188
|
+
"expect": "admissible"
|
|
2189
|
+
},
|
|
2190
|
+
{
|
|
2191
|
+
"name": "two digest qualifiers, both must recompute",
|
|
2192
|
+
"requestedId": "ref:folder:acme-tools;by=sha256:b89a7d58a6ed779ac53f03eafd0b9cddfac76aad11bfe510688680bfeff45a5f;over=sha256:27c2b1674a091639b11e51152103ce945bcd1edbb34ef36e549befcd8c0ce0a3",
|
|
2193
|
+
"envelope": {
|
|
2194
|
+
"id": "ref:folder:acme-tools;by=sha256:b89a7d58a6ed779ac53f03eafd0b9cddfac76aad11bfe510688680bfeff45a5f;over=sha256:27c2b1674a091639b11e51152103ce945bcd1edbb34ef36e549befcd8c0ce0a3",
|
|
2195
|
+
"sets": {
|
|
2196
|
+
"by": [
|
|
2197
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
2198
|
+
],
|
|
2199
|
+
"over": [
|
|
2200
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
2201
|
+
]
|
|
2202
|
+
}
|
|
2203
|
+
},
|
|
2204
|
+
"expect": "refused"
|
|
2205
|
+
},
|
|
2206
|
+
{
|
|
2207
|
+
"name": "a requested identifier that does not parse is refused",
|
|
2208
|
+
"requestedId": "not-a-ref",
|
|
2209
|
+
"envelope": {
|
|
2210
|
+
"id": "not-a-ref"
|
|
2211
|
+
},
|
|
2212
|
+
"expect": "refused"
|
|
2213
|
+
},
|
|
2214
|
+
{
|
|
2215
|
+
"name": "a requested identifier that is malformed is refused",
|
|
2216
|
+
"requestedId": "ref:folder:acme-tools;state=swh:1:rev:7e29bb6",
|
|
2217
|
+
"envelope": {
|
|
2218
|
+
"id": "ref:folder:acme-tools;state=swh:1:rev:7e29bb6"
|
|
2219
|
+
},
|
|
2220
|
+
"expect": "refused"
|
|
2221
|
+
},
|
|
2222
|
+
{
|
|
2223
|
+
"name": "an uncovered requested identifier is admissible",
|
|
2224
|
+
"requestedId": "ref:doi:10.1000/182",
|
|
2225
|
+
"envelope": {
|
|
2226
|
+
"id": "ref:doi:10.1000/182"
|
|
2227
|
+
},
|
|
2228
|
+
"expect": "admissible"
|
|
2229
|
+
},
|
|
2230
|
+
{
|
|
2231
|
+
"name": "alsoKnownAs is opaque to the invariant",
|
|
2232
|
+
"requestedId": "ref:folder:acme-tools;over=sha256:b89a7d58a6ed779ac53f03eafd0b9cddfac76aad11bfe510688680bfeff45a5f",
|
|
2233
|
+
"envelope": {
|
|
2234
|
+
"id": "ref:folder:acme-tools;over=sha256:b89a7d58a6ed779ac53f03eafd0b9cddfac76aad11bfe510688680bfeff45a5f",
|
|
2235
|
+
"sets": {
|
|
2236
|
+
"over": [
|
|
2237
|
+
"ref:folder:acme-tools#AGENTS.md;state=swh:1:cnt:3404a00f00000000000000000000000000000000"
|
|
2238
|
+
]
|
|
2239
|
+
},
|
|
2240
|
+
"alsoKnownAs": [
|
|
2241
|
+
"ref:pkg:npm/acme-tools@0.6.0"
|
|
2242
|
+
]
|
|
2243
|
+
},
|
|
2244
|
+
"expect": "admissible"
|
|
2245
|
+
}
|
|
2246
|
+
],
|
|
2247
|
+
"comparison": [
|
|
2248
|
+
{
|
|
2249
|
+
"name": "identical identifiers are the same package and cover each other",
|
|
2250
|
+
"a": "ref:pkg:npm/x@1.0.0",
|
|
2251
|
+
"b": "ref:pkg:npm/x@1.0.0",
|
|
2252
|
+
"expect": {
|
|
2253
|
+
"samePackage": true,
|
|
2254
|
+
"covers": true,
|
|
2255
|
+
"coversReversed": true
|
|
2256
|
+
}
|
|
2257
|
+
},
|
|
2258
|
+
{
|
|
2259
|
+
"name": "no version covers a version; the reverse does not hold",
|
|
2260
|
+
"a": "ref:pkg:npm/x",
|
|
2261
|
+
"b": "ref:pkg:npm/x@1.0.0",
|
|
2262
|
+
"expect": {
|
|
2263
|
+
"samePackage": true,
|
|
2264
|
+
"covers": true,
|
|
2265
|
+
"coversReversed": false
|
|
2266
|
+
}
|
|
2267
|
+
},
|
|
2268
|
+
{
|
|
2269
|
+
"name": "two versions are one package and neither covers the other",
|
|
2270
|
+
"a": "ref:pkg:npm/x@1.0.0",
|
|
2271
|
+
"b": "ref:pkg:npm/x@2.0.0",
|
|
2272
|
+
"expect": {
|
|
2273
|
+
"samePackage": true,
|
|
2274
|
+
"covers": false,
|
|
2275
|
+
"coversReversed": false
|
|
2276
|
+
}
|
|
2277
|
+
},
|
|
2278
|
+
{
|
|
2279
|
+
"name": "a namespace '@' is not a version — it opens a segment",
|
|
2280
|
+
"a": "ref:pkg:npm/%40acme/x",
|
|
2281
|
+
"b": "ref:pkg:npm/%40acme/x@1.0.0",
|
|
2282
|
+
"expect": {
|
|
2283
|
+
"samePackage": true,
|
|
2284
|
+
"covers": true,
|
|
2285
|
+
"coversReversed": false
|
|
2286
|
+
}
|
|
2287
|
+
},
|
|
2288
|
+
{
|
|
2289
|
+
"name": "a mailbox '@' is not a version: two mailboxes are two things",
|
|
2290
|
+
"a": "ref:email:someone@mail.example",
|
|
2291
|
+
"b": "ref:email:someone@other.example",
|
|
2292
|
+
"expect": {
|
|
2293
|
+
"samePackage": false,
|
|
2294
|
+
"covers": false,
|
|
2295
|
+
"coversReversed": false
|
|
2296
|
+
}
|
|
2297
|
+
},
|
|
2298
|
+
{
|
|
2299
|
+
"name": "a served model's '@' keys a quantisation, never a version",
|
|
2300
|
+
"a": "ref:ai-model:mymodel@q4_k_m",
|
|
2301
|
+
"b": "ref:ai-model:mymodel@q8_0",
|
|
2302
|
+
"expect": {
|
|
2303
|
+
"samePackage": false,
|
|
2304
|
+
"covers": false,
|
|
2305
|
+
"coversReversed": false
|
|
2306
|
+
}
|
|
2307
|
+
},
|
|
2308
|
+
{
|
|
2309
|
+
"name": "no declared name covers one",
|
|
2310
|
+
"a": "ref:pkg:npm/x",
|
|
2311
|
+
"b": "ref:pkg:npm/x@1.0.0#Observation",
|
|
2312
|
+
"expect": {
|
|
2313
|
+
"samePackage": false,
|
|
2314
|
+
"covers": true,
|
|
2315
|
+
"coversReversed": false
|
|
2316
|
+
}
|
|
2317
|
+
},
|
|
2318
|
+
{
|
|
2319
|
+
"name": "two declared names are neither",
|
|
2320
|
+
"a": "ref:pkg:npm/x#A",
|
|
2321
|
+
"b": "ref:pkg:npm/x#B",
|
|
2322
|
+
"expect": {
|
|
2323
|
+
"samePackage": false,
|
|
2324
|
+
"covers": false,
|
|
2325
|
+
"coversReversed": false
|
|
2326
|
+
}
|
|
2327
|
+
},
|
|
2328
|
+
{
|
|
2329
|
+
"name": "no refinement covers one",
|
|
2330
|
+
"a": "ref:folder:acme-tools#AGENTS.md",
|
|
2331
|
+
"b": "ref:folder:acme-tools#AGENTS.md;lines=1",
|
|
2332
|
+
"expect": {
|
|
2333
|
+
"samePackage": false,
|
|
2334
|
+
"covers": true,
|
|
2335
|
+
"coversReversed": false
|
|
2336
|
+
}
|
|
2337
|
+
},
|
|
2338
|
+
{
|
|
2339
|
+
"name": "two refinement values are neither — a range is not a family",
|
|
2340
|
+
"a": "ref:folder:acme-tools#AGENTS.md;lines=1",
|
|
2341
|
+
"b": "ref:folder:acme-tools#AGENTS.md;lines=9",
|
|
2342
|
+
"expect": {
|
|
2343
|
+
"samePackage": false,
|
|
2344
|
+
"covers": false,
|
|
2345
|
+
"coversReversed": false
|
|
2346
|
+
}
|
|
2347
|
+
},
|
|
2348
|
+
{
|
|
2349
|
+
"name": "no qualifier covers one",
|
|
2350
|
+
"a": "ref:pkg:npm/x",
|
|
2351
|
+
"b": "ref:pkg:npm/x;state=none",
|
|
2352
|
+
"expect": {
|
|
2353
|
+
"samePackage": false,
|
|
2354
|
+
"covers": true,
|
|
2355
|
+
"coversReversed": false
|
|
2356
|
+
}
|
|
2357
|
+
},
|
|
2358
|
+
{
|
|
2359
|
+
"name": "two qualifier values are neither",
|
|
2360
|
+
"a": "ref:pkg:npm/x;state=none",
|
|
2361
|
+
"b": "ref:pkg:npm/x;state=git:a1b2c3d",
|
|
2362
|
+
"expect": {
|
|
2363
|
+
"samePackage": false,
|
|
2364
|
+
"covers": false,
|
|
2365
|
+
"coversReversed": false
|
|
2366
|
+
}
|
|
2367
|
+
},
|
|
2368
|
+
{
|
|
2369
|
+
"name": "qualifier order does not distinguish either relation",
|
|
2370
|
+
"a": "ref:pkg:npm/x;state=none;when=2026-01-01T00:00:00Z",
|
|
2371
|
+
"b": "ref:pkg:npm/x;when=2026-01-01T00:00:00Z;state=none",
|
|
2372
|
+
"expect": {
|
|
2373
|
+
"samePackage": true,
|
|
2374
|
+
"covers": true,
|
|
2375
|
+
"coversReversed": true
|
|
2376
|
+
}
|
|
2377
|
+
},
|
|
2378
|
+
{
|
|
2379
|
+
"name": "two types are never compared",
|
|
2380
|
+
"a": "ref:url:acme.example/x",
|
|
2381
|
+
"b": "ref:pkg:npm/x",
|
|
2382
|
+
"expect": {
|
|
2383
|
+
"samePackage": false,
|
|
2384
|
+
"covers": false,
|
|
2385
|
+
"coversReversed": false
|
|
2386
|
+
}
|
|
2387
|
+
},
|
|
2388
|
+
{
|
|
2389
|
+
"name": "an uncovered type compares like any other",
|
|
2390
|
+
"a": "ref:eita:trait",
|
|
2391
|
+
"b": "ref:eita:trait@1",
|
|
2392
|
+
"expect": {
|
|
2393
|
+
"samePackage": false,
|
|
2394
|
+
"covers": false,
|
|
2395
|
+
"coversReversed": false
|
|
2396
|
+
}
|
|
2397
|
+
},
|
|
2398
|
+
{
|
|
2399
|
+
"name": "a malformed identifier names nothing, itself included",
|
|
2400
|
+
"a": "ref:url:NOPE",
|
|
2401
|
+
"b": "ref:url:NOPE",
|
|
2402
|
+
"expect": {
|
|
2403
|
+
"samePackage": false,
|
|
2404
|
+
"covers": false,
|
|
2405
|
+
"coversReversed": false
|
|
2406
|
+
}
|
|
2407
|
+
},
|
|
2408
|
+
{
|
|
2409
|
+
"name": "an unsupported scheme version has parts read by the wrong grammar",
|
|
2410
|
+
"a": "ref:pkg:npm/x",
|
|
2411
|
+
"b": "ref:2:pkg:npm/x@1.0.0",
|
|
2412
|
+
"expect": {
|
|
2413
|
+
"samePackage": false,
|
|
2414
|
+
"covers": false,
|
|
2415
|
+
"coversReversed": false
|
|
2416
|
+
}
|
|
2417
|
+
},
|
|
2418
|
+
{
|
|
2419
|
+
"name": "a corpus covers a file under it",
|
|
2420
|
+
"a": "ref:folder:acme-tools",
|
|
2421
|
+
"b": "ref:folder:acme-tools/docs/guide.md",
|
|
2422
|
+
"expect": {
|
|
2423
|
+
"samePackage": false,
|
|
2424
|
+
"covers": true,
|
|
2425
|
+
"coversReversed": false
|
|
2426
|
+
}
|
|
2427
|
+
},
|
|
2428
|
+
{
|
|
2429
|
+
"name": "a prefix that is not a whole segment covers nothing",
|
|
2430
|
+
"a": "ref:folder:acme-tools",
|
|
2431
|
+
"b": "ref:folder:acme-tools-extra",
|
|
2432
|
+
"expect": {
|
|
2433
|
+
"samePackage": false,
|
|
2434
|
+
"covers": false,
|
|
2435
|
+
"coversReversed": false
|
|
2436
|
+
}
|
|
2437
|
+
},
|
|
2438
|
+
{
|
|
2439
|
+
"name": "a directory covers what is under it and not its sibling",
|
|
2440
|
+
"a": "ref:folder:acme-tools/docs",
|
|
2441
|
+
"b": "ref:folder:acme-tools/docs/guide.md",
|
|
2442
|
+
"expect": {
|
|
2443
|
+
"samePackage": false,
|
|
2444
|
+
"covers": true,
|
|
2445
|
+
"coversReversed": false
|
|
2446
|
+
}
|
|
2447
|
+
},
|
|
2448
|
+
{
|
|
2449
|
+
"name": "one file at two versions is one package",
|
|
2450
|
+
"a": "ref:pkg:npm/x@1.0.0/docs/guide.md",
|
|
2451
|
+
"b": "ref:pkg:npm/x@2.0.0/docs/guide.md",
|
|
2452
|
+
"expect": {
|
|
2453
|
+
"samePackage": true,
|
|
2454
|
+
"covers": false,
|
|
2455
|
+
"coversReversed": false
|
|
2456
|
+
}
|
|
2457
|
+
},
|
|
2458
|
+
{
|
|
2459
|
+
"name": "a package covers a file inside one of its releases",
|
|
2460
|
+
"a": "ref:pkg:npm/x",
|
|
2461
|
+
"b": "ref:pkg:npm/x@1.0.0/docs/guide.md",
|
|
2462
|
+
"expect": {
|
|
2463
|
+
"samePackage": false,
|
|
2464
|
+
"covers": true,
|
|
2465
|
+
"coversReversed": false
|
|
2466
|
+
}
|
|
2467
|
+
},
|
|
2468
|
+
{
|
|
2469
|
+
"name": "two files in one release are neither",
|
|
2470
|
+
"a": "ref:pkg:npm/x@1.0.0/docs/guide.md",
|
|
2471
|
+
"b": "ref:pkg:npm/x@1.0.0/docs/api.md",
|
|
2472
|
+
"expect": {
|
|
2473
|
+
"samePackage": false,
|
|
2474
|
+
"covers": false,
|
|
2475
|
+
"coversReversed": false
|
|
2476
|
+
}
|
|
2477
|
+
},
|
|
2478
|
+
{
|
|
2479
|
+
"name": "a mailbox covers an item served under it",
|
|
2480
|
+
"a": "ref:email:alguem@dominio.com",
|
|
2481
|
+
"b": "ref:email:alguem@dominio.com/CADx9v7abc123@mail.gmail.com",
|
|
2482
|
+
"expect": {
|
|
2483
|
+
"samePackage": false,
|
|
2484
|
+
"covers": true,
|
|
2485
|
+
"coversReversed": false
|
|
2486
|
+
}
|
|
2487
|
+
},
|
|
2488
|
+
{
|
|
2489
|
+
"name": "two mailboxes sharing a prefix cover nothing",
|
|
2490
|
+
"a": "ref:email:alguem@dominio.com",
|
|
2491
|
+
"b": "ref:email:alguemx@dominio.com",
|
|
2492
|
+
"expect": {
|
|
2493
|
+
"samePackage": false,
|
|
2494
|
+
"covers": false,
|
|
2495
|
+
"coversReversed": false
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
]
|
|
2499
|
+
}
|
|
1852
2500
|
}
|