@slicedearth/whoisleuth-cli 2.2.0 → 2.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.
Files changed (282) hide show
  1. package/NOTICE +6 -0
  2. package/README.md +20 -15
  3. package/bin/whoisleuth.mjs +8 -1
  4. package/cli/archive-content-digest.mjs +14 -0
  5. package/cli/archive-inspect.mjs +20 -53
  6. package/cli/arguments.mjs +454 -1748
  7. package/cli/artifact-validation/case-response.mjs +66 -35
  8. package/cli/artifact-validation/investigation-capsule.mjs +52 -31
  9. package/cli/artifact-validation/lookup-evidence.mjs +12 -6
  10. package/cli/artifact-validation/signed-review.mjs +112 -72
  11. package/cli/artifact-validation/structure-primitives.mjs +1 -105
  12. package/cli/artifact-verify.mjs +90 -24
  13. package/cli/assurance-command-runner.mjs +39 -4
  14. package/cli/bagit-folder.mjs +57 -0
  15. package/cli/bagit-review.mjs +23 -0
  16. package/cli/bounded-json.mjs +1 -1
  17. package/cli/bulk-checkpoint.mjs +34 -3
  18. package/cli/bulk-command-runner.mjs +2 -0
  19. package/cli/bulk-output.mjs +29 -3
  20. package/cli/case-command.mjs +195 -0
  21. package/cli/case-pack.mjs +66 -111
  22. package/cli/command-argument-grammar.mjs +215 -0
  23. package/cli/command-reference.mjs +342 -285
  24. package/cli/completion.mjs +303 -80
  25. package/cli/config-profile.mjs +7 -5
  26. package/cli/ct-event-intake.mjs +12 -12
  27. package/cli/discover.mjs +4 -3
  28. package/cli/discovery-observation-snapshot.mjs +59 -18
  29. package/cli/discovery-scan-command-runner.mjs +21 -0
  30. package/cli/discovery-scan.mjs +13 -4
  31. package/cli/discovery-workflow.mjs +1 -1
  32. package/cli/domain-control-monitor.mjs +50 -20
  33. package/cli/domain-control-observations.mjs +149 -102
  34. package/cli/errors.mjs +33 -1
  35. package/cli/evidence-command-runner.mjs +16 -5
  36. package/cli/evidence-signing.mjs +2 -2
  37. package/cli/external-observation-mapping.mjs +7 -8
  38. package/cli/formatters/terminal-lookup.mjs +18 -46
  39. package/cli/formatters/terminal-shared.mjs +5 -3
  40. package/cli/formatters/terminal-technology.mjs +114 -0
  41. package/cli/inline-command-families.mjs +2 -0
  42. package/cli/input.mjs +116 -0
  43. package/cli/interactive-launcher.mjs +2 -160
  44. package/cli/interchange-report.mjs +18 -8
  45. package/cli/investigation-artifacts.mjs +176 -0
  46. package/cli/investigation-checkpoint.mjs +10 -0
  47. package/cli/investigation-folder.mjs +114 -0
  48. package/cli/investigation-manifest.mjs +1 -112
  49. package/cli/investigation-package-review.mjs +103 -0
  50. package/cli/investigation-plan.mjs +32 -19
  51. package/cli/investigation-run.mjs +188 -33
  52. package/cli/local-document-checkpoint.mjs +170 -0
  53. package/cli/lookalike-calibration.mjs +7 -2
  54. package/cli/lookup-brief.mjs +4 -2
  55. package/cli/lookup-browser-view.mjs +1 -1
  56. package/cli/lookup-browser.mjs +5 -12
  57. package/cli/lookup-command-runner.mjs +17 -6
  58. package/cli/lookup-diff.mjs +37 -3
  59. package/cli/lookup-plan.mjs +11 -5
  60. package/cli/lookup-reconcile.mjs +10 -8
  61. package/cli/mail-header-review.mjs +467 -0
  62. package/cli/mail-review.mjs +66 -14
  63. package/cli/manual.mjs +1 -0
  64. package/cli/network-command-runner.mjs +2 -0
  65. package/cli/output-file.mjs +31 -5
  66. package/cli/registry-doctor.mjs +3 -1
  67. package/cli/registry-support.mjs +1 -1
  68. package/cli/retained-artifact-diff.mjs +2 -2
  69. package/cli/review-command-runner.mjs +70 -0
  70. package/cli/risk-calibration.mjs +19 -17
  71. package/cli/runner.mjs +62 -7
  72. package/cli/sharing-review.mjs +21 -34
  73. package/cli/signer-trust.mjs +104 -0
  74. package/cli/source-reliability.mjs +74 -83
  75. package/cli/terminal-input.mjs +168 -0
  76. package/cli/workflow-command-runner.mjs +68 -13
  77. package/docs/cli-reference.md +77 -24
  78. package/docs/cli.md +300 -25
  79. package/lib/abort.mjs +4 -1
  80. package/lib/availability.mjs +161 -112
  81. package/lib/bounded-file.mjs +3 -1
  82. package/lib/bounded-html-document.mjs +125 -0
  83. package/lib/bounded-json.mjs +51 -8
  84. package/lib/browser-library-profile.mjs +42 -51
  85. package/lib/browser-library-worker.mjs +112 -0
  86. package/lib/client-behavior-profile.mjs +3 -3
  87. package/lib/ct-search.mjs +11 -4
  88. package/lib/dns-convergence-review.mjs +1 -0
  89. package/lib/dns-delegation-health.mjs +24 -14
  90. package/lib/dns-inheritance-review.mjs +217 -0
  91. package/lib/dns-intelligence.mjs +73 -26
  92. package/lib/dns-mx.mjs +1 -1
  93. package/lib/dnssec-chain-validation.mjs +6 -0
  94. package/lib/dnssec-evidence-validation.mjs +11 -3
  95. package/lib/domain-change-packet.mjs +49 -16
  96. package/lib/domain-change-review.mjs +14 -8
  97. package/lib/domain-control-flight-recorder.mjs +221 -117
  98. package/lib/domain-control-manifest.mjs +129 -69
  99. package/lib/domain-posture-analysis.mjs +20 -7
  100. package/lib/domain-posture-parsers.mjs +201 -8
  101. package/lib/domain-posture.mjs +147 -29
  102. package/lib/evidence-export-privacy.mjs +561 -0
  103. package/lib/evidence-export.mjs +11 -543
  104. package/lib/evidence-report.mjs +5 -3
  105. package/lib/favicon.mjs +117 -41
  106. package/lib/generated/cisa-kev-catalog.mjs +12 -4
  107. package/lib/generated/registrar-standing-catalogue.mjs +7 -7
  108. package/lib/generated/retire-browser-catalog.mjs +2335 -940
  109. package/lib/hostname.mjs +2 -38
  110. package/lib/html-signals.mjs +111 -108
  111. package/lib/http-evidence-bounds.mjs +2 -1
  112. package/lib/http-intelligence.mjs +39 -26
  113. package/lib/local-geoip-evidence.mjs +19 -3
  114. package/lib/lookup-cache.mjs +34 -11
  115. package/lib/lookup-child-profile-contract.mjs +24 -15
  116. package/lib/lookup-diagnostics.mjs +24 -1
  117. package/lib/lookup-progress.mjs +30 -13
  118. package/lib/lookup-response-contract.mjs +1048 -0
  119. package/lib/lookup-response.mjs +8 -10
  120. package/lib/lookup-source-progress.mjs +40 -14
  121. package/lib/lookup.mjs +48 -27
  122. package/lib/nameserver-preflight-review.mjs +1 -0
  123. package/lib/observed-network-context.mjs +43 -27
  124. package/lib/outbound-request-bounds.mjs +4 -1
  125. package/lib/page-fingerprints.mjs +69 -133
  126. package/lib/page-role-profile.mjs +12 -8
  127. package/lib/perceptual-hash.mjs +43 -14
  128. package/lib/rdap-bootstrap.mjs +72 -22
  129. package/lib/rdap-capabilities.mjs +1 -1
  130. package/lib/rdap-client.mjs +15 -7
  131. package/lib/rdap-normalization.mjs +33 -18
  132. package/lib/rdap-search-workbench.mjs +1 -1
  133. package/lib/rdap-transport.mjs +47 -20
  134. package/lib/rdap-types.mjs +2 -1
  135. package/lib/rdap.mjs +18 -3
  136. package/lib/registrable-domain.mjs +21 -1
  137. package/lib/registrar-standing-contract.mjs +1 -0
  138. package/lib/registry-capabilities.mjs +5 -1
  139. package/lib/registry-capability-catalogue.mjs +2 -1
  140. package/lib/registry-dates.mjs +2 -190
  141. package/lib/registry-insights.mjs +85 -34
  142. package/lib/response-policy.mjs +86 -48
  143. package/lib/risk-calibration-summary.mjs +18 -6
  144. package/lib/rpki-evidence.mjs +8 -5
  145. package/lib/safe-fetch.mjs +54 -47
  146. package/lib/security-txt.mjs +42 -7
  147. package/lib/service-binding-dns.mjs +8 -0
  148. package/lib/smtp-transport-review.mjs +27 -15
  149. package/lib/sslbl-certificates.generated.mjs +136 -135
  150. package/lib/static-html-analysis.mjs +178 -151
  151. package/lib/structured-data-identity.mjs +1 -0
  152. package/lib/technology-markup.mjs +100 -0
  153. package/lib/threat-intelligence-manifests.mjs +11 -139
  154. package/lib/threat-intelligence-runtime.mjs +24 -52
  155. package/lib/threat-intelligence-targets.mjs +6 -34
  156. package/lib/threat-intelligence-types.mjs +39 -0
  157. package/lib/typosquat-generator.mjs +19 -15
  158. package/lib/urlhaus-intelligence.mjs +8 -3
  159. package/lib/urlscan-intelligence.mjs +1 -1
  160. package/lib/website-security-posture.mjs +30 -6
  161. package/lib/website-technology.mjs +153 -45
  162. package/lib/whois-authority.mjs +14 -2
  163. package/lib/whois-chain.mjs +9 -2
  164. package/lib/whois-common-formats.mjs +5 -5
  165. package/lib/whois-contracts.mjs +2 -1
  166. package/lib/whois-dialects.mjs +2 -2
  167. package/lib/whois-parser-support.mjs +8 -1
  168. package/lib/whois-transport.mjs +23 -7
  169. package/lib/zone-intent-review.mjs +16 -6
  170. package/package.json +2 -1
  171. package/packages/cases/case-attachment-model.mjs +83 -0
  172. package/packages/cases/case-evidence-model.mjs +156 -62
  173. package/packages/cases/case-export-input.mjs +53 -0
  174. package/packages/cases/case-migration-model.mjs +127 -44
  175. package/packages/cases/case-model.mjs +1 -0
  176. package/packages/cases/case-recheck-model.mjs +91 -0
  177. package/packages/cases/case-record-contracts.mjs +5 -20
  178. package/packages/cases/case-record-core.mjs +12 -22
  179. package/packages/cases/case-record-decisions.mjs +72 -0
  180. package/packages/cases/case-record-model.mjs +1 -0
  181. package/packages/cases/case-record-operations.mjs +95 -31
  182. package/packages/cases/case-record-projection.mjs +221 -0
  183. package/packages/cases/case-report.mjs +70 -54
  184. package/packages/cases/case-response-actions.mjs +654 -0
  185. package/packages/cases/case-response-model.mjs +64 -1115
  186. package/packages/cases/case-response-outcomes.mjs +317 -0
  187. package/packages/cases/case-response-packet-render.mjs +153 -0
  188. package/packages/cases/case-response-packet-types.mjs +1 -0
  189. package/packages/cases/case-response-packet-vocabulary.mjs +48 -0
  190. package/packages/cases/case-response-packet.mjs +74 -572
  191. package/packages/cases/case-response-records.mjs +94 -0
  192. package/packages/cases/case-response-review-inputs.mjs +371 -0
  193. package/packages/cases/case-response-values.mjs +85 -0
  194. package/packages/cases/case-review-package.mjs +45 -0
  195. package/packages/cases/case-selection.mjs +46 -0
  196. package/packages/cases/case-storage-model.mjs +31 -2
  197. package/packages/cases/response-route-freshness.mjs +16 -0
  198. package/packages/comparison/capture-context.mjs +61 -0
  199. package/packages/comparison/comparison-ledger-bulk.mjs +13 -11
  200. package/packages/comparison/page-similarity.mjs +5 -2
  201. package/packages/comparison/relationship-evidence.mjs +85 -8
  202. package/packages/comparison/relationship-provenance.mjs +93 -0
  203. package/packages/contracts/analyst-interchange.mjs +216 -0
  204. package/packages/contracts/analyst-review-state-contract.mjs +11 -0
  205. package/packages/contracts/analyst-review-state.mjs +5 -4
  206. package/packages/contracts/case-portability.mjs +366 -83
  207. package/packages/contracts/case-views-contract.mjs +12 -0
  208. package/packages/contracts/case-views.mjs +26 -0
  209. package/packages/contracts/cli-command-semantics.mjs +94 -0
  210. package/packages/contracts/cli-lookup.mjs +0 -1
  211. package/packages/contracts/domain-control-flight-recorder.mjs +80 -42
  212. package/packages/contracts/domain-control-manifest.mjs +127 -73
  213. package/packages/contracts/domain-control-monitor.mjs +48 -45
  214. package/packages/contracts/domain-control-review.mjs +179 -121
  215. package/packages/contracts/domain-name.mjs +21 -0
  216. package/packages/contracts/external-observation-interchange.mjs +2 -1
  217. package/packages/contracts/extracted-domain-lifecycle.mjs +11 -32
  218. package/packages/contracts/http-url.mjs +2 -0
  219. package/packages/contracts/investigation-package-limits.mjs +24 -0
  220. package/packages/contracts/investigation-portability.mjs +56 -27
  221. package/packages/contracts/investigation-run.mjs +16 -0
  222. package/packages/contracts/ip-address.mjs +34 -0
  223. package/packages/contracts/lookup-evidence.mjs +35 -0
  224. package/packages/contracts/offline-comparison.mjs +1 -2
  225. package/packages/contracts/page-fingerprints.mjs +15 -0
  226. package/packages/contracts/risk-calibration.mjs +15 -11
  227. package/packages/contracts/schema-compatibility.mjs +1 -1
  228. package/packages/contracts/schema-lifecycle.mjs +83 -153
  229. package/packages/contracts/selected-file-limits.mjs +6 -0
  230. package/packages/contracts/vulnerability-identifiers.mjs +5 -0
  231. package/packages/contracts/web-capture.mjs +10 -0
  232. package/packages/contracts/workspace-portability.mjs +183 -211
  233. package/packages/evidence/artifact-integrity.mjs +8 -2
  234. package/packages/evidence/artifact-structure.mjs +105 -0
  235. package/packages/evidence/decision-fact.mjs +4 -1
  236. package/packages/evidence/domain-control-runtime.mjs +201 -33
  237. package/packages/evidence/domain-posture-context.mjs +79 -0
  238. package/packages/evidence/image-regions.mjs +56 -0
  239. package/packages/evidence/latest-observations.mjs +28 -0
  240. package/packages/evidence/lookup-target.mjs +104 -0
  241. package/packages/evidence/observation.mjs +16 -1
  242. package/packages/evidence/passphrase-encryption.mjs +44 -0
  243. package/packages/evidence/record-identity.mjs +72 -0
  244. package/packages/evidence/registry-dates.mjs +190 -0
  245. package/packages/evidence/retained-file.mjs +69 -0
  246. package/packages/evidence/review-age.mjs +14 -0
  247. package/packages/interchange/bagit.mjs +342 -0
  248. package/packages/interchange/bounded-zip-extraction.mjs +278 -0
  249. package/packages/interchange/crc32.mjs +17 -0
  250. package/packages/interchange/external-findings-import.mjs +92 -51
  251. package/packages/interchange/web-capture-import.mjs +382 -0
  252. package/packages/investigation/bulk-mail-exposure.mjs +2 -1
  253. package/packages/investigation/investigation-bagit.mjs +14 -0
  254. package/packages/investigation/investigation-capsule.mjs +33 -5
  255. package/packages/investigation/investigation-manifest.mjs +200 -0
  256. package/packages/investigation/investigation-package-crypto.mjs +98 -0
  257. package/packages/investigation/investigation-package.mjs +200 -0
  258. package/packages/investigation/lookup-asset-graph-inputs.mjs +38 -0
  259. package/packages/investigation/lookup-asset-graph.mjs +193 -165
  260. package/packages/investigation/lookup-claim-readiness.mjs +18 -0
  261. package/packages/investigation/lookup-investigation-brief.mjs +3 -3
  262. package/packages/investigation/lookup-task-guidance.mjs +58 -0
  263. package/packages/monitoring/analyst-review-state.mjs +38 -90
  264. package/packages/workspace/brand-profile-model.mjs +276 -22
  265. package/packages/workspace/bulk-columns.mjs +17 -0
  266. package/packages/workspace/bulk-review-model.mjs +23 -11
  267. package/packages/workspace/bulk-session-model.mjs +100 -24
  268. package/packages/workspace/bulk-sort.mjs +1 -0
  269. package/packages/workspace/case-views.mjs +102 -0
  270. package/packages/workspace/detection-rule-model.mjs +70 -22
  271. package/packages/workspace/hostile-input.mjs +29 -8
  272. package/packages/workspace/investigation-template-model.mjs +19 -4
  273. package/packages/workspace/page-baseline.mjs +18 -15
  274. package/packages/workspace/relationship-observation-model.mjs +41 -23
  275. package/packages/workspace/watchlist-history.mjs +2 -2
  276. package/packages/workspace/watchlist-store.mjs +8 -2
  277. package/packages/workspace/website-snapshot-model.mjs +164 -26
  278. package/packages/workspace/workspace-archive-crypto.mjs +41 -61
  279. package/packages/workspace/workspace-archive.mjs +87 -21
  280. package/third-party-notices.txt +29 -2
  281. package/cli/evidence-command-arguments.mjs +0 -156
  282. package/packages/investigation/bulk-review-export.mjs +0 -63
