@authorizedretailers/spec 0.1.0 → 0.2.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.
Files changed (209) hide show
  1. package/README.md +66 -47
  2. package/dist/constants.d.ts +25 -6
  3. package/dist/constants.js +41 -7
  4. package/dist/identity.d.ts +29 -14
  5. package/dist/identity.js +79 -39
  6. package/dist/index.d.ts +2 -0
  7. package/dist/index.js +2 -0
  8. package/dist/jws.d.ts +36 -5
  9. package/dist/jws.js +48 -14
  10. package/dist/match.d.ts +21 -0
  11. package/dist/match.js +89 -0
  12. package/dist/product.d.ts +34 -0
  13. package/dist/product.js +75 -0
  14. package/dist/published.d.ts +14 -8
  15. package/dist/published.js +32 -10
  16. package/dist/schemas.d.ts +366 -88
  17. package/dist/schemas.js +802 -178
  18. package/dist/types.d.ts +121 -47
  19. package/dist/types.js +2 -2
  20. package/dist/validate.d.ts +24 -10
  21. package/dist/validate.js +302 -82
  22. package/fixtures/list/invalid/list-all-mixed.json +53 -0
  23. package/fixtures/list/invalid/list-amazon-missing-seller-id.json +51 -0
  24. package/fixtures/list/invalid/list-amazon-on-walmart-domain.json +52 -0
  25. package/fixtures/{file/invalid/full-attached-jws.json → list/invalid/list-attached-jws.json} +14 -12
  26. package/fixtures/list/invalid/list-bad-asin.json +102 -0
  27. package/fixtures/list/invalid/list-bad-gtin.json +102 -0
  28. package/fixtures/list/invalid/list-brand-exclusion-no-catalog.json +57 -0
  29. package/fixtures/list/invalid/list-duplicate-asin.json +102 -0
  30. package/fixtures/{file/invalid/full-duplicate-authorization-id.json → list/invalid/list-duplicate-authorization-id.json} +23 -18
  31. package/fixtures/list/invalid/list-duplicate-gtin.json +102 -0
  32. package/fixtures/list/invalid/list-duplicate-product-id.json +102 -0
  33. package/fixtures/{file/invalid/full-empty-territories.json → list/invalid/list-empty-territories.json} +17 -10
  34. package/fixtures/list/invalid/list-exclude-unknown-product.json +105 -0
  35. package/fixtures/list/invalid/list-expires-field.json +53 -0
  36. package/fixtures/list/invalid/list-extra-property.json +53 -0
  37. package/fixtures/list/invalid/list-generic-web-no-territories.json +39 -0
  38. package/fixtures/list/invalid/list-gtin-11-digits.json +102 -0
  39. package/fixtures/list/invalid/list-impossible-date.json +53 -0
  40. package/fixtures/list/invalid/list-lowercase-territory.json +52 -0
  41. package/fixtures/{file/invalid/full-signature-missing-kid.json → list/invalid/list-marketplace-field.json} +14 -11
  42. package/fixtures/list/invalid/list-marketplace-territory-mismatch.json +52 -0
  43. package/fixtures/list/invalid/list-missing-revocation-id.json +51 -0
  44. package/fixtures/list/invalid/list-missing-scope.json +44 -0
  45. package/fixtures/list/invalid/list-missing-stale-until.json +51 -0
  46. package/fixtures/list/invalid/list-name-only-retailer.json +36 -0
  47. package/fixtures/list/invalid/list-no-channels.json +37 -0
  48. package/fixtures/list/invalid/list-non-utc-timestamp.json +52 -0
  49. package/fixtures/list/invalid/list-not-public-with-authorizations.json +18 -0
  50. package/fixtures/list/invalid/list-not-public-with-catalog.json +18 -0
  51. package/fixtures/list/invalid/list-physical.json +43 -0
  52. package/fixtures/list/invalid/list-product-no-identifier.json +98 -0
  53. package/fixtures/list/invalid/list-scope-no-products.json +49 -0
  54. package/fixtures/{file/valid/full-signed.json → list/invalid/list-single-domain.json} +12 -12
  55. package/fixtures/list/invalid/list-stale-over-24-hours.json +52 -0
  56. package/fixtures/list/invalid/list-territory-uk.json +52 -0
  57. package/fixtures/{file/invalid/full-unknown-channel-type.json → list/invalid/list-unknown-channel-type.json} +18 -12
  58. package/fixtures/list/invalid/list-unknown-line.json +102 -0
  59. package/fixtures/list/invalid/list-unknown-product.json +105 -0
  60. package/fixtures/{file/invalid/full-missing-authorization-expires.json → list/invalid/list-unsigned.json} +12 -9
  61. package/fixtures/list/invalid/list-valid-over-15-minutes.json +52 -0
  62. package/fixtures/{file/invalid/full-web-domain-is-url.json → list/invalid/list-web-domain-is-url.json} +18 -12
  63. package/fixtures/list/invalid/list-web-on-marketplace-domain.json +52 -0
  64. package/fixtures/{file/invalid/full-wildcard-mixed.json → list/invalid/list-wildcard-mixed.json} +17 -10
  65. package/fixtures/list/valid/list-catalog-line-scope.json +102 -0
  66. package/fixtures/list/valid/list-cctld-web.json +39 -0
  67. package/fixtures/list/valid/list-fractional-seconds.json +52 -0
  68. package/fixtures/{file/invalid/full-amazon-missing-seller-id.json → list/valid/list-generic-web-territories.json} +15 -17
  69. package/fixtures/list/valid/list-marketplace-no-territories.json +40 -0
  70. package/fixtures/list/valid/list-no-authorizations.json +18 -0
  71. package/fixtures/list/valid/list-no-catalog.json +52 -0
  72. package/fixtures/list/valid/list-no-expires.json +52 -0
  73. package/fixtures/list/valid/list-not-public.json +17 -0
  74. package/fixtures/list/valid/list-product-scope.json +103 -0
  75. package/fixtures/list/valid/list-proposed-by.json +55 -0
  76. package/fixtures/list/valid/list-with-expires.json +53 -0
  77. package/fixtures/list/valid/list-worldwide.json +52 -0
  78. package/fixtures/manifest.json +609 -154
  79. package/fixtures/match/all-scope-excluded-line.json +194 -0
  80. package/fixtures/match/all-scope-not-in-catalog.json +194 -0
  81. package/fixtures/match/as-of-before-end-date.json +194 -0
  82. package/fixtures/match/brand-exclusion-beats-named-product.json +194 -0
  83. package/fixtures/match/duplicate-asin-authorized-seller.json +192 -0
  84. package/fixtures/match/duplicate-asin-unauthorized-seller.json +191 -0
  85. package/fixtures/match/expired-end-date.json +193 -0
  86. package/fixtures/match/marketplace-territory-default.json +186 -0
  87. package/fixtures/match/marketplace-territory-mismatch.json +187 -0
  88. package/fixtures/match/match-by-channel-key.json +186 -0
  89. package/fixtures/match/product-excluded-by-authorization.json +194 -0
  90. package/fixtures/match/product-line-request.json +186 -0
  91. package/fixtures/match/product-not-in-scope.json +194 -0
  92. package/fixtures/match/seller-authorized-by-gtin.json +194 -0
  93. package/fixtures/match/seller-authorized-for-line.json +194 -0
  94. package/fixtures/match/worldwide-web.json +186 -0
  95. package/fixtures/pointer/invalid/full-form.json +11 -0
  96. package/fixtures/pointer/invalid/pointer-domain-mismatch.json +10 -0
  97. package/fixtures/{file → pointer}/invalid/pointer-http-url.json +2 -1
  98. package/fixtures/pointer/invalid/pointer-missing-verify-token.json +9 -0
  99. package/fixtures/pointer/invalid/pointer-other-host.json +10 -0
  100. package/fixtures/{file/valid/pointer.json → pointer/invalid/pointer-wrong-spec.json} +1 -0
  101. package/fixtures/pointer/invalid/private-form.json +10 -0
  102. package/fixtures/pointer/invalid/unknown-form.json +10 -0
  103. package/fixtures/pointer/valid/pointer-fetched-via-www.json +10 -0
  104. package/fixtures/pointer/valid/pointer.json +10 -0
  105. package/fixtures/revocation-feed/invalid/feed-hashed-entry.json +17 -0
  106. package/fixtures/revocation-feed/invalid/feed-valid-over-15-minutes.json +17 -0
  107. package/fixtures/revocation-feed/valid/feed-empty.json +12 -0
  108. package/fixtures/revocation-feed/valid/feed.json +17 -0
  109. package/fixtures/verify-request/invalid/bad-as-of.json +9 -0
  110. package/fixtures/verify-request/invalid/bad-gtin.json +11 -0
  111. package/fixtures/verify-request/invalid/domain-with-scheme.json +2 -4
  112. package/fixtures/verify-request/{valid/web-no-product-line.json → invalid/generic-web-no-territory.json} +1 -2
  113. package/fixtures/verify-request/invalid/gtin-and-asin.json +12 -0
  114. package/fixtures/verify-request/{valid/amazon.json → invalid/marketplace-field.json} +1 -3
  115. package/fixtures/verify-request/invalid/missing-channel.json +1 -3
  116. package/fixtures/verify-request/invalid/physical-channel.json +1 -3
  117. package/fixtures/verify-request/invalid/retailer-name-only.json +0 -2
  118. package/fixtures/verify-request/invalid/territory-uk.json +9 -0
  119. package/fixtures/verify-request/invalid/wildcard-territory.json +2 -3
  120. package/fixtures/verify-request/valid/as-of-datetime.json +9 -0
  121. package/fixtures/verify-request/valid/full.json +13 -0
  122. package/fixtures/verify-request/valid/gtin.json +11 -0
  123. package/fixtures/verify-request/valid/minimal-marketplace.json +8 -0
  124. package/fixtures/verify-request/valid/web-cctld-no-territory.json +7 -0
  125. package/fixtures/verify-request/valid/web-generic-with-territory.json +9 -0
  126. package/fixtures/verify-response/invalid/authorized-missing-revocation-id.json +18 -0
  127. package/fixtures/verify-response/invalid/authorized-with-reason.json +20 -0
  128. package/fixtures/verify-response/invalid/brand-unverified.json +13 -0
  129. package/fixtures/verify-response/invalid/expired-without-expires.json +18 -0
  130. package/fixtures/verify-response/invalid/missing-observed.json +11 -5
  131. package/fixtures/verify-response/invalid/missing-signature.json +9 -3
  132. package/fixtures/verify-response/invalid/missing-stale-until.json +18 -0
  133. package/fixtures/verify-response/invalid/not-in-catalog-with-id.json +17 -0
  134. package/fixtures/verify-response/invalid/not-registered-with-unlisted-reason.json +13 -0
  135. package/fixtures/verify-response/invalid/stale-until-over-24-hours.json +19 -0
  136. package/fixtures/verify-response/invalid/unlisted-observed.json +5 -4
  137. package/fixtures/verify-response/invalid/unlisted-with-authorization-id.json +5 -4
  138. package/fixtures/verify-response/invalid/unlisted-with-not-registered-reason.json +13 -0
  139. package/fixtures/verify-response/invalid/unlisted-with-revocation-id.json +13 -0
  140. package/fixtures/verify-response/invalid/valid-until-before-checked.json +11 -5
  141. package/fixtures/verify-response/invalid/valid-until-over-15-minutes.json +19 -0
  142. package/fixtures/verify-response/invalid/with-stale-flag.json +20 -0
  143. package/fixtures/verify-response/invalid/with-tier.json +11 -5
  144. package/fixtures/verify-response/valid/authorized-no-product.json +14 -0
  145. package/fixtures/verify-response/valid/authorized-not-in-catalog.json +22 -0
  146. package/fixtures/verify-response/valid/authorized-observed.json +11 -5
  147. package/fixtures/verify-response/valid/authorized-private-product.json +17 -0
  148. package/fixtures/verify-response/valid/authorized-with-end-date.json +20 -0
  149. package/fixtures/verify-response/valid/authorized.json +11 -5
  150. package/fixtures/verify-response/valid/disputed.json +10 -5
  151. package/fixtures/verify-response/valid/expired.json +12 -6
  152. package/fixtures/verify-response/valid/not-registered-no-reason.json +12 -0
  153. package/fixtures/verify-response/valid/not-registered-reason.json +13 -0
  154. package/fixtures/verify-response/valid/unlisted-product-excluded.json +18 -0
  155. package/fixtures/verify-response/valid/unlisted-product-not-in-catalog.json +16 -0
  156. package/fixtures/verify-response/valid/unlisted-territory-mismatch.json +13 -0
  157. package/fixtures/verify-response/valid/unlisted.json +5 -4
  158. package/fixtures/verify-response/valid/with-as-of.json +20 -0
  159. package/fixtures/verify-response/valid/with-signal.json +11 -5
  160. package/package.json +5 -4
  161. package/schemas/{common.json → 0.1/common.json} +3 -2
  162. package/schemas/0.2/common.json +761 -0
  163. package/schemas/0.2/list.json +87 -0
  164. package/schemas/0.2/pointer.json +33 -0
  165. package/schemas/0.2/revocation-feed.json +55 -0
  166. package/schemas/0.2/verify-request.json +65 -0
  167. package/schemas/0.2/verify-response.json +284 -0
  168. package/spec/spec-v0.1.md +11 -3
  169. package/spec/spec-v0.2.md +531 -0
  170. package/fixtures/file/invalid/full-all-mixed.json +0 -47
  171. package/fixtures/file/invalid/full-authorization-expires-after-file.json +0 -46
  172. package/fixtures/file/invalid/full-expires-before-issued.json +0 -46
  173. package/fixtures/file/invalid/full-expiry-over-180-days.json +0 -46
  174. package/fixtures/file/invalid/full-extra-property.json +0 -47
  175. package/fixtures/file/invalid/full-impossible-date.json +0 -46
  176. package/fixtures/file/invalid/full-lowercase-territory.json +0 -45
  177. package/fixtures/file/invalid/full-missing-file-expires.json +0 -45
  178. package/fixtures/file/invalid/full-missing-product-lines.json +0 -43
  179. package/fixtures/file/invalid/full-missing-scope.json +0 -37
  180. package/fixtures/file/invalid/full-missing-territories.json +0 -42
  181. package/fixtures/file/invalid/full-name-only-retailer.json +0 -30
  182. package/fixtures/file/invalid/full-no-channels.json +0 -31
  183. package/fixtures/file/invalid/full-non-utc-timestamp.json +0 -46
  184. package/fixtures/file/invalid/full-physical-missing-country.json +0 -50
  185. package/fixtures/file/invalid/full-web-missing-domain.json +0 -45
  186. package/fixtures/file/invalid/full-wrong-spec.json +0 -46
  187. package/fixtures/file/invalid/private-missing-verify.json +0 -8
  188. package/fixtures/file/invalid/private-with-authorizations.json +0 -45
  189. package/fixtures/file/invalid/unknown-form.json +0 -9
  190. package/fixtures/file/valid/full-fractional-seconds.json +0 -46
  191. package/fixtures/file/valid/full-max-expiry.json +0 -46
  192. package/fixtures/file/valid/full-no-authorizations.json +0 -11
  193. package/fixtures/file/valid/full-unsigned-handwritten.json +0 -46
  194. package/fixtures/file/valid/full-worldwide-physical-proposed.json +0 -82
  195. package/fixtures/file/valid/private.json +0 -9
  196. package/fixtures/verify-response/invalid/authorized-missing-authorization-id.json +0 -12
  197. package/fixtures/verify-response/invalid/missing-valid-until.json +0 -12
  198. package/fixtures/verify-response/invalid/observed-without-last-seen.json +0 -13
  199. package/fixtures/verify-response/invalid/unknown-status.json +0 -13
  200. package/fixtures/verify-response/invalid/unlisted-with-reason.json +0 -12
  201. package/fixtures/verify-response/invalid/valid-until-over-24h.json +0 -13
  202. package/fixtures/verify-response/valid/brand-unverified-no-reason.json +0 -11
  203. package/fixtures/verify-response/valid/brand-unverified-reason.json +0 -12
  204. /package/schemas/{file-full.json → 0.1/file-full.json} +0 -0
  205. /package/schemas/{file-pointer.json → 0.1/file-pointer.json} +0 -0
  206. /package/schemas/{file-private.json → 0.1/file-private.json} +0 -0
  207. /package/schemas/{file.json → 0.1/file.json} +0 -0
  208. /package/schemas/{verify-request.json → 0.1/verify-request.json} +0 -0
  209. /package/schemas/{verify-response.json → 0.1/verify-response.json} +0 -0