@@ -1,14 +1,19 @@
1
1
  import { defineSchemaCompatibility } from "./schema-compatibility.mjs";
2
2
  import { defineSchemaLifecycleFamily } from "./schema-lifecycle.mjs";
3
- import { DOMAIN_CONTROL_MANIFEST_ENTRY_KEYS, DOMAIN_CONTROL_MANIFEST_INTEGRITY_KEYS, DOMAIN_CONTROL_MANIFEST_LIMITATIONS, DOMAIN_CONTROL_MANIFEST_ROOT_KEYS, DOMAIN_CONTROL_SPKI_SHA256_HEX_LENGTH, DOMAIN_CONTROL_TEXT_INPUT_BOUND_FACTOR, MAX_CANONICAL_DOMAIN_CONTROL_RECORDS, MAX_DOMAIN_CONTROL_CLI_REVIEW_JSON_DEPTH, MAX_DOMAIN_CONTROL_CLI_REVIEW_JSON_KEYS, MAX_DOMAIN_CONTROL_CLI_REVIEW_JSON_VALUES, MAX_DOMAIN_CONTROL_DOMAIN_LENGTH, MAX_DOMAIN_CONTROL_INPUT_RECORDS, MAX_DOMAIN_CONTROL_JSON_CONTAINER_ITEMS, MAX_DOMAIN_CONTROL_MANIFEST_BYTES, MAX_DOMAIN_CONTROL_MANIFEST_ENTRIES, MAX_DOMAIN_CONTROL_TIMESTAMP_LENGTH, } from "./domain-control-manifest.mjs";
3
+ import { PUBLIC_DOMAIN_CONTROL_MANIFEST_ENTRY_KEYS, PUBLIC_DOMAIN_CONTROL_MANIFEST_LIMITATIONS, DOMAIN_CONTROL_MANIFEST_INTEGRITY_KEYS, DOMAIN_CONTROL_MANIFEST_ROOT_KEYS, DOMAIN_CONTROL_SPKI_SHA256_HEX_LENGTH, DOMAIN_CONTROL_TEXT_INPUT_BOUND_FACTOR, MAX_CURRENT_DOMAIN_CONTROL_RECORDS, MAX_CANONICAL_DOMAIN_CONTROL_RECORDS, MAX_DOMAIN_CONTROL_CLI_REVIEW_JSON_DEPTH, MAX_DOMAIN_CONTROL_CLI_REVIEW_JSON_KEYS, MAX_DOMAIN_CONTROL_CLI_REVIEW_JSON_VALUES, MAX_DOMAIN_CONTROL_DOMAIN_LENGTH, MAX_DOMAIN_CONTROL_INPUT_RECORDS, MAX_DOMAIN_CONTROL_JSON_CONTAINER_ITEMS, MAX_DOMAIN_CONTROL_MANIFEST_BYTES, MAX_DOMAIN_CONTROL_MANIFEST_ENTRIES, MAX_DOMAIN_CONTROL_TIMESTAMP_LENGTH, } from "./domain-control-manifest.mjs";
4
4
  import { MAX_DOMAIN_CONTROL_MONITOR_CONCURRENCY, MAX_DOMAIN_CONTROL_MONITOR_DOMAINS, MIN_DOMAIN_CONTROL_MONITOR_CONCURRENCY, MIN_DOMAIN_CONTROL_MONITOR_DOMAINS, } from "./domain-control-monitor.mjs";