@@ -1,280 +1,531 @@
1
1
  [
2
2
  {
3
- "path": "file/valid/full-signed.json",
4
- "kind": "file",
3
+ "path": "pointer/valid/pointer.json",
4
+ "kind": "pointer",
5
5
  "valid": true,
6
- "note": "Section 5 example"
6
+ "fetched_from": "brand.example",
7
+ "note": "Section 5.1 example"
7
8
  },
8
9
  {
9
- "path": "file/valid/full-unsigned-handwritten.json",
10
- "kind": "file",
10
+ "path": "pointer/valid/pointer-fetched-via-www.json",
11
+ "kind": "pointer",
11
12
  "valid": true,
12
- "note": "Section 5: hand-written unsigned files are accepted"
13
+ "fetched_from": "www.brand.example",
14
+ "note": "Section 5.1: www is ignored when matching the domain"
13
15
  },
14
16
  {
15
- "path": "file/valid/full-no-authorizations.json",
16
- "kind": "file",
17
+ "path": "pointer/invalid/pointer-other-host.json",
18
+ "kind": "pointer",
19
+ "valid": false,
20
+ "expect": "list_not_on_registry",
21
+ "note": "Section 5.1: list MUST be on authorizedretailers.ai"
22
+ },
23
+ {
24
+ "path": "pointer/invalid/pointer-http-url.json",
25
+ "kind": "pointer",
26
+ "valid": false,
27
+ "expect": "schema",
28
+ "note": "Pointer list must be HTTPS"
29
+ },
30
+ {
31
+ "path": "pointer/invalid/pointer-missing-verify-token.json",
32
+ "kind": "pointer",
33
+ "valid": false,
34
+ "expect": "schema",
35
+ "note": "Section 5.1: verify_token is required"
36
+ },
37
+ {
38
+ "path": "pointer/invalid/pointer-domain-mismatch.json",
39
+ "kind": "pointer",
40
+ "valid": false,
41
+ "expect": "brand_domain_mismatch",
42
+ "fetched_from": "other.example",
43
+ "note": "Section 5.1: a pointer vouches only for its own domain"
44
+ },
45
+ {
46
+ "path": "pointer/invalid/full-form.json",
47
+ "kind": "pointer",
48
+ "valid": false,
49
+ "expect": "form_not_supported",
50
+ "note": "v0.1 full form was removed"
51
+ },
52
+ {
53
+ "path": "pointer/invalid/private-form.json",
54
+ "kind": "pointer",
55
+ "valid": false,
56
+ "expect": "form_not_supported",
57
+ "note": "v0.1 private form was removed"
58
+ },
59
+ {
60
+ "path": "pointer/invalid/unknown-form.json",
61
+ "kind": "pointer",
62
+ "valid": false,
63
+ "expect": "form_not_supported",
64
+ "note": "Only pointer"
65
+ },
66
+ {
67
+ "path": "pointer/invalid/pointer-wrong-spec.json",
68
+ "kind": "pointer",
69
+ "valid": false,
70
+ "expect": "schema",
71
+ "note": "Spec version is 0.2"
72
+ },
73
+ {
74
+ "path": "list/valid/list-no-catalog.json",
75
+ "kind": "list",
17
76
  "valid": true,
18
- "note": "A brand with nothing authorized"
77
+ "note": "Section 5.2, no catalog"
19
78
  },
20
79
  {
21
- "path": "file/valid/full-worldwide-physical-proposed.json",
22
- "kind": "file",
80
+ "path": "list/valid/list-catalog-line-scope.json",
81
+ "kind": "list",
23
82
  "valid": true,
24
- "note": "Worldwide scope, named product lines, eBay + physical, distributor-proposed"
83
+ "note": "Section 3.1: catalog with a line-scoped authorization and a brand exclusion"
25
84
  },
26
85
  {
27
- "path": "file/valid/full-max-expiry.json",
28
- "kind": "file",
86
+ "path": "list/valid/list-product-scope.json",
87
+ "kind": "list",
29
88
  "valid": true,
30
- "note": "Exactly 180 days after issued (section 10)"
89
+ "note": "Section 3.1: authorization scoped to named products"
31
90
  },
32
91
  {
33
- "path": "file/valid/full-fractional-seconds.json",
34
- "kind": "file",
92
+ "path": "list/valid/list-no-expires.json",
93
+ "kind": "list",
35
94
  "valid": true,
36
- "note": "Fractional seconds are allowed"
95
+ "note": "Section 10: no end date, lasts until revoked"
37
96
  },
38
97
  {
39
- "path": "file/valid/pointer.json",
40
- "kind": "file",
98
+ "path": "list/valid/list-with-expires.json",
99
+ "kind": "list",
41
100
  "valid": true,
42
- "note": "Section 5 pointer form"
101
+ "note": "Section 10: brand-set end date"
43
102
  },
44
103
  {
45
- "path": "file/valid/private.json",
46
- "kind": "file",
104
+ "path": "list/valid/list-generic-web-territories.json",
105
+ "kind": "list",
47
106
  "valid": true,
48
- "note": "Section 5 private form"
107
+ "note": "Section 6.2: generic-domain web store lists territories"
49
108
  },
50
109
  {
51
- "path": "file/invalid/full-no-channels.json",
52
- "kind": "file",
110
+ "path": "list/valid/list-cctld-web.json",
111
+ "kind": "list",
112
+ "valid": true,
113
+ "note": "Section 6.2: ccTLD web store takes GB from its domain"
114
+ },
115
+ {
116
+ "path": "list/valid/list-marketplace-no-territories.json",
117
+ "kind": "list",
118
+ "valid": true,
119
+ "note": "Section 6.2: marketplace territory comes from the domain"
120
+ },
121
+ {
122
+ "path": "list/valid/list-worldwide.json",
123
+ "kind": "list",
124
+ "valid": true,
125
+ "note": "Worldwide scope"
126
+ },
127
+ {
128
+ "path": "list/valid/list-proposed-by.json",
129
+ "kind": "list",
130
+ "valid": true,
131
+ "note": "Section 3: distributor-proposed"
132
+ },
133
+ {
134
+ "path": "list/valid/list-not-public.json",
135
+ "kind": "list",
136
+ "valid": true,
137
+ "note": "Section 5.2: signed not-public response"
138
+ },
139
+ {
140
+ "path": "list/valid/list-no-authorizations.json",
141
+ "kind": "list",
142
+ "valid": true,
143
+ "note": "A brand with nothing authorized"
144
+ },
145
+ {
146
+ "path": "list/valid/list-fractional-seconds.json",
147
+ "kind": "list",
148
+ "valid": true,
149
+ "note": "Fractional seconds are allowed"
150
+ },
151
+ {
152
+ "path": "list/invalid/list-marketplace-field.json",
153
+ "kind": "list",
53
154
  "valid": false,
54
- "expect": "schema",
55
- "note": "Section 6: at least one channel identifier"
155
+ "expect": "marketplace_field_removed",
156
+ "note": "Section 6: marketplace was replaced by domain"
56
157
  },
57
158
  {
58
- "path": "file/invalid/full-name-only-retailer.json",
59
- "kind": "file",
159
+ "path": "list/invalid/list-amazon-on-walmart-domain.json",
160
+ "kind": "list",
60
161
  "valid": false,
61
- "expect": "schema",
62
- "note": "Section 6: a name alone is not verifiable"
162
+ "expect": "marketplace_domain_mismatch",
163
+ "note": "Section 6: type and domain must match"
63
164
  },
64
165
  {
65
- "path": "file/invalid/full-missing-scope.json",
66
- "kind": "file",
166
+ "path": "list/invalid/list-web-on-marketplace-domain.json",
167
+ "kind": "list",
67
168
  "valid": false,
68
- "expect": "schema",
69
- "note": "Section 3: every authorization MUST carry a scope"
169
+ "expect": "marketplace_domain_mismatch",
170
+ "note": "Section 6: a web channel can't use a marketplace domain"
70
171
  },
71
172
  {
72
- "path": "file/invalid/full-missing-territories.json",
73
- "kind": "file",
173
+ "path": "list/invalid/list-physical.json",
174
+ "kind": "list",
74
175
  "valid": false,
75
- "expect": "schema",
76
- "note": "Section 3: scope needs territories"
176
+ "expect": "unknown_channel_type",
177
+ "note": "Section 6: physical was removed"
77
178
  },
78
179
  {
79
- "path": "file/invalid/full-missing-product-lines.json",
80
- "kind": "file",
180
+ "path": "list/invalid/list-unknown-channel-type.json",
181
+ "kind": "list",
81
182
  "valid": false,
82
- "expect": "schema",
83
- "note": "Section 3: scope needs product lines"
183
+ "expect": "unknown_channel_type",
184
+ "note": "Section 6: unlisted channel type"
84
185
  },
85
186
  {
86
- "path": "file/invalid/full-missing-authorization-expires.json",
87
- "kind": "file",
187
+ "path": "list/invalid/list-amazon-missing-seller-id.json",
188
+ "kind": "list",
88
189
  "valid": false,
89
190
  "expect": "schema",
90
- "note": "Section 3: scope needs an expiry"
191
+ "note": "Section 6: amazon needs seller_id"
91
192
  },
92
193
  {
93
- "path": "file/invalid/full-empty-territories.json",
94
- "kind": "file",
194
+ "path": "list/invalid/list-web-domain-is-url.json",
195
+ "kind": "list",
95
196
  "valid": false,
96
197
  "expect": "schema",
97
- "note": "Territories cannot be empty"
198
+ "note": "Domains are bare hostnames"
98
199
  },
99
200
  {
100
- "path": "file/invalid/full-wildcard-mixed.json",
101
- "kind": "file",
201
+ "path": "list/invalid/list-no-channels.json",
202
+ "kind": "list",
102
203
  "valid": false,
103
204
  "expect": "schema",
104
- "note": "'*' must stand alone"
205
+ "note": "Section 6: at least one channel identifier"
105
206
  },
106
207
  {
107
- "path": "file/invalid/full-lowercase-territory.json",
108
- "kind": "file",
208
+ "path": "list/invalid/list-name-only-retailer.json",
209
+ "kind": "list",
109
210
  "valid": false,
110
211
  "expect": "schema",
212
+ "note": "Section 6: a name alone is not verifiable"
213
+ },
214
+ {
215
+ "path": "list/invalid/list-generic-web-no-territories.json",
216
+ "kind": "list",
217
+ "valid": false,
218
+ "expect": "territories_required",
219
+ "note": "Section 6.2: generic domain needs territories"
220
+ },
221
+ {
222
+ "path": "list/invalid/list-marketplace-territory-mismatch.json",
223
+ "kind": "list",
224
+ "valid": false,
225
+ "expect": "territory_mismatch",
226
+ "note": "Section 6.2: amazon.com is US"
227
+ },
228
+ {
229
+ "path": "list/invalid/list-territory-uk.json",
230
+ "kind": "list",
231
+ "valid": false,
232
+ "expect": "invalid_country",
233
+ "note": "ISO 3166-1: the United Kingdom is GB"
234
+ },
235
+ {
236
+ "path": "list/invalid/list-lowercase-territory.json",
237
+ "kind": "list",
238
+ "valid": false,
239
+ "expect": "invalid_country",
111
240
  "note": "Country codes are uppercase alpha-2"
112
241
  },
113
242
  {
114
- "path": "file/invalid/full-all-mixed.json",
115
- "kind": "file",
243
+ "path": "list/invalid/list-wildcard-mixed.json",
244
+ "kind": "list",
116
245
  "valid": false,
117
246
  "expect": "schema",
118
- "note": "'all' must stand alone"
247
+ "note": "'*' must stand alone"
119
248
  },
120
249
  {
121
- "path": "file/invalid/full-unknown-channel-type.json",
122
- "kind": "file",
250
+ "path": "list/invalid/list-empty-territories.json",
251
+ "kind": "list",
123
252
  "valid": false,
124
253
  "expect": "schema",
125
- "note": "Section 6: unlisted channel type"
254
+ "note": "Territories cannot be empty when given"
126
255
  },
127
256
  {
128
- "path": "file/invalid/full-amazon-missing-seller-id.json",
129
- "kind": "file",
257
+ "path": "list/invalid/list-missing-scope.json",
258
+ "kind": "list",
130
259
  "valid": false,
131
260
  "expect": "schema",
132
- "note": "Section 6: amazon needs seller_id"
261
+ "note": "Section 3: every authorization carries a scope"
133
262
  },
134
263
  {
135
- "path": "file/invalid/full-web-missing-domain.json",
136
- "kind": "file",
264
+ "path": "list/invalid/list-scope-no-products.json",
265
+ "kind": "list",
137
266
  "valid": false,
138
267
  "expect": "schema",
139
- "note": "Section 6: web needs domain"
268
+ "note": "Section 3: product_lines, products or both"
140
269
  },
141
270
  {
142
- "path": "file/invalid/full-web-domain-is-url.json",
143
- "kind": "file",
271
+ "path": "list/invalid/list-all-mixed.json",
272
+ "kind": "list",
144
273
  "valid": false,
145
274
  "expect": "schema",
146
- "note": "Domains are bare hostnames"
275
+ "note": "'all' must stand alone"
147
276
  },
148
277
  {
149
- "path": "file/invalid/full-physical-missing-country.json",
150
- "kind": "file",
278
+ "path": "list/invalid/list-bad-gtin.json",
279
+ "kind": "list",
151
280
  "valid": false,
152
- "expect": "schema",
153
- "note": "Section 6: physical needs country"
281
+ "expect": "invalid_gtin",
282
+ "note": "Section 3.1: GTIN check digit"
154
283
  },
155
284
  {
156
- "path": "file/invalid/full-wrong-spec.json",
157
- "kind": "file",
285
+ "path": "list/invalid/list-bad-asin.json",
286
+ "kind": "list",
158
287
  "valid": false,
159
- "expect": "schema",
160
- "note": "Unknown spec version"
288
+ "expect": "invalid_asin",
289
+ "note": "Section 3.1: ASINs are 10 uppercase letters or digits"
161
290
  },
162
291
  {
163
- "path": "file/invalid/full-missing-file-expires.json",
164
- "kind": "file",
292
+ "path": "list/invalid/list-product-no-identifier.json",
293
+ "kind": "list",
165
294
  "valid": false,
166
- "expect": "schema",
167
- "note": "File needs expires"
295
+ "expect": "product_without_identifier",
296
+ "note": "Section 3.1: gtin or asins"
168
297
  },
169
298
  {
170
- "path": "file/invalid/full-non-utc-timestamp.json",
171
- "kind": "file",
299
+ "path": "list/invalid/list-duplicate-asin.json",
300
+ "kind": "list",
172
301
  "valid": false,
173
- "expect": "schema",
174
- "note": "Timestamps are UTC with Z"
302
+ "expect": "duplicate_identifier",
303
+ "note": "Section 3.1: one ASIN on two products"
175
304
  },
176
305
  {
177
- "path": "file/invalid/full-extra-property.json",
178
- "kind": "file",
306
+ "path": "list/invalid/list-gtin-11-digits.json",
307
+ "kind": "list",
179
308
  "valid": false,
180
309
  "expect": "schema",
181
- "note": "Section 1: no pricing; unknown properties rejected"
310
+ "note": "11 digits is not a GTIN length"
311
+ },
312
+ {
313
+ "path": "list/invalid/list-duplicate-gtin.json",
314
+ "kind": "list",
315
+ "valid": false,
316
+ "expect": "duplicate_identifier",
317
+ "note": "Section 3.1: GTIN-13 and GTIN-14 of the same number collide"
182
318
  },
183
319
  {
184
- "path": "file/invalid/full-attached-jws.json",
185
- "kind": "file",
320
+ "path": "list/invalid/list-duplicate-product-id.json",
321
+ "kind": "list",
322
+ "valid": false,
323
+ "expect": "duplicate_product_id",
324
+ "note": "Product IDs are unique"
325
+ },
326
+ {
327
+ "path": "list/invalid/list-unknown-line.json",
328
+ "kind": "list",
329
+ "valid": false,
330
+ "expect": "unknown_product_line",
331
+ "note": "Section 3.1: scope names a line not in the catalog"
332
+ },
333
+ {
334
+ "path": "list/invalid/list-unknown-product.json",
335
+ "kind": "list",
336
+ "valid": false,
337
+ "expect": "unknown_product",
338
+ "note": "Section 3.1: scope names a product not in the catalog"
339
+ },
340
+ {
341
+ "path": "list/invalid/list-exclude-unknown-product.json",
342
+ "kind": "list",
343
+ "valid": false,
344
+ "expect": "unknown_product",
345
+ "note": "Section 3.1: exclusions must exist in the catalog"
346
+ },
347
+ {
348
+ "path": "list/invalid/list-brand-exclusion-no-catalog.json",
349
+ "kind": "list",
350
+ "valid": false,
351
+ "expect": "unknown_product_line",
352
+ "note": "Section 3.1: exclusions need a catalog"
353
+ },
354
+ {
355
+ "path": "list/invalid/list-duplicate-authorization-id.json",
356
+ "kind": "list",
357
+ "valid": false,
358
+ "expect": "duplicate_authorization_id",
359
+ "note": "Authorization IDs are unique within a list"
360
+ },
361
+ {
362
+ "path": "list/invalid/list-missing-revocation-id.json",
363
+ "kind": "list",
186
364
  "valid": false,
187
365
  "expect": "schema",
188
- "note": "Section 8: JWS must be detached"
366
+ "note": "Section 10.3: every authorization has a revocation_id"
189
367
  },
190
368
  {
191
- "path": "file/invalid/full-signature-missing-kid.json",
192
- "kind": "file",
369
+ "path": "list/invalid/list-expires-field.json",
370
+ "kind": "list",
193
371
  "valid": false,
194
372
  "expect": "schema",
195
- "note": "Section 8: every signature names its kid"
373
+ "note": "v0.2 lists use valid_until, not expires"
374
+ },
375
+ {
376
+ "path": "list/invalid/list-valid-over-15-minutes.json",
377
+ "kind": "list",
378
+ "valid": false,
379
+ "expect": "valid_until_exceeds_max",
380
+ "note": "Section 10.1: 15 minutes at most"
381
+ },
382
+ {
383
+ "path": "list/invalid/list-stale-over-24-hours.json",
384
+ "kind": "list",
385
+ "valid": false,
386
+ "expect": "stale_until_exceeds_max",
387
+ "note": "Section 10.2: 24 hours at most"
196
388
  },
197
389
  {
198
- "path": "file/invalid/pointer-http-url.json",
199
- "kind": "file",
390
+ "path": "list/invalid/list-missing-stale-until.json",
391
+ "kind": "list",
200
392
  "valid": false,
201
393
  "expect": "schema",
202
- "note": "Pointer must be HTTPS"
394
+ "note": "stale_until is required"
203
395
  },
204
396
  {
205
- "path": "file/invalid/private-missing-verify.json",
206
- "kind": "file",
397
+ "path": "list/invalid/list-single-domain.json",
398
+ "kind": "list",
207
399
  "valid": false,
208
400
  "expect": "schema",
209
- "note": "Private form needs a verify endpoint"
401
+ "note": "Section 5.2: lists name brand.domains"
210
402
  },
211
403
  {
212
- "path": "file/invalid/private-with-authorizations.json",
213
- "kind": "file",
404
+ "path": "list/invalid/list-not-public-with-authorizations.json",
405
+ "kind": "list",
214
406
  "valid": false,
215
407
  "expect": "schema",
216
- "note": "Section 5: private form carries no retailers"
408
+ "note": "Section 5.2: a not-public response carries no authorizations"
217
409
  },
218
410
  {
219
- "path": "file/invalid/unknown-form.json",
220
- "kind": "file",
411
+ "path": "list/invalid/list-not-public-with-catalog.json",
412
+ "kind": "list",
221
413
  "valid": false,
222
414
  "expect": "schema",
223
- "note": "Only full, pointer, private"
415
+ "note": "Section 5.2: nor a catalog"
224
416
  },
225
417
  {
226
- "path": "file/invalid/full-authorization-expires-after-file.json",
227
- "kind": "file",
418
+ "path": "list/invalid/list-extra-property.json",
419
+ "kind": "list",
228
420
  "valid": false,
229
- "expect": "authorization_expires_after_file",
230
- "note": "Section 5 MUST"
421
+ "expect": "schema",
422
+ "note": "Section 1: no pricing; unknown properties rejected"
231
423
  },
232
424
  {
233
- "path": "file/invalid/full-expiry-over-180-days.json",
234
- "kind": "file",
425
+ "path": "list/invalid/list-attached-jws.json",
426
+ "kind": "list",
235
427
  "valid": false,
236
- "expect": "file_expiry_exceeds_max",
237
- "note": "Section 10: max 180 days"
428
+ "expect": "schema",
429
+ "note": "Section 8: JWS must be detached"
238
430
  },
239
431
  {
240
- "path": "file/invalid/full-expires-before-issued.json",
241
- "kind": "file",
432
+ "path": "list/invalid/list-unsigned.json",
433
+ "kind": "list",
242
434
  "valid": false,
243
- "expect": "expires_not_after_issued",
244
- "note": "Expiry must follow issue"
435
+ "expect": "schema",
436
+ "note": "Section 5.2: lists are signed"
245
437
  },
246
438
  {
247
- "path": "file/invalid/full-duplicate-authorization-id.json",
248
- "kind": "file",
439
+ "path": "list/invalid/list-non-utc-timestamp.json",
440
+ "kind": "list",
249
441
  "valid": false,
250
- "expect": "duplicate_authorization_id",
251
- "note": "Authorization ids are unique within a file"
442
+ "expect": "schema",
443
+ "note": "Timestamps are UTC with Z"
252
444
  },
253
445
  {
254
- "path": "file/invalid/full-impossible-date.json",
255
- "kind": "file",
446
+ "path": "list/invalid/list-impossible-date.json",
447
+ "kind": "list",
256
448
  "valid": false,
257
449
  "expect": "schema",
258
- "note": "Feb 30 does not exist (format date-time; parseTimestamp also rejects it)"
450
+ "note": "Feb 30 does not exist"
259
451
  },
260
452
  {
261
- "path": "verify-request/valid/amazon.json",
453
+ "path": "verify-request/valid/full.json",
262
454
  "kind": "verify-request",
263
455
  "valid": true,
264
456
  "note": "Section 9 example"
265
457
  },
266
458
  {
267
- "path": "verify-request/valid/web-no-product-line.json",
459
+ "path": "verify-request/valid/minimal-marketplace.json",
268
460
  "kind": "verify-request",
269
461
  "valid": true,
270
- "note": "product_line defaults to all"
462
+ "note": "Territory defaults to amazon.com's country"
271
463
  },
272
464
  {
273
- "path": "verify-request/invalid/physical-channel.json",
465
+ "path": "verify-request/valid/web-generic-with-territory.json",
466
+ "kind": "verify-request",
467
+ "valid": true,
468
+ "note": "Section 6.2: generic domain names its territory"
469
+ },
470
+ {
471
+ "path": "verify-request/valid/web-cctld-no-territory.json",
472
+ "kind": "verify-request",
473
+ "valid": true,
474
+ "note": "Section 6.2: ccTLD implies GB"
475
+ },
476
+ {
477
+ "path": "verify-request/valid/gtin.json",
478
+ "kind": "verify-request",
479
+ "valid": true,
480
+ "note": "Product by GTIN"
481
+ },
482
+ {
483
+ "path": "verify-request/valid/as-of-datetime.json",
484
+ "kind": "verify-request",
485
+ "valid": true,
486
+ "note": "as_of as a UTC date-time"
487
+ },
488
+ {
489
+ "path": "verify-request/invalid/marketplace-field.json",
490
+ "kind": "verify-request",
491
+ "valid": false,
492
+ "expect": "marketplace_field_removed",
493
+ "note": "Section 6: marketplace was replaced by domain"
494
+ },
495
+ {
496
+ "path": "verify-request/invalid/gtin-and-asin.json",
274
497
  "kind": "verify-request",
275
498
  "valid": false,
276
499
  "expect": "schema",
277
- "note": "Section 6: physical is not verifiable"
500
+ "note": "Section 9: exactly one of gtin or asin"
501
+ },
502
+ {
503
+ "path": "verify-request/invalid/bad-gtin.json",
504
+ "kind": "verify-request",
505
+ "valid": false,
506
+ "expect": "invalid_gtin",
507
+ "note": "GTIN check digit"
508
+ },
509
+ {
510
+ "path": "verify-request/invalid/territory-uk.json",
511
+ "kind": "verify-request",
512
+ "valid": false,
513
+ "expect": "invalid_country",
514
+ "note": "ISO 3166-1: GB, not UK (normalizeVerifyRequest maps it)"
515
+ },
516
+ {
517
+ "path": "verify-request/invalid/generic-web-no-territory.json",
518
+ "kind": "verify-request",
519
+ "valid": false,
520
+ "expect": "territory_required",
521
+ "note": "Section 6.2: generic domain needs a territory"
522
+ },
523
+ {
524
+ "path": "verify-request/invalid/physical-channel.json",
525
+ "kind": "verify-request",
526
+ "valid": false,
527
+ "expect": "unknown_channel_type",
528
+ "note": "physical was removed"
278
529
  },
279
530
  {
280
531
  "path": "verify-request/invalid/wildcard-territory.json",
@@ -304,18 +555,49 @@
304
555
  "expect": "schema",
305
556
  "note": "Bare hostname only"
306
557
  },
558
+ {
559
+ "path": "verify-request/invalid/bad-as-of.json",
560
+ "kind": "verify-request",
561
+ "valid": false,
562
+ "expect": "schema",
563
+ "note": "as_of is an ISO 8601 date or UTC date-time"
564
+ },
307
565
  {
308
566
  "path": "verify-response/valid/authorized.json",
309
567
  "kind": "verify-response",
310
568
  "valid": true,
311
569
  "note": "Section 9 example"
312
570
  },
571
+ {
572
+ "path": "verify-response/valid/authorized-no-product.json",
573
+ "kind": "verify-response",
574
+ "valid": true,
575
+ "note": "No product asked"
576
+ },
577
+ {
578
+ "path": "verify-response/valid/authorized-with-end-date.json",
579
+ "kind": "verify-response",
580
+ "valid": true,
581
+ "note": "Brand-set end date"
582
+ },
313
583
  {
314
584
  "path": "verify-response/valid/authorized-observed.json",
315
585
  "kind": "verify-response",
316
586
  "valid": true,
317
587
  "note": "Section 7: seen selling within 30 days"
318
588
  },
589
+ {
590
+ "path": "verify-response/valid/authorized-not-in-catalog.json",
591
+ "kind": "verify-response",
592
+ "valid": true,
593
+ "note": "Section 9.2 rule 5"
594
+ },
595
+ {
596
+ "path": "verify-response/valid/authorized-private-product.json",
597
+ "kind": "verify-response",
598
+ "valid": true,
599
+ "note": "Section 9: private lists show only in_catalog"
600
+ },
319
601
  {
320
602
  "path": "verify-response/valid/expired.json",
321
603
  "kind": "verify-response",
@@ -332,17 +614,41 @@
332
614
  "valid": true
333
615
  },
334
616
  {
335
- "path": "verify-response/valid/brand-unverified-reason.json",
617
+ "path": "verify-response/valid/unlisted-territory-mismatch.json",
618
+ "kind": "verify-response",
619
+ "valid": true,
620
+ "note": "Section 6.2"
621
+ },
622
+ {
623
+ "path": "verify-response/valid/unlisted-product-excluded.json",
624
+ "kind": "verify-response",
625
+ "valid": true,
626
+ "note": "Section 9.2 rule 2"
627
+ },
628
+ {
629
+ "path": "verify-response/valid/unlisted-product-not-in-catalog.json",
336
630
  "kind": "verify-response",
337
631
  "valid": true,
338
- "note": "Section 9 reason"
632
+ "note": "Section 9.2 rule 4"
339
633
  },
340
634
  {
341
- "path": "verify-response/valid/brand-unverified-no-reason.json",
635
+ "path": "verify-response/valid/not-registered-reason.json",
636
+ "kind": "verify-response",
637
+ "valid": true,
638
+ "note": "Section 4 reason"
639
+ },
640
+ {
641
+ "path": "verify-response/valid/not-registered-no-reason.json",
342
642
  "kind": "verify-response",
343
643
  "valid": true,
344
644
  "note": "reason is optional"
345
645
  },
646
+ {
647
+ "path": "verify-response/valid/with-as-of.json",
648
+ "kind": "verify-response",
649
+ "valid": true,
650
+ "note": "Section 9: as_of echoed"
651
+ },
346
652
  {
347
653
  "path": "verify-response/valid/with-signal.json",
348
654
  "kind": "verify-response",
@@ -350,59 +656,88 @@
350
656
  "note": "Section 7 signals"
351
657
  },
352
658
  {
353
- "path": "verify-response/invalid/missing-observed.json",
659
+ "path": "verify-response/invalid/brand-unverified.json",
354
660
  "kind": "verify-response",
355
661
  "valid": false,
356
662
  "expect": "schema",
357
- "note": "Section 7: every answer MUST carry observed"
663
+ "note": "Renamed brand_not_registered in v0.2"
358
664
  },
359
665
  {
360
- "path": "verify-response/invalid/unlisted-observed.json",
666
+ "path": "verify-response/invalid/authorized-missing-revocation-id.json",
361
667
  "kind": "verify-response",
362
668
  "valid": false,
363
669
  "expect": "schema",
364
- "note": "Section 7: observed is null unless authorized"
670
+ "note": "Section 10.3: authorized answers carry revocation_id"
365
671
  },
366
672
  {
367
- "path": "verify-response/invalid/observed-without-last-seen.json",
673
+ "path": "verify-response/invalid/unlisted-with-revocation-id.json",
368
674
  "kind": "verify-response",
369
675
  "valid": false,
370
676
  "expect": "schema",
371
- "note": "Section 7: observed carries last_seen"
677
+ "note": "Only authorized answers carry revocation_id"
372
678
  },
373
679
  {
374
- "path": "verify-response/invalid/with-tier.json",
680
+ "path": "verify-response/invalid/unlisted-with-not-registered-reason.json",
375
681
  "kind": "verify-response",
376
682
  "valid": false,
377
683
  "expect": "schema",
378
- "note": "Evidence tiers were removed (section 7)"
684
+ "note": "Section 9: reasons belong to their status"
379
685
  },
380
686
  {
381
- "path": "verify-response/invalid/unlisted-with-reason.json",
687
+ "path": "verify-response/invalid/not-registered-with-unlisted-reason.json",
382
688
  "kind": "verify-response",
383
689
  "valid": false,
384
690
  "expect": "schema",
385
- "note": "Section 9: reason only on brand_unverified"
691
+ "note": "Section 9: reasons belong to their status"
386
692
  },
387
693
  {
388
- "path": "verify-response/invalid/unlisted-with-authorization-id.json",
694
+ "path": "verify-response/invalid/authorized-with-reason.json",
695
+ "kind": "verify-response",
696
+ "valid": false,
697
+ "expect": "schema",
698
+ "note": "Section 9: no reason on authorized"
699
+ },
700
+ {
701
+ "path": "verify-response/invalid/not-in-catalog-with-id.json",
702
+ "kind": "verify-response",
703
+ "valid": false,
704
+ "expect": "schema",
705
+ "note": "A product not in the catalog has no id"
706
+ },
707
+ {
708
+ "path": "verify-response/invalid/expired-without-expires.json",
389
709
  "kind": "verify-response",
390
710
  "valid": false,
391
711
  "expect": "schema",
392
- "note": "Unlisted answers leak nothing about other authorizations"
712
+ "note": "expired names the end date"
393
713
  },
394
714
  {
395
- "path": "verify-response/invalid/authorized-missing-authorization-id.json",
715
+ "path": "verify-response/invalid/missing-observed.json",
396
716
  "kind": "verify-response",
397
717
  "valid": false,
398
- "expect": "schema"
718
+ "expect": "schema",
719
+ "note": "Section 7: every answer MUST carry observed"
399
720
  },
400
721
  {
401
- "path": "verify-response/invalid/missing-valid-until.json",
722
+ "path": "verify-response/invalid/unlisted-observed.json",
402
723
  "kind": "verify-response",
403
724
  "valid": false,
404
725
  "expect": "schema",
405
- "note": "Section 9: valid_until is required"
726
+ "note": "Section 7: observed is null unless authorized"
727
+ },
728
+ {
729
+ "path": "verify-response/invalid/unlisted-with-authorization-id.json",
730
+ "kind": "verify-response",
731
+ "valid": false,
732
+ "expect": "schema",
733
+ "note": "Unlisted answers name no authorization"
734
+ },
735
+ {
736
+ "path": "verify-response/invalid/missing-stale-until.json",
737
+ "kind": "verify-response",
738
+ "valid": false,
739
+ "expect": "schema",
740
+ "note": "Section 10.2: stale_until is required"
406
741
  },
407
742
  {
408
743
  "path": "verify-response/invalid/missing-signature.json",
@@ -412,14 +747,21 @@
412
747
  "note": "Answers are signed"
413
748
  },
414
749
  {
415
- "path": "verify-response/invalid/unknown-status.json",
750
+ "path": "verify-response/invalid/with-tier.json",
416
751
  "kind": "verify-response",
417
752
  "valid": false,
418
753
  "expect": "schema",
419
- "note": "Section 1: unlisted is not unlawful"
754
+ "note": "Evidence tiers were removed (section 7)"
420
755
  },
421
756
  {
422
- "path": "verify-response/invalid/valid-until-over-24h.json",
757
+ "path": "verify-response/invalid/with-stale-flag.json",
758
+ "kind": "verify-response",
759
+ "valid": false,
760
+ "expect": "schema",
761
+ "note": "stale is the verifier's verdict, not part of a signed answer"
762
+ },
763
+ {
764
+ "path": "verify-response/invalid/valid-until-over-15-minutes.json",
423
765
  "kind": "verify-response",
424
766
  "valid": false,
425
767
  "expect": "valid_until_exceeds_max",
@@ -429,6 +771,119 @@
429
771
  "path": "verify-response/invalid/valid-until-before-checked.json",
430
772
  "kind": "verify-response",
431
773
  "valid": false,
432
- "expect": "valid_until_not_after_checked"
774
+ "expect": "valid_until_not_after_issued"
775
+ },
776
+ {
777
+ "path": "verify-response/invalid/stale-until-over-24-hours.json",
778
+ "kind": "verify-response",
779
+ "valid": false,
780
+ "expect": "stale_until_exceeds_max",
781
+ "note": "Section 10.2"
782
+ },
783
+ {
784
+ "path": "revocation-feed/valid/feed.json",
785
+ "kind": "revocation-feed",
786
+ "valid": true,
787
+ "note": "Section 10.3 example"
788
+ },
789
+ {
790
+ "path": "revocation-feed/valid/feed-empty.json",
791
+ "kind": "revocation-feed",
792
+ "valid": true,
793
+ "note": "No revocations in the last 24 hours"
794
+ },
795
+ {
796
+ "path": "revocation-feed/invalid/feed-hashed-entry.json",
797
+ "kind": "revocation-feed",
798
+ "valid": false,
799
+ "expect": "schema",
800
+ "note": "Section 10.3: entries are revocation IDs, not hashes"
801
+ },
802
+ {
803
+ "path": "revocation-feed/invalid/feed-valid-over-15-minutes.json",
804
+ "kind": "revocation-feed",
805
+ "valid": false,
806
+ "expect": "valid_until_exceeds_max",
807
+ "note": "Section 10.1"
808
+ },
809
+ {
810
+ "path": "match/seller-authorized-for-line.json",
811
+ "kind": "match",
812
+ "note": "Rule 1: in the catalog and covered"
813
+ },
814
+ {
815
+ "path": "match/seller-authorized-by-gtin.json",
816
+ "kind": "match",
817
+ "note": "GTIN-12 matches the catalog's GTIN-14"
818
+ },
819
+ {
820
+ "path": "match/product-excluded-by-authorization.json",
821
+ "kind": "match",
822
+ "note": "Rule 2: authorization excludes the product"
823
+ },
824
+ {
825
+ "path": "match/product-not-in-scope.json",
826
+ "kind": "match",
827
+ "note": "Rule 3: in the catalog, not included"
828
+ },
829
+ {
830
+ "path": "match/duplicate-asin-authorized-seller.json",
831
+ "kind": "match",
832
+ "note": "Rule 4: line-scoped seller, ASIN not in the catalog"
833
+ },
834
+ {
835
+ "path": "match/duplicate-asin-unauthorized-seller.json",
836
+ "kind": "match",
837
+ "note": "Section 9.1: an unauthorized seller's duplicate ASIN never authorizes"
838
+ },
839
+ {
840
+ "path": "match/all-scope-not-in-catalog.json",
841
+ "kind": "match",
842
+ "note": "Rule 5: [\"all\"] covers it, with a signal"
843
+ },
844
+ {
845
+ "path": "match/all-scope-excluded-line.json",
846
+ "kind": "match",
847
+ "note": "[\"all\"] with one excluded line"
848
+ },
849
+ {
850
+ "path": "match/brand-exclusion-beats-named-product.json",
851
+ "kind": "match",
852
+ "note": "Brand-level exclusion overrides an authorization naming the product"
853
+ },
854
+ {
855
+ "path": "match/marketplace-territory-default.json",
856
+ "kind": "match",
857
+ "note": "Territory defaults to amazon.co.uk's GB"
858
+ },
859
+ {
860
+ "path": "match/marketplace-territory-mismatch.json",
861
+ "kind": "match",
862
+ "note": "Section 6.2: amazon.co.uk is GB"
863
+ },
864
+ {
865
+ "path": "match/worldwide-web.json",
866
+ "kind": "match",
867
+ "note": "Worldwide web store"
868
+ },
869
+ {
870
+ "path": "match/product-line-request.json",
871
+ "kind": "match",
872
+ "note": "Excluded line asked by product_line"
873
+ },
874
+ {
875
+ "path": "match/expired-end-date.json",
876
+ "kind": "match",
877
+ "note": "Section 10: past the brand's end date"
878
+ },
879
+ {
880
+ "path": "match/as-of-before-end-date.json",
881
+ "kind": "match",
882
+ "note": "Section 9: as_of before the end date"
883
+ },
884
+ {
885
+ "path": "match/match-by-channel-key.json",
886
+ "kind": "match",
887
+ "note": "Section 6.1: Amazon seller IDs compare uppercased"
433
888
  }
434
889
  ]