5
5
  import { MAX_CLI_LOOKUP_BYTES } from "./cli-lookup.mjs";
6
+ import { DOMAIN_CONTROL_FLIGHT_RECORDER_OBSERVATION_KEYS, PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_OBSERVATION_KEYS, DOMAIN_CONTROL_FLIGHT_RECORDER_FIELD_KEYS, PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_FIELD_KEYS, } from "./domain-control-flight-recorder.mjs";
6
7
  export const DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA = 'whoisleuth.domain-control-review-input';
7
8
  export const DOMAIN_CONTROL_REVIEW_SCHEMA = 'whoisleuth.domain-control-review';
8
9
  export const CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA = 'whoisleuth.cli.domain-control-review-input';
9
10
  export const CLI_DOMAIN_CONTROL_REVIEW_SCHEMA = 'whoisleuth.cli.domain-control-review';
10
- export const DOMAIN_CONTROL_REVIEW_VERSION = 1;
11
- export const CLI_DOMAIN_CONTROL_REVIEW_VERSION = 1;
11
+ export const PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION = 1;
12
+ export const PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION = 1;
13
+ export const DOMAIN_CONTROL_REVIEW_VERSION = 2;
14
+ export const CLI_DOMAIN_CONTROL_REVIEW_VERSION = 2;
15
+ export const SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS = [PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION, DOMAIN_CONTROL_REVIEW_VERSION];
16
+ export const SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS = [PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION, CLI_DOMAIN_CONTROL_REVIEW_VERSION];
12
17
  export const DOMAIN_CONTROL_REVIEW_OBSERVATION_FACTOR = 2;
13
18
  export const MAX_DOMAIN_CONTROL_REVIEW_OBSERVATIONS = MAX_DOMAIN_CONTROL_MANIFEST_ENTRIES
14
19
  * DOMAIN_CONTROL_REVIEW_OBSERVATION_FACTOR;
@@ -73,7 +78,7 @@ export const DOMAIN_CONTROL_REVIEW_MANIFEST_SUMMARY_KEYS = Object.freeze([
73
78
  'digestSha256',
74
79
  'expired',
75
80
  ]);
76
- export const DOMAIN_CONTROL_REVIEW_COUNT_KEYS = Object.freeze([
81
+ export const PUBLIC_DOMAIN_CONTROL_REVIEW_COUNT_KEYS = Object.freeze([
77
82
  'aligned',
78
83
  'drift',
79
84
  'partial',
@@ -82,12 +87,13 @@ export const DOMAIN_CONTROL_REVIEW_COUNT_KEYS = Object.freeze([
82
87
  'not_configured',
83
88
  'due',
84
89
  ]);
90
+ export const DOMAIN_CONTROL_REVIEW_COUNT_KEYS = Object.freeze([...PUBLIC_DOMAIN_CONTROL_REVIEW_COUNT_KEYS, 'observed']);
85
91
  export const DOMAIN_CONTROL_REVIEW_DOMAIN_KEYS = Object.freeze([
86
92
  'domain',
87
93
  'state',
88
94
  'comparisons',
89
95
  ]);
90
- export const DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS = Object.freeze([
96
+ export const PUBLIC_DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS = Object.freeze([
91
97
  'field',
92
98
  'state',
93
99
  'desired',
@@ -96,11 +102,17 @@ export const DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS = Object.freeze([
96
102
  'observedAt',
97
103
  'explanation',
98
104
  ]);
99
- export const DOMAIN_CONTROL_REVIEW_LIMITATIONS = Object.freeze([
105
+ export const DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS = Object.freeze([...PUBLIC_DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS, 'expectation']);
106
+ export const PUBLIC_DOMAIN_CONTROL_REVIEW_LIMITATIONS = Object.freeze([
100
107
  'This local review compares analyst-authored desired state with separately supplied observations and performs no collection or configuration change.',
101
108
  'Only complete observations can produce drift. Partial, unavailable, unsupported, or missing evidence remains inconclusive.',
102
109
  'A valid manifest digest or signature establishes file integrity, not the correctness of the desired state or supplied observations.',
103
110
  ]);
111
+ export const DOMAIN_CONTROL_REVIEW_LIMITATIONS = Object.freeze([
112
+ PUBLIC_DOMAIN_CONTROL_REVIEW_LIMITATIONS[0],
113
+ 'Only complete observations with valid source times within the current review-age window can establish alignment, drift or expected absence. Observation-only fields do not establish alignment.',
114
+ PUBLIC_DOMAIN_CONTROL_REVIEW_LIMITATIONS[2],
115
+ ]);
104
116
  export const CLI_DOMAIN_CONTROL_REVIEW_INPUT_KEYS = Object.freeze([
105
117
  'schema',
106
118
  'version',
@@ -116,37 +128,34 @@ export const CLI_DOMAIN_CONTROL_REVIEW_ROOT_KEYS = Object.freeze([
116
128
  'input',
117
129
  'limitations',
118
130
  ]);
119
- export const CLI_DOMAIN_CONTROL_REVIEW_OBSERVATION_KEYS = Object.freeze([
120
- 'domain',
121
- 'observedAt',
122
- 'collectionDepth',
123
- 'fields',
124
- ]);
125
- export const CLI_DOMAIN_CONTROL_REVIEW_FIELD_KEYS = Object.freeze([
126
- 'id',
127
- 'source',
128
- 'state',
129
- 'values',
130
- ]);
131
+ export const PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_OBSERVATION_KEYS = PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_OBSERVATION_KEYS;
132
+ export const CLI_DOMAIN_CONTROL_REVIEW_OBSERVATION_KEYS = DOMAIN_CONTROL_FLIGHT_RECORDER_OBSERVATION_KEYS;
133
+ export const PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_FIELD_KEYS = PUBLIC_DOMAIN_CONTROL_FLIGHT_RECORDER_FIELD_KEYS;
134
+ export const CLI_DOMAIN_CONTROL_REVIEW_FIELD_KEYS = DOMAIN_CONTROL_FLIGHT_RECORDER_FIELD_KEYS;
131
135
  export const CLI_DOMAIN_CONTROL_REVIEW_INPUT_SUMMARY_KEYS = Object.freeze([
132
136
  'lookupsReceived',
133
137
  'latestDomainObservations',
134
138
  'ignoredHistoricalLookups',
135
139
  ]);
136
- export const CLI_DOMAIN_CONTROL_REVIEW_LIMITATIONS = Object.freeze([
140
+ export const PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_LIMITATIONS = Object.freeze([
137
141
  'The review uses only supplied saved Lookup documents and performs no request.',
138
142
  'The newest supplied observation per domain is used for desired-state comparison; all supplied observations remain available to a separate flight-recorder review.',
139
143
  'Raw RDAP, WHOIS, HTTP, TLS, and page payloads are not copied into this output.',
140
144
  ]);
145
+ export const CLI_DOMAIN_CONTROL_REVIEW_LIMITATIONS = Object.freeze([
146
+ PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_LIMITATIONS[0],
147
+ 'The newest supplied capture per domain is reviewed using each field’s retained source time. Missing or conflicting source times remain inconclusive.',
148
+ PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_LIMITATIONS[2],
149
+ ]);
141
150
  export const DOMAIN_CONTROL_REVIEW_INPUT_COMPATIBILITY = defineSchemaCompatibility({
142
151
  id: 'cli.domain-control-review-core-input',
143
152
  kind: 'cli_document',
144
153
  schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA,
145
154
  currentVersion: DOMAIN_CONTROL_REVIEW_VERSION,
146
- supportedVersions: [DOMAIN_CONTROL_REVIEW_VERSION],
155
+ supportedVersions: SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS,
147
156
  acceptsUnversionedLegacy: false,
148
157
  futureVersionBehavior: 'reject',
149
- migration: 'exact_current_only',
158
+ migration: 'read_only',
150
159
  writeSemantics: 'read_only',
151
160
  byteBudget: null,
152
161
  owner: 'packages/contracts/domain-control-review.mts',
@@ -157,10 +166,10 @@ export const DOMAIN_CONTROL_REVIEW_COMPATIBILITY = defineSchemaCompatibility({
157
166
  kind: 'cli_document',
158
167
  schema: DOMAIN_CONTROL_REVIEW_SCHEMA,
159
168
  currentVersion: DOMAIN_CONTROL_REVIEW_VERSION,
160
- supportedVersions: [DOMAIN_CONTROL_REVIEW_VERSION],
169
+ supportedVersions: SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS,
161
170
  acceptsUnversionedLegacy: false,
162
171
  futureVersionBehavior: 'reject',
163
- migration: 'exact_current_only',
172
+ migration: 'read_only',
164
173
  writeSemantics: 'read_only',
165
174
  byteBudget: null,
166
175
  owner: 'packages/contracts/domain-control-review.mts',
@@ -171,10 +180,10 @@ export const CLI_DOMAIN_CONTROL_REVIEW_INPUT_COMPATIBILITY = defineSchemaCompati
171
180
  kind: 'cli_document',
172
181
  schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA,
173
182
  currentVersion: CLI_DOMAIN_CONTROL_REVIEW_VERSION,
174
- supportedVersions: [CLI_DOMAIN_CONTROL_REVIEW_VERSION],
183
+ supportedVersions: SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS,
175
184
  acceptsUnversionedLegacy: false,
176
185
  futureVersionBehavior: 'reject',
177
- migration: 'exact_current_only',
186
+ migration: 'read_only',
178
187
  writeSemantics: 'read_only',
179
188
  byteBudget: MAX_DOMAIN_CONTROL_REVIEW_INPUT_BYTES,
180
189
  owner: 'packages/contracts/domain-control-review.mts',
@@ -185,7 +194,7 @@ export const CLI_DOMAIN_CONTROL_REVIEW_COMPATIBILITY = defineSchemaCompatibility
185
194
  kind: 'cli_document',
186
195
  schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA,
187
196
  currentVersion: CLI_DOMAIN_CONTROL_REVIEW_VERSION,
188
- supportedVersions: [CLI_DOMAIN_CONTROL_REVIEW_VERSION],
197
+ supportedVersions: SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS,
189
198
  acceptsUnversionedLegacy: false,
190
199
  futureVersionBehavior: 'not_applicable',
191
200
  migration: 'read_only',
@@ -194,15 +203,15 @@ export const CLI_DOMAIN_CONTROL_REVIEW_COMPATIBILITY = defineSchemaCompatibility
194
203
  owner: 'packages/contracts/domain-control-review.mts',
195
204
  note: 'Compact source-qualified control observations and desired-state comparison.',
196
205
  });
197
- const CORE_REVIEW_SHAPES = [
206
+ const CORE_REVIEW_SHAPES = SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS.flatMap((version) => [
198
207
  {
199
- id: 'domain-control-review.input.v1',
208
+ id: `domain-control-review.input.v${version}`,
200
209
  schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA,
201
- versions: [DOMAIN_CONTROL_REVIEW_VERSION],
210
+ versions: [version],
202
211
  objects: [
203
212
  { path: '$', requiredKeys: DOMAIN_CONTROL_REVIEW_INPUT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
204
213
  { path: '$.manifest', requiredKeys: DOMAIN_CONTROL_MANIFEST_ROOT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
205
- { path: '$.manifest.entries[]', requiredKeys: DOMAIN_CONTROL_MANIFEST_ENTRY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
214
+ { path: '$.manifest.entries[]', requiredKeys: PUBLIC_DOMAIN_CONTROL_MANIFEST_ENTRY_KEYS, optionalKeys: version === PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION ? [] : ['recordModes'], unknownKeys: 'reject' },
206
215
  { path: '$.manifest.integrity', requiredKeys: DOMAIN_CONTROL_MANIFEST_INTEGRITY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
207
216
  { path: '$.observations[]', requiredKeys: DOMAIN_CONTROL_REVIEW_OBSERVATION_KEYS, optionalKeys: [], unknownKeys: 'reject' },
208
217
  { path: '$.observations[].fields', requiredKeys: [], optionalKeys: DOMAIN_CONTROL_REVIEW_FIELDS, unknownKeys: 'reject' },
@@ -213,26 +222,54 @@ const CORE_REVIEW_SHAPES = [
213
222
  unknownKeys: 'reject',
214
223
  })),
215
224
  ],
216
- fixedArrays: [{ path: '$.manifest.limitations', values: DOMAIN_CONTROL_MANIFEST_LIMITATIONS }],
225
+ fixedArrays: version === PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION ? [{ path: '$.manifest.limitations', values: PUBLIC_DOMAIN_CONTROL_MANIFEST_LIMITATIONS }] : [],
217
226
  normalisation: 'input_to_current',
218
227
  target: { schema: DOMAIN_CONTROL_REVIEW_SCHEMA, version: DOMAIN_CONTROL_REVIEW_VERSION },
219
228
  },
220
229
  {
221
- id: 'domain-control-review.document.v1',
230
+ id: `domain-control-review.document.v${version}`,
222
231
  schema: DOMAIN_CONTROL_REVIEW_SCHEMA,
223
- versions: [DOMAIN_CONTROL_REVIEW_VERSION],
232
+ versions: [version],
224
233
  objects: [
225
234
  { path: '$', requiredKeys: DOMAIN_CONTROL_REVIEW_ROOT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
226
235
  { path: '$.manifest', requiredKeys: DOMAIN_CONTROL_REVIEW_MANIFEST_SUMMARY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
227
- { path: '$.counts', requiredKeys: DOMAIN_CONTROL_REVIEW_COUNT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
236
+ { path: '$.counts', requiredKeys: version === PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION ? PUBLIC_DOMAIN_CONTROL_REVIEW_COUNT_KEYS : DOMAIN_CONTROL_REVIEW_COUNT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
228
237
  { path: '$.domains[]', requiredKeys: DOMAIN_CONTROL_REVIEW_DOMAIN_KEYS, optionalKeys: [], unknownKeys: 'reject' },
229
- { path: '$.domains[].comparisons[]', requiredKeys: DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS, optionalKeys: [], unknownKeys: 'reject' },
238
+ { path: '$.domains[].comparisons[]', requiredKeys: version === PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION ? PUBLIC_DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS : DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS, optionalKeys: [], unknownKeys: 'reject' },
230
239
  ],
231
- fixedArrays: [{ path: '$.limitations', values: DOMAIN_CONTROL_REVIEW_LIMITATIONS }],
240
+ fixedArrays: [{ path: '$.limitations', values: version === PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION ? PUBLIC_DOMAIN_CONTROL_REVIEW_LIMITATIONS : DOMAIN_CONTROL_REVIEW_LIMITATIONS }],
232
241
  normalisation: 'preserve_document',
233
242
  target: null,
234
243
  },
235
- ];
244
+ ]);
245
+ const CORE_BOUND_PROFILE_IDS = SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS.map((version) => `domain-control-review.core.v${version}`);
246
+ const CORE_INPUT_SHAPE_IDS = SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS.map((version) => `domain-control-review.input.v${version}`);
247
+ const CORE_DOCUMENT_SHAPE_IDS = SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS.map((version) => `domain-control-review.document.v${version}`);
248
+ const CURRENT_CORE_DOCUMENT_SHAPE_ID = `domain-control-review.document.v${DOMAIN_CONTROL_REVIEW_VERSION}`;
249
+ const CLI_INPUT_SHAPE_IDS = SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS.map((version) => `domain-control-review.cli-input.v${version}`);
250
+ const CURRENT_CLI_DOCUMENT_SHAPE_ID = `domain-control-review.cli-document.v${CLI_DOMAIN_CONTROL_REVIEW_VERSION}`;
251
+ function reviewFixtureShapeId(schema, version) {
252
+ const cli = schema.startsWith('whoisleuth.cli.');
253
+ return `domain-control-review.${cli ? 'cli-' : ''}${schema.endsWith('-input') ? 'input' : 'document'}.v${version}`;
254
+ }
255
+ const CURRENT_REVIEW_FIXTURE_CONTENT = {
256
+ "domain-control-review-input-v2": {
257
+ "bytes": 1879,
258
+ "sha256": "ac3b5913a44c47bd179cd69e4a8bf4268f10e9f01dd7f59c7d722a8c0d241ad1"
259
+ },
260
+ "domain-control-review-v2": {
261
+ "bytes": 4386,
262
+ "sha256": "e85870d7c978f484a47c807104cab038af2aa30265d05cae1b129ce663e7b9b8"
263
+ },
264
+ "cli-domain-control-review-input-v2": {
265
+ "bytes": 4123,
266
+ "sha256": "ae360c4bcc2f6c3b48b5e9cef524b51ac25f958a88184d6f7efdf26eadfd815f"
267
+ },
268
+ "cli-domain-control-review-v2": {
269
+ "bytes": 9084,
270
+ "sha256": "4befd3e6e81873497a0d56b8337a6540516f36cfdb81d35a26c807875488e309"
271
+ }
272
+ };
236
273
  export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamily({
237
274
  id: 'domain-control-review',
238
275
  owner: 'packages/contracts/domain-control-review.mts',
@@ -283,7 +320,7 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
283
320
  role: 'input',
284
321
  lifecycle: 'current',
285
322
  readable: true,
286
- emitted: true,
323
+ emitted: false,
287
324
  exactKeys: true,
288
325
  extensionPolicy: 'reject',
289
326
  futureVersionBehaviour: 'reject',
@@ -308,7 +345,15 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
308
345
  byteBudget: null,
309
346
  fixtureIds: ['cli-domain-control-review-v1'],
310
347
  },
311
- ],
348
+ ].flatMap((contract) => {
349
+ const versions = contract.schema.startsWith('whoisleuth.cli.') ? SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS : SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS;
350
+ return versions.map((version) => ({
351
+ ...contract, version,
352
+ lifecycle: version === contract.version ? 'current' : contract.readable ? 'legacy' : 'retired',
353
+ emitted: contract.emitted && version === contract.version,
354
+ fixtureIds: contract.fixtureIds.map((id) => id.replace(/v\d+$/u, `v${version}`)),
355
+ }));
356
+ }),
312
357
  fixtures: [
313
358
  {
314
359
  id: 'domain-control-review-input-v1',
@@ -317,7 +362,7 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
317
362
  sha256: 'ca6e894a67715fa93a872d189fe22a21dc516200f672546de7cc8ffe2df12329',
318
363
  contentDigestSha256: null,
319
364
  schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA,
320
- version: DOMAIN_CONTROL_REVIEW_VERSION,
365
+ version: PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION,
321
366
  role: 'input',
322
367
  expectation: 'normalises_to_current_output',
323
368
  expectedOutputFixtureId: 'domain-control-review-v1',
@@ -330,7 +375,7 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
330
375
  sha256: '1ac47d146aee742dd9e1c2b9755bfd8d59d1104b005bedd21d63f42c68d255ec',
331
376
  contentDigestSha256: null,
332
377
  schema: DOMAIN_CONTROL_REVIEW_SCHEMA,
333
- version: DOMAIN_CONTROL_REVIEW_VERSION,
378
+ version: PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION,
334
379
  role: 'current',
335
380
  expectation: 'accepted_exact',
336
381
  expectedOutputFixtureId: null,
@@ -343,7 +388,7 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
343
388
  sha256: 'b4f2005738bf6d8f12433304f20b503eb3ee47778bef9daa1cf1d4fdddae8621',
344
389
  contentDigestSha256: null,
345
390
  schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA,
346
- version: CLI_DOMAIN_CONTROL_REVIEW_VERSION,
391
+ version: PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION,
347
392
  role: 'input',
348
393
  expectation: 'normalises_to_current_output',
349
394
  expectedOutputFixtureId: 'cli-domain-control-review-v1',
@@ -356,58 +401,67 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
356
401
  sha256: 'd6e24209da9d4e41d2065bab493c035adf117faa5bacc8c8ce30c56c8aef0b93',
357
402
  contentDigestSha256: null,
358
403
  schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA,
359
- version: CLI_DOMAIN_CONTROL_REVIEW_VERSION,
404
+ version: PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION,
360
405
  role: 'current',
361
406
  expectation: 'accepted_exact',
362
407
  expectedOutputFixtureId: null,
363
408
  scope: 'repository',
364
409
  },
365
- ],
410
+ ].flatMap((fixture) => {
411
+ const version = fixture.schema.startsWith('whoisleuth.cli.') ? CLI_DOMAIN_CONTROL_REVIEW_VERSION : DOMAIN_CONTROL_REVIEW_VERSION;
412
+ const id = fixture.id.replace(/v\d+$/u, `v${version}`);
413
+ const content = CURRENT_REVIEW_FIXTURE_CONTENT[id];
414
+ return [
415
+ { ...fixture, shapeId: reviewFixtureShapeId(fixture.schema, fixture.version), role: fixture.role === 'input' ? 'input' : 'historical', expectation: fixture.schema === CLI_DOMAIN_CONTROL_REVIEW_SCHEMA ? 'historical_output_exact' : 'accepted_exact', expectedOutputFixtureId: null },
416
+ { ...fixture, ...content, id, path: `test/fixtures/${id}.json`, version, shapeId: reviewFixtureShapeId(fixture.schema, version), role: fixture.role, expectation: fixture.expectation, expectedOutputFixtureId: fixture.expectedOutputFixtureId?.replace(/v\d+$/u, `v${version}`) ?? null },
417
+ ];
418
+ }),
366
419
  metadata: {
367
- metadataVersion: 2,
368
420
  enforcement: 'declarative_only',
369
421
  shapes: [
370
422
  ...CORE_REVIEW_SHAPES,
371
- {
372
- id: 'domain-control-review.cli-input.v1',
373
- schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA,
374
- versions: [CLI_DOMAIN_CONTROL_REVIEW_VERSION],
375
- objects: [
376
- { path: '$', requiredKeys: CLI_DOMAIN_CONTROL_REVIEW_INPUT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
377
- { path: '$.manifest', requiredKeys: DOMAIN_CONTROL_MANIFEST_ROOT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
378
- { path: '$.manifest.entries[]', requiredKeys: DOMAIN_CONTROL_MANIFEST_ENTRY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
379
- { path: '$.manifest.integrity', requiredKeys: DOMAIN_CONTROL_MANIFEST_INTEGRITY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
380
- ],
381
- fixedArrays: [{ path: '$.manifest.limitations', values: DOMAIN_CONTROL_MANIFEST_LIMITATIONS }],
382
- normalisation: 'input_to_current',
383
- target: { schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA, version: CLI_DOMAIN_CONTROL_REVIEW_VERSION },
384
- },
385
- {
386
- id: 'domain-control-review.cli-document.v1',
387
- schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA,
388
- versions: [CLI_DOMAIN_CONTROL_REVIEW_VERSION],
389
- objects: [
390
- { path: '$', requiredKeys: CLI_DOMAIN_CONTROL_REVIEW_ROOT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
391
- { path: '$.review', requiredKeys: DOMAIN_CONTROL_REVIEW_ROOT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
392
- { path: '$.review.manifest', requiredKeys: DOMAIN_CONTROL_REVIEW_MANIFEST_SUMMARY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
393
- { path: '$.review.counts', requiredKeys: DOMAIN_CONTROL_REVIEW_COUNT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
394
- { path: '$.review.domains[]', requiredKeys: DOMAIN_CONTROL_REVIEW_DOMAIN_KEYS, optionalKeys: [], unknownKeys: 'reject' },
395
- { path: '$.review.domains[].comparisons[]', requiredKeys: DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS, optionalKeys: [], unknownKeys: 'reject' },
396
- { path: '$.observations[]', requiredKeys: CLI_DOMAIN_CONTROL_REVIEW_OBSERVATION_KEYS, optionalKeys: [], unknownKeys: 'reject' },
397
- { path: '$.observations[].fields[]', requiredKeys: CLI_DOMAIN_CONTROL_REVIEW_FIELD_KEYS, optionalKeys: [], unknownKeys: 'reject' },
398
- { path: '$.input', requiredKeys: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SUMMARY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
399
- ],
400
- fixedArrays: [
401
- { path: '$.review.limitations', values: DOMAIN_CONTROL_REVIEW_LIMITATIONS },
402
- { path: '$.limitations', values: CLI_DOMAIN_CONTROL_REVIEW_LIMITATIONS },
403
- ],
404
- normalisation: 'preserve_document',
405
- target: null,
406
- },
407
- ],
423
+ ...SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS.flatMap((version) => [
424
+ {
425
+ id: `domain-control-review.cli-input.v${version}`,
426
+ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA,
427
+ versions: [version],
428
+ objects: [
429
+ { path: '$', requiredKeys: CLI_DOMAIN_CONTROL_REVIEW_INPUT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
430
+ { path: '$.manifest', requiredKeys: DOMAIN_CONTROL_MANIFEST_ROOT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
431
+ { path: '$.manifest.entries[]', requiredKeys: PUBLIC_DOMAIN_CONTROL_MANIFEST_ENTRY_KEYS, optionalKeys: version === PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION ? [] : ['recordModes'], unknownKeys: 'reject' },
432
+ { path: '$.manifest.integrity', requiredKeys: DOMAIN_CONTROL_MANIFEST_INTEGRITY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
433
+ ],
434
+ fixedArrays: version === PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION ? [{ path: '$.manifest.limitations', values: PUBLIC_DOMAIN_CONTROL_MANIFEST_LIMITATIONS }] : [],
435
+ normalisation: 'input_to_current',
436
+ target: { schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA, version: CLI_DOMAIN_CONTROL_REVIEW_VERSION },
437
+ },
438
+ {
439
+ id: `domain-control-review.cli-document.v${version}`,
440
+ schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA,
441
+ versions: [version],
442
+ objects: [
443
+ { path: '$', requiredKeys: CLI_DOMAIN_CONTROL_REVIEW_ROOT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
444
+ { path: '$.review', requiredKeys: DOMAIN_CONTROL_REVIEW_ROOT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
445
+ { path: '$.review.manifest', requiredKeys: DOMAIN_CONTROL_REVIEW_MANIFEST_SUMMARY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
446
+ { path: '$.review.counts', requiredKeys: version === PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION ? PUBLIC_DOMAIN_CONTROL_REVIEW_COUNT_KEYS : DOMAIN_CONTROL_REVIEW_COUNT_KEYS, optionalKeys: [], unknownKeys: 'reject' },
447
+ { path: '$.review.domains[]', requiredKeys: DOMAIN_CONTROL_REVIEW_DOMAIN_KEYS, optionalKeys: [], unknownKeys: 'reject' },
448
+ { path: '$.review.domains[].comparisons[]', requiredKeys: version === PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION ? PUBLIC_DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS : DOMAIN_CONTROL_REVIEW_COMPARISON_KEYS, optionalKeys: [], unknownKeys: 'reject' },
449
+ { path: '$.observations[]', requiredKeys: version === PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION ? PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_OBSERVATION_KEYS : CLI_DOMAIN_CONTROL_REVIEW_OBSERVATION_KEYS, optionalKeys: [], unknownKeys: 'reject' },
450
+ { path: '$.observations[].fields[]', requiredKeys: version === PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION ? PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_FIELD_KEYS : CLI_DOMAIN_CONTROL_REVIEW_FIELD_KEYS, optionalKeys: [], unknownKeys: 'reject' },
451
+ { path: '$.input', requiredKeys: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SUMMARY_KEYS, optionalKeys: [], unknownKeys: 'reject' },
452
+ ],
453
+ fixedArrays: [
454
+ { path: '$.review.limitations', values: version === PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION ? PUBLIC_DOMAIN_CONTROL_REVIEW_LIMITATIONS : DOMAIN_CONTROL_REVIEW_LIMITATIONS },
455
+ { path: '$.limitations', values: version === PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_VERSION ? PUBLIC_CLI_DOMAIN_CONTROL_REVIEW_LIMITATIONS : CLI_DOMAIN_CONTROL_REVIEW_LIMITATIONS },
456
+ ],
457
+ normalisation: 'preserve_document',
458
+ target: null,
459
+ },
460
+ ]),
461
+ ].map((shape) => ({ ...shape, discriminator: null, objects: shape.objects.map((object) => ({ ...object, alternativeRequiredKeys: [] })) })),
408
462
  boundProfiles: [
409
- {
410
- id: 'domain-control-review.core.v1',
463
+ ...SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS.map((version) => ({
464
+ id: `domain-control-review.core.v${version}`,
411
465
  bounds: [
412
466
  { id: 'observations', path: '$.observations', phase: 'pre_accumulation', unit: 'items', minimum: 0, maximum: MAX_DOMAIN_CONTROL_REVIEW_OBSERVATIONS, handling: 'reject' },
413
467
  { id: 'observation-fields', path: '$.observations[].fields', phase: 'pre_accumulation', unit: 'keys', minimum: 0, maximum: MAX_DOMAIN_CONTROL_REVIEW_FIELDS, handling: 'reject' },
@@ -415,7 +469,7 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
415
469
  const boundId = field.replace(/([A-Z])/gu, '-$1').toLowerCase();
416
470
  return [
417
471
  { id: `${boundId}-input-values`, path: `$.observations[].fields.${field}.values`, phase: 'pre_accumulation', unit: 'items', minimum: 0, maximum: MAX_DOMAIN_CONTROL_REVIEW_FIELD_INPUT_VALUES, handling: 'reject' },
418
- { id: `${boundId}-values`, path: `$.observations[].fields.${field}.values`, phase: 'normalised', unit: 'items', minimum: 0, maximum: MAX_CANONICAL_DOMAIN_CONTROL_RECORDS, handling: 'truncate' },
472
+ { id: `${boundId}-values`, path: `$.observations[].fields.${field}.values`, phase: 'normalised', unit: 'items', minimum: 0, maximum: version === PUBLIC_DOMAIN_CONTROL_REVIEW_VERSION ? MAX_CANONICAL_DOMAIN_CONTROL_RECORDS : MAX_CURRENT_DOMAIN_CONTROL_RECORDS, handling: 'reject' },
419
473
  { id: `${boundId}-source-input`, path: `$.observations[].fields.${field}.source`, phase: 'pre_accumulation', unit: 'characters', minimum: 1, maximum: MAX_DOMAIN_CONTROL_REVIEW_SOURCE_INPUT_LENGTH, handling: 'reject' },
420
474
  { id: `${boundId}-source`, path: `$.observations[].fields.${field}.source`, phase: 'normalised', unit: 'characters', minimum: 1, maximum: MAX_DOMAIN_CONTROL_REVIEW_SOURCE_LENGTH, handling: 'truncate' },
421
475
  { id: `${boundId}-observed-at-input`, path: `$.observations[].fields.${field}.observedAt`, phase: 'pre_accumulation', unit: 'characters', minimum: 0, maximum: MAX_DOMAIN_CONTROL_TIMESTAMP_LENGTH * DOMAIN_CONTROL_TEXT_INPUT_BOUND_FACTOR, handling: 'reject' },
@@ -430,7 +484,7 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
430
484
  { id: 'tls-spki-text', path: '$.observations[].fields.tlsSpkiSha256.values[]', phase: 'normalised', unit: 'characters', minimum: DOMAIN_CONTROL_SPKI_SHA256_HEX_LENGTH, maximum: DOMAIN_CONTROL_SPKI_SHA256_HEX_LENGTH, handling: 'reject' },
431
485
  { id: 'output-domains', path: '$.domains', phase: 'normalised', unit: 'entries', minimum: 1, maximum: MAX_DOMAIN_CONTROL_MANIFEST_ENTRIES, handling: 'reject' },
432
486
  ],
433
- },
487
+ })),
434
488
  {
435
489
  id: 'domain-control-review.cli-library.v1',
436
490
  bounds: [
@@ -471,7 +525,7 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
471
525
  {
472
526
  id: 'domain-control-review.core-json.v1',
473
527
  schema: DOMAIN_CONTROL_REVIEW_SCHEMA,
474
- versions: [DOMAIN_CONTROL_REVIEW_VERSION],
528
+ versions: SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS,
475
529
  mediaType: 'application/json',
476
530
  encoding: 'utf-8',
477
531
  bom: false,
@@ -486,7 +540,7 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
486
540
  {
487
541
  id: 'domain-control-review.cli-json.v1',
488
542
  schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA,
489
- versions: [CLI_DOMAIN_CONTROL_REVIEW_VERSION],
543
+ versions: SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS,
490
544
  mediaType: 'application/json',
491
545
  encoding: 'utf-8',
492
546
  bom: false,
@@ -583,10 +637,10 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
583
637
  id: 'domain-control-review.node-core',
584
638
  plane: 'node',
585
639
  operation: 'review',
586
- acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: [DOMAIN_CONTROL_REVIEW_VERSION], mode: 'direct' }],
640
+ acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'direct' }],
587
641
  emittedContract: { schema: DOMAIN_CONTROL_REVIEW_SCHEMA, version: DOMAIN_CONTROL_REVIEW_VERSION },
588
- shapeIds: ['domain-control-review.input.v1', 'domain-control-review.document.v1'],
589
- boundProfileIds: ['domain-control-review.core.v1'],
642
+ shapeIds: [...CORE_INPUT_SHAPE_IDS, CURRENT_CORE_DOCUMENT_SHAPE_ID],
643
+ boundProfileIds: [...CORE_BOUND_PROFILE_IDS],
590
644
  hookIds: ['domain-control-review.node.verify-manifest', 'domain-control-review.node.build-core'],
591
645
  serialisationProfileId: null,
592
646
  privacyProfileId: 'domain-control-review.sensitive.v1',
@@ -600,10 +654,10 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
600
654
  id: 'domain-control-review.cli-core-json-stdout',
601
655
  plane: 'cli',
602
656
  operation: 'review-json-stdout',
603
- acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: [DOMAIN_CONTROL_REVIEW_VERSION], mode: 'direct' }],
657
+ acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'direct' }],
604
658
  emittedContract: { schema: DOMAIN_CONTROL_REVIEW_SCHEMA, version: DOMAIN_CONTROL_REVIEW_VERSION },
605
- shapeIds: ['domain-control-review.input.v1', 'domain-control-review.document.v1'],
606
- boundProfileIds: ['domain-control-review.core.v1', 'domain-control-review.cli-command.v1'],
659
+ shapeIds: [...CORE_INPUT_SHAPE_IDS, CURRENT_CORE_DOCUMENT_SHAPE_ID],
660
+ boundProfileIds: [...CORE_BOUND_PROFILE_IDS, 'domain-control-review.cli-command.v1'],
607
661
  hookIds: [
608
662
  'domain-control-review.node.verify-manifest',
609
663
  'domain-control-review.node.build-core',
@@ -621,10 +675,10 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
621
675
  id: 'domain-control-review.cli-core-terminal-stdout',
622
676
  plane: 'cli',
623
677
  operation: 'review-terminal-stdout',
624
- acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: [DOMAIN_CONTROL_REVIEW_VERSION], mode: 'direct' }],
678
+ acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'direct' }],
625
679
  emittedContract: { schema: DOMAIN_CONTROL_REVIEW_SCHEMA, version: DOMAIN_CONTROL_REVIEW_VERSION },
626
- shapeIds: ['domain-control-review.input.v1', 'domain-control-review.document.v1'],
627
- boundProfileIds: ['domain-control-review.core.v1', 'domain-control-review.cli-command.v1'],
680
+ shapeIds: [...CORE_INPUT_SHAPE_IDS, CURRENT_CORE_DOCUMENT_SHAPE_ID],
681
+ boundProfileIds: [...CORE_BOUND_PROFILE_IDS, 'domain-control-review.cli-command.v1'],
628
682
  hookIds: [
629
683
  'domain-control-review.node.verify-manifest',
630
684
  'domain-control-review.node.build-core',
@@ -642,10 +696,10 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
642
696
  id: 'domain-control-review.cli-core-json-file',
643
697
  plane: 'cli',
644
698
  operation: 'review-json-file',
645
- acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: [DOMAIN_CONTROL_REVIEW_VERSION], mode: 'direct' }],
699
+ acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'direct' }],
646
700
  emittedContract: { schema: DOMAIN_CONTROL_REVIEW_SCHEMA, version: DOMAIN_CONTROL_REVIEW_VERSION },
647
- shapeIds: ['domain-control-review.input.v1', 'domain-control-review.document.v1'],
648
- boundProfileIds: ['domain-control-review.core.v1', 'domain-control-review.cli-command.v1'],
701
+ shapeIds: [...CORE_INPUT_SHAPE_IDS, CURRENT_CORE_DOCUMENT_SHAPE_ID],
702
+ boundProfileIds: [...CORE_BOUND_PROFILE_IDS, 'domain-control-review.cli-command.v1'],
649
703
  hookIds: [
650
704
  'domain-control-review.node.verify-manifest',
651
705
  'domain-control-review.node.build-core',
@@ -663,10 +717,10 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
663
717
  id: 'domain-control-review.cli-core-terminal-file',
664
718
  plane: 'cli',
665
719
  operation: 'review-terminal-file',
666
- acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: [DOMAIN_CONTROL_REVIEW_VERSION], mode: 'direct' }],
720
+ acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'direct' }],
667
721
  emittedContract: { schema: DOMAIN_CONTROL_REVIEW_SCHEMA, version: DOMAIN_CONTROL_REVIEW_VERSION },
668
- shapeIds: ['domain-control-review.input.v1', 'domain-control-review.document.v1'],
669
- boundProfileIds: ['domain-control-review.core.v1', 'domain-control-review.cli-command.v1'],
722
+ shapeIds: [...CORE_INPUT_SHAPE_IDS, CURRENT_CORE_DOCUMENT_SHAPE_ID],
723
+ boundProfileIds: [...CORE_BOUND_PROFILE_IDS, 'domain-control-review.cli-command.v1'],
670
724
  hookIds: [
671
725
  'domain-control-review.node.verify-manifest',
672
726
  'domain-control-review.node.build-core',
@@ -684,10 +738,10 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
684
738
  id: 'domain-control-review.cli-saved-lookup-library',
685
739
  plane: 'cli',
686
740
  operation: 'review',
687
- acceptedContracts: [{ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: [CLI_DOMAIN_CONTROL_REVIEW_VERSION], mode: 'direct' }],
741
+ acceptedContracts: [{ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'direct' }],
688
742
  emittedContract: { schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA, version: CLI_DOMAIN_CONTROL_REVIEW_VERSION },
689
- shapeIds: ['domain-control-review.cli-input.v1', 'domain-control-review.cli-document.v1'],
690
- boundProfileIds: ['domain-control-review.core.v1', 'domain-control-review.cli-library.v1'],
743
+ shapeIds: [...CLI_INPUT_SHAPE_IDS, CURRENT_CLI_DOCUMENT_SHAPE_ID],
744
+ boundProfileIds: [...CORE_BOUND_PROFILE_IDS, 'domain-control-review.cli-library.v1'],
691
745
  hookIds: [
692
746
  'domain-control-review.node.verify-manifest',
693
747
  'domain-control-review.node.build-core',
@@ -705,11 +759,11 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
705
759
  id: 'domain-control-review.cli-saved-json-stdout',
706
760
  plane: 'cli',
707
761
  operation: 'review-json-stdout',
708
- acceptedContracts: [{ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: [CLI_DOMAIN_CONTROL_REVIEW_VERSION], mode: 'direct' }],
762
+ acceptedContracts: [{ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'direct' }],
709
763
  emittedContract: { schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA, version: CLI_DOMAIN_CONTROL_REVIEW_VERSION },
710
- shapeIds: ['domain-control-review.cli-input.v1', 'domain-control-review.cli-document.v1'],
764
+ shapeIds: [...CLI_INPUT_SHAPE_IDS, CURRENT_CLI_DOCUMENT_SHAPE_ID],
711
765
  boundProfileIds: [
712
- 'domain-control-review.core.v1',
766
+ ...CORE_BOUND_PROFILE_IDS,
713
767
  'domain-control-review.cli-library.v1',
714
768
  'domain-control-review.cli-command.v1',
715
769
  ],
@@ -731,11 +785,11 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
731
785
  id: 'domain-control-review.cli-saved-terminal-stdout',
732
786
  plane: 'cli',
733
787
  operation: 'review-terminal-stdout',
734
- acceptedContracts: [{ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: [CLI_DOMAIN_CONTROL_REVIEW_VERSION], mode: 'direct' }],
788
+ acceptedContracts: [{ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'direct' }],
735
789
  emittedContract: { schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA, version: CLI_DOMAIN_CONTROL_REVIEW_VERSION },
736
- shapeIds: ['domain-control-review.cli-input.v1', 'domain-control-review.cli-document.v1'],
790
+ shapeIds: [...CLI_INPUT_SHAPE_IDS, CURRENT_CLI_DOCUMENT_SHAPE_ID],
737
791
  boundProfileIds: [
738
- 'domain-control-review.core.v1',
792
+ ...CORE_BOUND_PROFILE_IDS,
739
793
  'domain-control-review.cli-library.v1',
740
794
  'domain-control-review.cli-command.v1',
741
795
  ],
@@ -757,11 +811,11 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
757
811
  id: 'domain-control-review.cli-saved-json-file',
758
812
  plane: 'cli',
759
813
  operation: 'review-json-file',
760
- acceptedContracts: [{ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: [CLI_DOMAIN_CONTROL_REVIEW_VERSION], mode: 'direct' }],
814
+ acceptedContracts: [{ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'direct' }],
761
815
  emittedContract: { schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA, version: CLI_DOMAIN_CONTROL_REVIEW_VERSION },
762
- shapeIds: ['domain-control-review.cli-input.v1', 'domain-control-review.cli-document.v1'],
816
+ shapeIds: [...CLI_INPUT_SHAPE_IDS, CURRENT_CLI_DOCUMENT_SHAPE_ID],
763
817
  boundProfileIds: [
764
- 'domain-control-review.core.v1',
818
+ ...CORE_BOUND_PROFILE_IDS,
765
819
  'domain-control-review.cli-library.v1',
766
820
  'domain-control-review.cli-command.v1',
767
821
  ],
@@ -783,11 +837,11 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
783
837
  id: 'domain-control-review.cli-saved-terminal-file',
784
838
  plane: 'cli',
785
839
  operation: 'review-terminal-file',
786
- acceptedContracts: [{ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: [CLI_DOMAIN_CONTROL_REVIEW_VERSION], mode: 'direct' }],
840
+ acceptedContracts: [{ schema: CLI_DOMAIN_CONTROL_REVIEW_INPUT_SCHEMA, versions: SUPPORTED_CLI_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'direct' }],
787
841
  emittedContract: { schema: CLI_DOMAIN_CONTROL_REVIEW_SCHEMA, version: CLI_DOMAIN_CONTROL_REVIEW_VERSION },
788
- shapeIds: ['domain-control-review.cli-input.v1', 'domain-control-review.cli-document.v1'],
842
+ shapeIds: [...CLI_INPUT_SHAPE_IDS, CURRENT_CLI_DOCUMENT_SHAPE_ID],
789
843
  boundProfileIds: [
790
- 'domain-control-review.core.v1',
844
+ ...CORE_BOUND_PROFILE_IDS,
791
845
  'domain-control-review.cli-library.v1',
792
846
  'domain-control-review.cli-command.v1',
793
847
  ],
@@ -809,9 +863,9 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
809
863
  id: 'domain-control-review.cli-monitor-embedding',
810
864
  plane: 'cli',
811
865
  operation: 'embed-review-after-bounded-passive-collection',
812
- acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_SCHEMA, versions: [DOMAIN_CONTROL_REVIEW_VERSION], mode: 'embedded' }],
866
+ acceptedContracts: [{ schema: DOMAIN_CONTROL_REVIEW_SCHEMA, versions: SUPPORTED_DOMAIN_CONTROL_REVIEW_VERSIONS, mode: 'embedded' }],
813
867
  emittedContract: null,
814
- shapeIds: ['domain-control-review.document.v1'],
868
+ shapeIds: CORE_DOCUMENT_SHAPE_IDS,
815
869
  boundProfileIds: ['domain-control-review.monitor-action.v1'],
816
870
  hookIds: ['domain-control-review.node.validate-core', 'domain-control-review.cli.monitor'],
817
871
  serialisationProfileId: null,
@@ -822,7 +876,11 @@ export const DOMAIN_CONTROL_REVIEW_SCHEMA_LIFECYCLE = defineSchemaLifecycleFamil
822
876
  bindingState: 'declared_unenforced',
823
877
  policyState: 'current',
824
878
  },
825
- ],
879
+ ].map((edge) => ({
880
+ ...edge,
881
+ acceptedContracts: edge.acceptedContracts.map((contract) => ({ ...contract, discriminator: null })),
882
+ emittedContract: edge.emittedContract ? { ...edge.emittedContract, discriminator: null } : null,
883
+ })),
826
884
  consumerRelationships: [],
827
885
  },
828
886
  });
@@ -2,3 +2,24 @@
2
2
  // normalisers. These are canonical A-label limits, not raw-input allowances.
3
3
  export const MAX_DOMAIN_NAME_LENGTH = 253;
4
4
  export const MAX_DOMAIN_LABEL_LENGTH = 63;
5
+ const ASCII_LABEL_RE = /^[A-Za-z0-9-]+$/u;
6
+ // Syntax only: public-suffix policy and network-address safety are separate.
7
+ export function isValidAsciiHostname(value, options = {}) {
8
+ if (typeof value !== 'string'
9
+ || value.length < 1
10
+ || value.length > MAX_DOMAIN_NAME_LENGTH
11
+ || (options.requireLowercase === true && value !== value.toLowerCase()))
12
+ return false;
13
+ const labels = value.split('.');
14
+ if (options.requireDot !== false && labels.length < 2)
15
+ return false;
16
+ return labels.every((label) => label.length > 0 && label.length <= MAX_DOMAIN_LABEL_LENGTH
17
+ && !label.startsWith('-') && !label.endsWith('-') && ASCII_LABEL_RE.test(label));
18
+ }
19
+ function isIpv4Literal(value) {
20
+ const parts = value.split('.');
21
+ return parts.length === 4 && parts.every((part) => /^(?:0|[1-9]\d{0,2})$/u.test(part) && Number(part) <= 255);
22
+ }
23
+ export function isValidAsciiDomainName(value, options = {}) {
24
+ return isValidAsciiHostname(value, options) && !isIpv4Literal(value);
25
+ }