@slicedearth/whoisleuth-cli 2.3.0 → 2.5.1

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 (418) hide show
  1. package/NOTICE +8 -2
  2. package/README.md +19 -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/argument-values.mjs +55 -0
  7. package/cli/arguments.mjs +24 -408
  8. package/cli/artifact-validation/case-response.mjs +65 -44
  9. package/cli/artifact-validation/investigation-capsule.mjs +52 -31
  10. package/cli/artifact-validation/lookup-evidence.mjs +15 -9
  11. package/cli/artifact-validation/signed-review.mjs +136 -68
  12. package/cli/artifact-validation/structure-primitives.mjs +1 -105
  13. package/cli/artifact-verify.mjs +92 -24
  14. package/cli/assurance-arguments.mjs +56 -0
  15. package/cli/assurance-command-definitions.mjs +179 -0
  16. package/cli/assurance-command-runner.mjs +40 -5
  17. package/cli/bagit-folder.mjs +57 -0
  18. package/cli/bagit-review.mjs +23 -0
  19. package/cli/bounded-json.mjs +1 -1
  20. package/cli/bulk-checkpoint.mjs +1 -1
  21. package/cli/bulk-command-runner.mjs +4 -2
  22. package/cli/bulk-output.mjs +29 -3
  23. package/cli/bulk.mjs +2 -3
  24. package/cli/case-command.mjs +212 -0
  25. package/cli/case-pack.mjs +50 -32
  26. package/cli/ci-report.mjs +6 -3
  27. package/cli/collection-arguments.mjs +123 -0
  28. package/cli/collection-command-definitions.mjs +330 -0
  29. package/cli/collection-preflight.mjs +8 -1
  30. package/cli/command-argument-grammar.mjs +8 -206
  31. package/cli/command-definition.mjs +329 -0
  32. package/cli/command-reference.mjs +94 -1357
  33. package/cli/command-seeds.mjs +18 -0
  34. package/cli/compare.mjs +1 -1
  35. package/cli/completion.mjs +298 -79
  36. package/cli/config-profile.mjs +8 -6
  37. package/cli/ct-event-intake.mjs +16 -16
  38. package/cli/discover.mjs +5 -4
  39. package/cli/discovery-observation-snapshot.mjs +46 -18
  40. package/cli/discovery-scan-command-runner.mjs +5 -3
  41. package/cli/discovery-scan.mjs +7 -4
  42. package/cli/discovery-snapshot.mjs +2 -2
  43. package/cli/discovery-workflow.mjs +5 -5
  44. package/cli/domain-control-monitor.mjs +50 -20
  45. package/cli/domain-control-observations.mjs +151 -103
  46. package/cli/errors.mjs +37 -6
  47. package/cli/evidence-arguments.mjs +46 -0
  48. package/cli/evidence-command-definitions.mjs +69 -0
  49. package/cli/evidence-command-runner.mjs +18 -8
  50. package/cli/evidence-signing.mjs +5 -4
  51. package/cli/external-observation-mapping.mjs +9 -10
  52. package/cli/formatters/terminal-command-formats.mjs +6 -0
  53. package/cli/formatters/terminal-lookup.mjs +24 -46
  54. package/cli/formatters/terminal-shared.mjs +5 -3
  55. package/cli/formatters/terminal-technology.mjs +114 -0
  56. package/cli/history-arguments.mjs +39 -0
  57. package/cli/history-command-definitions.mjs +88 -0
  58. package/cli/indicator-set-command.mjs +33 -0
  59. package/cli/inline-command-families.mjs +6 -46
  60. package/cli/inline-command-runner.mjs +4 -31
  61. package/cli/input.mjs +2 -2
  62. package/cli/intake-command.mjs +107 -0
  63. package/cli/interactive-launcher.mjs +2 -160
  64. package/cli/interchange-report.mjs +8 -10
  65. package/cli/investigation-artifacts.mjs +176 -0
  66. package/cli/investigation-checkpoint.mjs +10 -0
  67. package/cli/investigation-folder.mjs +114 -0
  68. package/cli/investigation-manifest.mjs +1 -112
  69. package/cli/investigation-package-review.mjs +103 -0
  70. package/cli/investigation-plan.mjs +38 -147
  71. package/cli/investigation-recipes.mjs +177 -0
  72. package/cli/investigation-run.mjs +256 -35
  73. package/cli/local-document-checkpoint.mjs +170 -0
  74. package/cli/local-mmdb-review.mjs +197 -17
  75. package/cli/lookalike-calibration.mjs +1 -1
  76. package/cli/lookup-brief.mjs +2 -2
  77. package/cli/lookup-browser.mjs +5 -12
  78. package/cli/lookup-command-runner.mjs +33 -39
  79. package/cli/lookup-diff.mjs +47 -12
  80. package/cli/lookup-plan.mjs +16 -14
  81. package/cli/lookup-reconcile.mjs +15 -12
  82. package/cli/lookup-timeline.mjs +7 -6
  83. package/cli/mail-header-review.mjs +24 -247
  84. package/cli/mail-review.mjs +75 -21
  85. package/cli/manual.mjs +1 -0
  86. package/cli/network-arguments.mjs +51 -0
  87. package/cli/network-command-definitions.mjs +130 -0
  88. package/cli/network-command-runner.mjs +45 -31
  89. package/cli/offline-evidence-review.mjs +39 -6
  90. package/cli/output-file.mjs +31 -5
  91. package/cli/posture.mjs +1 -1
  92. package/cli/registry-doctor.mjs +3 -1
  93. package/cli/registry-fixture-scaffold.mjs +1 -1
  94. package/cli/registry-support.mjs +1 -1
  95. package/cli/retained-artifact-diff.mjs +10 -9
  96. package/cli/review-arguments.mjs +131 -0
  97. package/cli/review-command-definitions.mjs +273 -0
  98. package/cli/review-command-runner.mjs +104 -149
  99. package/cli/risk-calibration.mjs +8 -8
  100. package/cli/runner.mjs +74 -37
  101. package/cli/saved-lookup.mjs +2 -2
  102. package/cli/selected-input-worker.mjs +63 -0
  103. package/cli/sharing-review.mjs +8 -80
  104. package/cli/signer-trust.mjs +104 -0
  105. package/cli/source-reliability.mjs +75 -84
  106. package/cli/support-arguments.mjs +49 -0
  107. package/cli/support-command-definitions.mjs +209 -0
  108. package/cli/support-command-runner.mjs +2 -2
  109. package/cli/terminal-input.mjs +168 -0
  110. package/cli/workflow-arguments.mjs +86 -0
  111. package/cli/workflow-command-definitions.mjs +78 -0
  112. package/cli/workflow-command-runner.mjs +75 -13
  113. package/docs/cli-reference.md +103 -30
  114. package/docs/cli.md +510 -25
  115. package/docs/contextual-reviews.md +155 -0
  116. package/lib/abort.mjs +4 -1
  117. package/lib/analyst-taxonomy.mjs +2 -40
  118. package/lib/application-version.mjs +1 -1
  119. package/lib/availability.mjs +27 -754
  120. package/lib/bounded-contract-normalizers.mjs +4 -0
  121. package/lib/bounded-file.mjs +3 -1
  122. package/lib/bounded-html-document.mjs +125 -0
  123. package/lib/bounded-json.mjs +2 -290
  124. package/lib/browser-library-profile.mjs +99 -130
  125. package/lib/browser-library-worker.mjs +112 -0
  126. package/lib/candidate-provenance-bounds.mjs +2 -0
  127. package/lib/classify.mjs +1 -1
  128. package/lib/client-behavior-profile.mjs +3 -3
  129. package/lib/ct-query.mjs +2 -27
  130. package/lib/ct-response-bounds.mjs +2 -9
  131. package/lib/ct-search.mjs +89 -46
  132. package/lib/dmarc-discovery.mjs +62 -0
  133. package/lib/dns-convergence-review.mjs +21 -8
  134. package/lib/dns-delegation-health.mjs +36 -22
  135. package/lib/dns-inheritance-review.mjs +207 -0
  136. package/lib/dns-intelligence.mjs +44 -29
  137. package/lib/dns-mx.mjs +1 -1
  138. package/lib/dns-query-coverage.mjs +40 -0
  139. package/lib/dnssec-evidence-validation.mjs +11 -3
  140. package/lib/domain-assurance.mjs +1 -1
  141. package/lib/domain-change-packet.mjs +18 -14
  142. package/lib/domain-change-review.mjs +40 -16
  143. package/lib/domain-control-flight-recorder.mjs +301 -124
  144. package/lib/domain-control-manifest.mjs +126 -58
  145. package/lib/domain-posture-analysis.mjs +41 -11
  146. package/lib/domain-posture-parsers.mjs +88 -6
  147. package/lib/domain-posture.mjs +120 -32
  148. package/lib/domain-registration.mjs +392 -0
  149. package/lib/evidence-export-privacy.mjs +568 -0
  150. package/lib/evidence-export.mjs +12 -593
  151. package/lib/evidence-report.mjs +7 -2
  152. package/lib/external-intelligence-risk.mjs +2 -124
  153. package/lib/favicon.mjs +117 -41
  154. package/lib/generated/cisa-kev-catalog.mjs +50 -4
  155. package/lib/generated/registrar-standing-catalogue.mjs +18 -10
  156. package/lib/generated/retire-browser-catalog.mjs +2742 -1034
  157. package/lib/generated/{unicode-confusables-17.mjs → unicode-confusables.mjs} +33 -33
  158. package/lib/html-signals.mjs +87 -85
  159. package/lib/http-evidence-bounds.mjs +2 -7
  160. package/lib/http-intelligence.mjs +52 -27
  161. package/lib/idn-confusable-policy.mjs +6 -4
  162. package/lib/idn-confusables.mjs +1 -1
  163. package/lib/interchange-fidelity-registry.mjs +10 -0
  164. package/lib/lookup-cache.mjs +34 -11
  165. package/lib/lookup-child-profile-contract.mjs +24 -15
  166. package/lib/lookup-contract-primitives.mjs +1 -1
  167. package/lib/lookup-diagnostics.mjs +2 -1
  168. package/lib/lookup-network-evidence-bounds.mjs +1 -10
  169. package/lib/lookup-progress.mjs +79 -13
  170. package/lib/lookup-response-contract.mjs +1077 -0
  171. package/lib/lookup-response.mjs +11 -24
  172. package/lib/lookup-source-progress.mjs +24 -35
  173. package/lib/lookup.mjs +49 -28
  174. package/lib/observed-network-context.mjs +43 -27
  175. package/lib/opportunity-scoring.mjs +2 -107
  176. package/lib/outbound-identity.mjs +1 -1
  177. package/lib/outbound-request-bounds.mjs +4 -1
  178. package/lib/page-fingerprints.mjs +87 -134
  179. package/lib/page-role-profile.mjs +12 -8
  180. package/lib/perceptual-hash-comparison.mjs +2 -34
  181. package/lib/perceptual-hash.mjs +79 -24
  182. package/lib/portable-generator.mjs +2 -29
  183. package/lib/project-metadata.mjs +2 -8
  184. package/lib/rdap-bootstrap.mjs +72 -22
  185. package/lib/rdap-client.mjs +26 -14
  186. package/lib/rdap-normalization.mjs +33 -18
  187. package/lib/rdap-search-workbench.mjs +1 -1
  188. package/lib/rdap-transport.mjs +47 -20
  189. package/lib/rdap-types.mjs +2 -1
  190. package/lib/rdap.mjs +18 -3
  191. package/lib/registrable-domain.mjs +2 -36
  192. package/lib/registrar-standing-contract.mjs +2 -1
  193. package/lib/registrar-standing.mjs +9 -13
  194. package/lib/registry-capabilities.mjs +7 -3
  195. package/lib/registry-capability-catalogue.mjs +29 -20
  196. package/lib/registry-dates.mjs +2 -190
  197. package/lib/registry-insights.mjs +56 -18
  198. package/lib/response-policy.mjs +86 -48
  199. package/lib/risk-calibration-summary.mjs +2 -338
  200. package/lib/risk-scoring.mjs +2 -345
  201. package/lib/rpki-evidence.mjs +8 -5
  202. package/lib/safe-fetch.mjs +54 -47
  203. package/lib/scoring-evidence-quality.mjs +2 -107
  204. package/lib/security-txt.mjs +10 -7
  205. package/lib/semantic-version.mjs +2 -54
  206. package/lib/service-binding-dns.mjs +35 -0
  207. package/lib/smtp-transport-review.mjs +75 -34
  208. package/lib/sslbl-certificates.generated.mjs +141 -138
  209. package/lib/static-html-analysis.mjs +117 -146
  210. package/lib/structured-data-identity.mjs +2 -1
  211. package/lib/technology-markup.mjs +100 -0
  212. package/lib/threat-intelligence-manifests.mjs +11 -139
  213. package/lib/threat-intelligence-runtime.mjs +24 -52
  214. package/lib/threat-intelligence-targets.mjs +6 -34
  215. package/lib/threat-intelligence-types.mjs +2 -36
  216. package/lib/typosquat-generator.mjs +29 -16
  217. package/lib/urlhaus-intelligence.mjs +8 -3
  218. package/lib/urlscan-intelligence.mjs +1 -1
  219. package/lib/website-enrichment.mjs +388 -0
  220. package/lib/website-security-posture.mjs +30 -6
  221. package/lib/website-technology.mjs +111 -71
  222. package/lib/whois-authority.mjs +55 -5
  223. package/lib/whois-chain.mjs +9 -2
  224. package/lib/whois-common-formats.mjs +5 -5
  225. package/lib/whois-contracts.mjs +2 -1
  226. package/lib/whois-dialects.mjs +2 -2
  227. package/lib/whois-normalization.mjs +3 -1
  228. package/lib/whois-parser-support.mjs +8 -1
  229. package/lib/whois-parser.mjs +5 -3
  230. package/lib/whois-transport.mjs +23 -7
  231. package/package.json +14 -14
  232. package/packages/analysis/analyst-taxonomy.mjs +40 -0
  233. package/packages/analysis/bounded-json.mjs +330 -0
  234. package/packages/analysis/candidate-provenance-bounds.mjs +4 -0
  235. package/packages/analysis/cli-argument-grammar.mjs +216 -0
  236. package/packages/analysis/ct-query.mjs +27 -0
  237. package/packages/analysis/ct-response-bounds.mjs +9 -0
  238. package/packages/analysis/external-intelligence-risk.mjs +124 -0
  239. package/packages/analysis/http-evidence-bounds.mjs +8 -0
  240. package/packages/analysis/lookup-network-evidence-bounds.mjs +10 -0
  241. package/packages/analysis/opportunity-scoring.mjs +107 -0
  242. package/packages/analysis/perceptual-hash-comparison.mjs +34 -0
  243. package/packages/analysis/portable-generator.mjs +29 -0
  244. package/packages/analysis/project-metadata.mjs +8 -0
  245. package/packages/analysis/registrable-domain.mjs +56 -0
  246. package/packages/analysis/risk-calibration-summary.mjs +352 -0
  247. package/packages/analysis/risk-scoring.mjs +345 -0
  248. package/packages/analysis/scoring-evidence-quality.mjs +107 -0
  249. package/packages/analysis/semantic-version.mjs +54 -0
  250. package/packages/analysis/threat-intelligence-types.mjs +75 -0
  251. package/packages/cases/case-attachment-model.mjs +83 -0
  252. package/packages/cases/case-evidence-links.mjs +135 -0
  253. package/packages/cases/case-evidence-model.mjs +229 -69
  254. package/packages/cases/case-evidence-quality.mjs +5 -0
  255. package/packages/cases/case-export-input.mjs +55 -0
  256. package/packages/cases/case-incident-context.mjs +52 -0
  257. package/packages/cases/case-markdown.mjs +11 -0
  258. package/packages/cases/case-migration-model.mjs +98 -48
  259. package/packages/cases/case-model.mjs +1 -0
  260. package/packages/cases/case-recheck-model.mjs +149 -0
  261. package/packages/cases/case-record-contracts.mjs +1 -1
  262. package/packages/cases/case-record-core.mjs +4 -3
  263. package/packages/cases/case-record-operations.mjs +123 -133
  264. package/packages/cases/case-record-projection.mjs +30 -20
  265. package/packages/cases/case-record-version-input.mjs +19 -0
  266. package/packages/cases/case-report.mjs +114 -67
  267. package/packages/cases/case-requested-evidence.mjs +146 -0
  268. package/packages/cases/case-response-actions.mjs +756 -0
  269. package/packages/cases/case-response-model.mjs +49 -1129
  270. package/packages/cases/case-response-outcomes.mjs +338 -0
  271. package/packages/cases/case-response-packet-render.mjs +157 -0
  272. package/packages/cases/case-response-packet-types.mjs +1 -0
  273. package/packages/cases/case-response-packet-vocabulary.mjs +48 -0
  274. package/packages/cases/case-response-packet.mjs +58 -593
  275. package/packages/cases/case-response-records.mjs +93 -0
  276. package/packages/cases/case-response-review-inputs.mjs +382 -0
  277. package/packages/cases/case-response-values.mjs +85 -0
  278. package/packages/cases/case-review-package.mjs +45 -0
  279. package/packages/cases/case-selection.mjs +46 -0
  280. package/packages/cases/case-storage-model.mjs +26 -1
  281. package/packages/cases/case-workflow-metadata.mjs +225 -0
  282. package/packages/cases/case-workflow-migration.mjs +43 -0
  283. package/packages/cases/http-summary.mjs +6 -1
  284. package/packages/cases/response-route-freshness.mjs +16 -0
  285. package/packages/comparison/capture-context.mjs +61 -0
  286. package/packages/comparison/comparison-ledger-bulk.mjs +4 -1
  287. package/packages/comparison/favicon-similarity.mjs +1 -1
  288. package/packages/comparison/page-similarity.mjs +3 -2
  289. package/packages/comparison/relationship-evidence.mjs +103 -14
  290. package/packages/comparison/relationship-provenance.mjs +99 -0
  291. package/packages/contracts/analyst-interchange.mjs +234 -0
  292. package/packages/contracts/analyst-review-state-contract.mjs +11 -0
  293. package/packages/contracts/analyst-review-state.mjs +5 -4
  294. package/packages/contracts/case-portability.mjs +370 -114
  295. package/packages/contracts/case-views-contract.mjs +12 -0
  296. package/packages/contracts/case-views.mjs +26 -0
  297. package/packages/contracts/cli-command-semantics.mjs +3 -0
  298. package/packages/contracts/cli-grammar.mjs +6 -0
  299. package/packages/contracts/cli-lookup-brief.mjs +2 -0
  300. package/packages/contracts/cli-lookup.mjs +0 -1
  301. package/packages/contracts/context-review.mjs +24 -0
  302. package/packages/contracts/document-intake.mjs +11 -0
  303. package/packages/contracts/domain-control-flight-recorder.mjs +98 -44
  304. package/packages/contracts/domain-control-manifest.mjs +128 -74
  305. package/packages/contracts/domain-control-monitor.mjs +59 -45
  306. package/packages/contracts/domain-control-review.mjs +200 -121
  307. package/packages/contracts/domain-name.mjs +21 -0
  308. package/packages/contracts/external-observation-interchange.mjs +2 -1
  309. package/packages/contracts/extracted-domain-lifecycle.mjs +11 -32
  310. package/packages/contracts/har-review.mjs +2 -0
  311. package/packages/contracts/http-url.mjs +2 -0
  312. package/packages/contracts/identity-events.mjs +4 -0
  313. package/packages/contracts/investigation-package-limits.mjs +24 -0
  314. package/packages/contracts/investigation-portability.mjs +56 -27
  315. package/packages/contracts/investigation-run.mjs +18 -0
  316. package/packages/contracts/ip-address.mjs +44 -0
  317. package/packages/contracts/lookup-evidence.mjs +35 -0
  318. package/packages/contracts/mail-authentication.mjs +5 -0
  319. package/packages/contracts/message-intake.mjs +31 -0
  320. package/packages/contracts/offline-comparison.mjs +4 -2
  321. package/packages/contracts/page-fingerprints.mjs +15 -0
  322. package/packages/contracts/passive-mail.mjs +10 -0
  323. package/packages/contracts/risk-calibration.mjs +0 -1
  324. package/packages/contracts/schema-compatibility.mjs +1 -1
  325. package/packages/contracts/schema-lifecycle.mjs +83 -153
  326. package/packages/contracts/selected-file-limits.mjs +6 -0
  327. package/packages/contracts/vulnerability-identifiers.mjs +5 -0
  328. package/packages/contracts/web-capture.mjs +10 -0
  329. package/packages/contracts/workspace-portability.mjs +219 -238
  330. package/packages/evidence/artifact-integrity.mjs +8 -2
  331. package/packages/evidence/artifact-structure.mjs +105 -0
  332. package/packages/evidence/collection-quality.mjs +67 -0
  333. package/packages/evidence/decision-fact.mjs +4 -1
  334. package/packages/evidence/dns-query-outcome.mjs +72 -0
  335. package/packages/evidence/domain-control-runtime.mjs +155 -27
  336. package/packages/evidence/domain-posture-context.mjs +79 -0
  337. package/packages/evidence/email-recipient.mjs +18 -0
  338. package/packages/evidence/image-regions.mjs +56 -0
  339. package/packages/evidence/latest-observations.mjs +28 -0
  340. package/packages/evidence/lookup-target.mjs +108 -0
  341. package/packages/evidence/observation.mjs +18 -1
  342. package/packages/evidence/passphrase-encryption.mjs +44 -0
  343. package/packages/evidence/png-pixels.mjs +117 -0
  344. package/packages/evidence/public-address-policy.mjs +83 -0
  345. package/packages/evidence/record-identity.mjs +72 -0
  346. package/packages/evidence/registry-dates.mjs +190 -0
  347. package/packages/evidence/retained-file.mjs +69 -0
  348. package/packages/evidence/review-age.mjs +14 -0
  349. package/packages/interchange/bagit.mjs +342 -0
  350. package/packages/interchange/bounded-zip-extraction.mjs +278 -0
  351. package/packages/interchange/crc32.mjs +17 -0
  352. package/packages/interchange/defensive-indicator-export.mjs +264 -0
  353. package/packages/interchange/external-findings-import.mjs +93 -61
  354. package/packages/interchange/managed-indicator-export.mjs +35 -0
  355. package/packages/interchange/managed-indicator-set.mjs +210 -0
  356. package/packages/interchange/misp-indicator-export.mjs +93 -0
  357. package/packages/interchange/sharing-policy.mjs +56 -0
  358. package/packages/interchange/stix-indicator-export.mjs +129 -0
  359. package/packages/interchange/web-capture-import.mjs +389 -0
  360. package/packages/investigation/acquisition-decision-packet.mjs +1 -1
  361. package/packages/investigation/bulk-mail-exposure.mjs +9 -14
  362. package/packages/investigation/capture-coverage.mjs +57 -0
  363. package/packages/investigation/connector-provenance-review.mjs +100 -0
  364. package/packages/investigation/context-review.mjs +35 -0
  365. package/packages/investigation/document-intake.mjs +81 -0
  366. package/packages/investigation/docx-intake.mjs +133 -0
  367. package/packages/investigation/domain-history-review.mjs +100 -0
  368. package/packages/investigation/domain-transition-review.mjs +47 -0
  369. package/packages/investigation/evidence-coverage-ledger.mjs +9 -1
  370. package/packages/investigation/har-intake.mjs +68 -0
  371. package/packages/investigation/identity-event-intake.mjs +131 -0
  372. package/packages/investigation/identity-incident-review.mjs +39 -0
  373. package/packages/investigation/incident-sequence-review.mjs +58 -0
  374. package/packages/investigation/intake-report.mjs +19 -0
  375. package/packages/investigation/investigation-bagit.mjs +14 -0
  376. package/packages/investigation/investigation-capsule.mjs +33 -5
  377. package/packages/investigation/investigation-manifest.mjs +200 -0
  378. package/packages/investigation/investigation-package-crypto.mjs +98 -0
  379. package/packages/investigation/investigation-package.mjs +200 -0
  380. package/packages/investigation/link-intake.mjs +179 -0
  381. package/packages/investigation/lookup-asset-graph-inputs.mjs +38 -0
  382. package/packages/investigation/lookup-asset-graph.mjs +161 -141
  383. package/packages/investigation/lookup-claim-readiness.mjs +18 -0
  384. package/packages/investigation/lookup-investigation-brief.mjs +3 -3
  385. package/packages/investigation/lookup-task-guidance.mjs +58 -0
  386. package/packages/investigation/mail-authentication-review.mjs +222 -0
  387. package/packages/investigation/mail-header-identity.mjs +209 -0
  388. package/packages/investigation/message-intake.mjs +195 -0
  389. package/packages/investigation/page-behaviour.mjs +113 -0
  390. package/packages/investigation/pdf-intake.mjs +155 -0
  391. package/packages/investigation/platform-continuity-review.mjs +60 -0
  392. package/packages/investigation/qr-intake.mjs +56 -0
  393. package/packages/investigation/requested-action-hints.mjs +11 -0
  394. package/packages/investigation/selected-input-review.mjs +17 -0
  395. package/packages/investigation/storefront-review.mjs +70 -0
  396. package/packages/monitoring/analyst-review-state.mjs +38 -90
  397. package/packages/workspace/brand-profile-model.mjs +160 -22
  398. package/packages/workspace/bulk-columns.mjs +17 -0
  399. package/packages/workspace/bulk-review-model.mjs +39 -31
  400. package/packages/workspace/bulk-session-model.mjs +112 -27
  401. package/packages/workspace/bulk-sort.mjs +1 -0
  402. package/packages/workspace/campaign-model.mjs +1 -1
  403. package/packages/workspace/case-views.mjs +102 -0
  404. package/packages/workspace/detection-rule-model.mjs +1 -1
  405. package/packages/workspace/hostile-input.mjs +29 -8
  406. package/packages/workspace/investigation-guide.mjs +2 -2
  407. package/packages/workspace/investigation-template-model.mjs +45 -6
  408. package/packages/workspace/page-baseline.mjs +20 -17
  409. package/packages/workspace/relationship-observation-model.mjs +54 -35
  410. package/packages/workspace/shortlist-model.mjs +14 -5
  411. package/packages/workspace/watchlist-history.mjs +30 -14
  412. package/packages/workspace/watchlist-store.mjs +24 -6
  413. package/packages/workspace/website-snapshot-model.mjs +98 -33
  414. package/packages/workspace/workspace-archive-crypto.mjs +41 -61
  415. package/packages/workspace/workspace-archive.mjs +90 -25
  416. package/third-party-notices.txt +577 -17
  417. package/lib/hostname.mjs +0 -38
  418. package/packages/investigation/bulk-review-export.mjs +0 -63
@@ -2,7 +2,16 @@ import { MAX_DOMAIN_NAME_LENGTH } from "./domain-name.mjs";
2
2
  import { defineSchemaCompatibility } from "./schema-compatibility.mjs";
3
3
  import { defineSchemaLifecycleFamily } from "./schema-lifecycle.mjs";
4
4
  export const CASE_CONTRACT_OWNER = 'packages/contracts/case-portability.mts';
5
- export const LATEST_PUBLIC_APPLICATION_VERSION = '2.2.0';
5
+ export const MAX_CASE_OBJECTIVE_LENGTH = 320;
6
+ // These published export names identify a format checkpoint, not the newest
7
+ // application patch. Release verification reads the preceding tag's durable
8
+ // commitments directly. Historical readers use fixed schema epochs below.
9
+ export const LATEST_PUBLIC_APPLICATION_VERSION = '2.4.0';
10
+ export const LATEST_PUBLIC_CASE_SCHEMA_VERSION = 16;
11
+ export const LATEST_PUBLIC_CASE_REPORT_SCHEMA_VERSION = 12;
12
+ export const LATEST_PUBLIC_CASE_RESPONSE_PACKET_VERSION = 10;
13
+ export const LATEST_PUBLIC_CASE_RESPONSE_REVIEW_INPUTS_VERSION = 4;
14
+ export const LATEST_PUBLIC_WORKSPACE_ARCHIVE_VERSION = 9;
6
15
  export const CASE_PORTABILITY_IDENTITY_CONSTANTS = Object.freeze([
7
16
  'LATEST_PUBLIC_APPLICATION_VERSION',
8
17
  'LATEST_PUBLIC_CASE_SCHEMA_VERSION',
@@ -10,9 +19,20 @@ export const CASE_PORTABILITY_IDENTITY_CONSTANTS = Object.freeze([
10
19
  'LATEST_PUBLIC_CASE_RESPONSE_PACKET_VERSION',
11
20
  'LATEST_PUBLIC_CASE_RESPONSE_REVIEW_INPUTS_VERSION',
12
21
  'LATEST_PUBLIC_WORKSPACE_ARCHIVE_VERSION',
22
+ 'PUBLISHED_V2_2_CASE_SCHEMA_VERSION',
23
+ 'PUBLISHED_V2_2_CASE_REPORT_SCHEMA_VERSION',
24
+ 'PUBLISHED_V2_2_CASE_RESPONSE_PACKET_VERSION',
25
+ 'PUBLISHED_V2_2_CASE_RESPONSE_REVIEW_INPUTS_VERSION',
26
+ 'PUBLISHED_V2_2_WORKSPACE_ARCHIVE_VERSION',
27
+ 'PUBLISHED_V2_3_CASE_SCHEMA_VERSION',
28
+ 'PUBLISHED_V2_3_CASE_REPORT_SCHEMA_VERSION',
29
+ 'PUBLISHED_V2_3_CASE_RESPONSE_PACKET_VERSION',
30
+ 'PUBLISHED_V2_3_CASE_RESPONSE_REVIEW_INPUTS_VERSION',
31
+ 'PUBLISHED_V2_3_WORKSPACE_ARCHIVE_VERSION',
13
32
  'CASE_BROWSER_STORE_LIFECYCLE_SCHEMA',
14
33
  'CASE_EXPORT_LIFECYCLE_SCHEMA',
15
34
  'CASE_SCHEMA_VERSION',
35
+ 'INCIDENT_CASE_SCHEMA_VERSION',
16
36
  'CASE_BROWSER_SUPPORTED_VERSIONS',
17
37
  'CASE_IMPORT_VERSIONS',
18
38
  'CASE_REPORT_SCHEMA',
@@ -27,6 +47,8 @@ export const CASE_PORTABILITY_IDENTITY_CONSTANTS = Object.freeze([
27
47
  'SUPPORTED_CASE_RESPONSE_REVIEW_INPUTS_VERSIONS',
28
48
  'CLI_CASE_PACK_SCHEMA',
29
49
  'CLI_CASE_PACK_VERSION',
50
+ 'CLI_CASE_PACK_WRITER_FIXTURE_ID',
51
+ 'CLI_CASE_PACK_INPUT_CASE_VERSIONS',
30
52
  'SUPPORTED_CLI_CASE_PACK_VERSIONS',
31
53
  'CLI_CASE_PACK_CASE_REPORT_EPOCHS',
32
54
  'WORKSPACE_ARCHIVE_SCHEMA',
@@ -42,12 +64,15 @@ export const CASE_PORTABILITY_IDENTITY_CONSTANTS = Object.freeze([
42
64
  'ENCRYPTED_WORKSPACE_ARCHIVE_VERSION',
43
65
  ]);
44
66
  export const CASE_PORTABILITY_BOUND_CONSTANTS = Object.freeze([
67
+ 'MAX_CASE_OBJECTIVE_LENGTH',
45
68
  'MAX_CASES',
46
69
  'MAX_NOTES_PER_CASE',
47
70
  'MAX_NOTE_LENGTH',
48
71
  'MAX_TAGS_PER_CASE',
49
72
  'MAX_CASE_IMPORT_BYTES',
50
73
  'MAX_CASE_STORE_BYTES',
74
+ 'MAX_EDITABLE_CASE_INPUT_BYTES',
75
+ 'MAX_EDITABLE_CASE_OUTPUT_BYTES',
51
76
  'MAX_EVIDENCE_SNAPSHOTS_PER_CASE',
52
77
  'MAX_EVIDENCE_FACTORS',
53
78
  'MAX_EVIDENCE_NAMESERVERS',
@@ -132,48 +157,64 @@ export const CASE_BROWSER_STORE_LIFECYCLE_SCHEMA = 'whoisleuth.browser.case-stor
132
157
  export const CASE_EXPORT_LIFECYCLE_SCHEMA = 'whoisleuth.case-export';
133
158
  export const PUBLIC_CASE_SCHEMA_VERSION = 12;
134
159
  export const PUBLISHED_V2_CASE_SCHEMA_VERSION = 13;
135
- export const LATEST_PUBLIC_CASE_SCHEMA_VERSION = 14;
136
- export const CASE_SCHEMA_VERSION = 15;
160
+ export const PUBLISHED_V2_2_CASE_SCHEMA_VERSION = 14;
161
+ export const PUBLISHED_V2_3_CASE_SCHEMA_VERSION = 15;
162
+ export const INCIDENT_CASE_SCHEMA_VERSION = 16;
163
+ export const EVIDENCE_FOLLOW_UP_CASE_SCHEMA_VERSION = 17;
164
+ export const CASE_SCHEMA_VERSION = EVIDENCE_FOLLOW_UP_CASE_SCHEMA_VERSION;
137
165
  export const CASE_BROWSER_SUPPORTED_VERSIONS = Object.freeze([
138
166
  PUBLIC_CASE_SCHEMA_VERSION,
139
167
  PUBLISHED_V2_CASE_SCHEMA_VERSION,
140
- LATEST_PUBLIC_CASE_SCHEMA_VERSION,
168
+ PUBLISHED_V2_2_CASE_SCHEMA_VERSION,
169
+ PUBLISHED_V2_3_CASE_SCHEMA_VERSION,
170
+ INCIDENT_CASE_SCHEMA_VERSION,
141
171
  CASE_SCHEMA_VERSION,
142
172
  ]);
143
173
  export const CASE_IMPORT_VERSIONS = CASE_BROWSER_SUPPORTED_VERSIONS;
144
174
  export const CASE_REPORT_SCHEMA = 'whoisleuth.case-report';
145
175
  export const PUBLIC_CASE_REPORT_SCHEMA_VERSION = 8;
146
176
  export const PUBLISHED_V2_CASE_REPORT_SCHEMA_VERSION = 9;
147
- export const LATEST_PUBLIC_CASE_REPORT_SCHEMA_VERSION = 10;
148
- export const CASE_REPORT_SCHEMA_VERSION = 11;
177
+ export const PUBLISHED_V2_2_CASE_REPORT_SCHEMA_VERSION = 10;
178
+ export const PUBLISHED_V2_3_CASE_REPORT_SCHEMA_VERSION = 11;
179
+ export const CASE_REPORT_SCHEMA_VERSION = 13;
149
180
  export const CASE_REPORT_OUTPUT_VERSIONS = Object.freeze([
150
181
  PUBLISHED_V2_CASE_REPORT_SCHEMA_VERSION,
182
+ PUBLISHED_V2_2_CASE_REPORT_SCHEMA_VERSION,
183
+ PUBLISHED_V2_3_CASE_REPORT_SCHEMA_VERSION,
151
184
  LATEST_PUBLIC_CASE_REPORT_SCHEMA_VERSION,
152
185
  CASE_REPORT_SCHEMA_VERSION,
153
186
  ]);
154
187
  export const CASE_RESPONSE_PACKET_SCHEMA = 'whoisleuth.case-response-packet';
155
188
  export const PUBLIC_CASE_RESPONSE_PACKET_VERSION = 6;
156
189
  export const PUBLISHED_V2_CASE_RESPONSE_PACKET_VERSION = 7;
157
- export const LATEST_PUBLIC_CASE_RESPONSE_PACKET_VERSION = 8;
158
- export const CASE_RESPONSE_PACKET_VERSION = 9;
190
+ export const PUBLISHED_V2_2_CASE_RESPONSE_PACKET_VERSION = 8;
191
+ export const PUBLISHED_V2_3_CASE_RESPONSE_PACKET_VERSION = 9;
192
+ export const CASE_RESPONSE_PACKET_VERSION = 11;
159
193
  export const CASE_RESPONSE_PACKET_OUTPUT_VERSIONS = Object.freeze([
160
194
  PUBLIC_CASE_RESPONSE_PACKET_VERSION,
161
195
  PUBLISHED_V2_CASE_RESPONSE_PACKET_VERSION,
196
+ PUBLISHED_V2_2_CASE_RESPONSE_PACKET_VERSION,
197
+ PUBLISHED_V2_3_CASE_RESPONSE_PACKET_VERSION,
162
198
  LATEST_PUBLIC_CASE_RESPONSE_PACKET_VERSION,
163
199
  CASE_RESPONSE_PACKET_VERSION,
164
200
  ]);
165
201
  export const SUPPORTED_CASE_RESPONSE_PACKET_VERSIONS = CASE_RESPONSE_PACKET_OUTPUT_VERSIONS;
166
202
  export const CASE_RESPONSE_REVIEW_INPUTS_SCHEMA = 'whoisleuth.case-response-review-inputs';
167
203
  export const PUBLISHED_V2_CASE_RESPONSE_REVIEW_INPUTS_VERSION = 1;
168
- export const LATEST_PUBLIC_CASE_RESPONSE_REVIEW_INPUTS_VERSION = 2;
169
- export const CASE_RESPONSE_REVIEW_INPUTS_VERSION = 3;
204
+ export const PUBLISHED_V2_2_CASE_RESPONSE_REVIEW_INPUTS_VERSION = 2;
205
+ export const PUBLISHED_V2_3_CASE_RESPONSE_REVIEW_INPUTS_VERSION = 3;
206
+ export const CASE_RESPONSE_REVIEW_INPUTS_VERSION = 5;
170
207
  export const SUPPORTED_CASE_RESPONSE_REVIEW_INPUTS_VERSIONS = Object.freeze([
171
208
  PUBLISHED_V2_CASE_RESPONSE_REVIEW_INPUTS_VERSION,
209
+ PUBLISHED_V2_2_CASE_RESPONSE_REVIEW_INPUTS_VERSION,
210
+ PUBLISHED_V2_3_CASE_RESPONSE_REVIEW_INPUTS_VERSION,
172
211
  LATEST_PUBLIC_CASE_RESPONSE_REVIEW_INPUTS_VERSION,
173
212
  CASE_RESPONSE_REVIEW_INPUTS_VERSION,
174
213
  ]);
175
214
  export const CLI_CASE_PACK_SCHEMA = 'whoisleuth.cli.case-pack';
176
215
  export const CLI_CASE_PACK_VERSION = 2;
216
+ export const CLI_CASE_PACK_WRITER_FIXTURE_ID = 'cli-case-pack-v2-case-v17-current';
217
+ export const CLI_CASE_PACK_INPUT_CASE_VERSIONS = Object.freeze(CASE_IMPORT_VERSIONS.filter((version) => version >= PUBLISHED_V2_3_CASE_SCHEMA_VERSION));
177
218
  export const SUPPORTED_CLI_CASE_PACK_VERSIONS = Object.freeze([CLI_CASE_PACK_VERSION]);
178
219
  export const CLI_CASE_PACK_ROOT_KEYS = Object.freeze(['version', 'exportedAt', 'cases', 'packet', 'integrity']);
179
220
  export const CLI_CASE_PACK_PACKET_KEYS = Object.freeze(['schema', 'version', 'audience', 'reviewed', 'reports', 'redactionManifest', 'limitations']);
@@ -189,7 +230,9 @@ export const CLI_CASE_PACK_LIMITATIONS = Object.freeze([
189
230
  export const CLI_CASE_PACK_CASE_REPORT_EPOCHS = Object.freeze([
190
231
  Object.freeze({ caseVersions: Object.freeze([PUBLIC_CASE_SCHEMA_VERSION]), reportVersions: Object.freeze([PUBLIC_CASE_REPORT_SCHEMA_VERSION]) }),
191
232
  Object.freeze({ caseVersions: Object.freeze([PUBLISHED_V2_CASE_SCHEMA_VERSION]), reportVersions: Object.freeze([PUBLISHED_V2_CASE_REPORT_SCHEMA_VERSION]) }),
192
- Object.freeze({ caseVersions: Object.freeze([LATEST_PUBLIC_CASE_SCHEMA_VERSION]), reportVersions: Object.freeze([LATEST_PUBLIC_CASE_REPORT_SCHEMA_VERSION]) }),
233
+ Object.freeze({ caseVersions: Object.freeze([PUBLISHED_V2_2_CASE_SCHEMA_VERSION]), reportVersions: Object.freeze([PUBLISHED_V2_2_CASE_REPORT_SCHEMA_VERSION]) }),
234
+ Object.freeze({ caseVersions: Object.freeze([PUBLISHED_V2_3_CASE_SCHEMA_VERSION]), reportVersions: Object.freeze([PUBLISHED_V2_3_CASE_REPORT_SCHEMA_VERSION]) }),
235
+ Object.freeze({ caseVersions: Object.freeze([INCIDENT_CASE_SCHEMA_VERSION]), reportVersions: Object.freeze([LATEST_PUBLIC_CASE_REPORT_SCHEMA_VERSION]) }),
193
236
  Object.freeze({ caseVersions: Object.freeze([CASE_SCHEMA_VERSION]), reportVersions: Object.freeze([CASE_REPORT_SCHEMA_VERSION]) }),
194
237
  ]);
195
238
  export function caseReportVersionMatchesCase(caseVersion, reportVersion) {
@@ -201,12 +244,14 @@ export function caseReportVersionMatchesCase(caseVersion, reportVersion) {
201
244
  export const WORKSPACE_ARCHIVE_SCHEMA = 'whoisleuth.workspace-archive';
202
245
  export const PUBLIC_WORKSPACE_ARCHIVE_VERSION = 5;
203
246
  export const PUBLISHED_V2_WORKSPACE_ARCHIVE_VERSION = 6;
204
- export const LATEST_PUBLIC_WORKSPACE_ARCHIVE_VERSION = 7;
205
- export const WORKSPACE_ARCHIVE_VERSION = 8;
247
+ export const PUBLISHED_V2_2_WORKSPACE_ARCHIVE_VERSION = 7;
248
+ export const PUBLISHED_V2_3_WORKSPACE_ARCHIVE_VERSION = 8;
249
+ export const WORKSPACE_ARCHIVE_VERSION = 9;
206
250
  export const SUPPORTED_WORKSPACE_ARCHIVE_VERSIONS = Object.freeze([
207
251
  PUBLIC_WORKSPACE_ARCHIVE_VERSION,
208
252
  PUBLISHED_V2_WORKSPACE_ARCHIVE_VERSION,
209
- LATEST_PUBLIC_WORKSPACE_ARCHIVE_VERSION,
253
+ PUBLISHED_V2_2_WORKSPACE_ARCHIVE_VERSION,
254
+ PUBLISHED_V2_3_WORKSPACE_ARCHIVE_VERSION,
210
255
  WORKSPACE_ARCHIVE_VERSION,
211
256
  ]);
212
257
  export function isSupportedWorkspaceArchiveVersion(value) {
@@ -217,9 +262,9 @@ export function isSupportedWorkspaceArchiveVersion(value) {
217
262
  export const WORKSPACE_ARCHIVE_SECTION_IDS = Object.freeze([
218
263
  'cases', 'campaigns', 'brandProfiles', 'watchlists', 'shortlist', 'detectionRules',
219
264
  'relationshipObservations', 'bulkSessions', 'websiteSnapshots', 'investigationTemplates',
220
- 'bulkReview', 'analystReviewState', 'settings',
265
+ 'bulkReview', 'analystReviewState', 'caseViews', 'settings',
221
266
  ]);
222
- export const PUBLIC_WORKSPACE_ARCHIVE_SECTION_IDS = Object.freeze(WORKSPACE_ARCHIVE_SECTION_IDS.filter((id) => id !== 'analystReviewState'));
267
+ export const PUBLIC_WORKSPACE_ARCHIVE_SECTION_IDS = Object.freeze(WORKSPACE_ARCHIVE_SECTION_IDS.filter((id) => id !== 'analystReviewState' && id !== 'caseViews'));
223
268
  export const WORKSPACE_ARCHIVE_CASE_SECTION = Object.freeze({
224
269
  id: 'cases',
225
270
  schema: null,
@@ -258,8 +303,12 @@ export const MAX_NOTE_LENGTH = 2000;
258
303
  export const MAX_TAGS_PER_CASE = 20;
259
304
  export const MAX_TAG_LENGTH = 40;
260
305
  export const MAX_DOMAIN_LENGTH = MAX_DOMAIN_NAME_LENGTH;
261
- export const MAX_CASE_IMPORT_BYTES = 2 * 1024 * 1024;
262
306
  export const MAX_CASE_STORE_BYTES = 4 * 1024 * 1024;
307
+ // Formatting and JSON escaping may enlarge an admitted canonical Case store.
308
+ // Editable files retain the store budget; the envelope adds bounded metadata.
309
+ export const MAX_CASE_IMPORT_BYTES = MAX_CASE_STORE_BYTES * 4;
310
+ export const MAX_EDITABLE_CASE_INPUT_BYTES = MAX_CASE_IMPORT_BYTES;
311
+ export const MAX_EDITABLE_CASE_OUTPUT_BYTES = MAX_CASE_STORE_BYTES + 256;
263
312
  export const MAX_EVIDENCE_SNAPSHOTS_PER_CASE = 25;
264
313
  export const MAX_EVIDENCE_FACTORS = 20;
265
314
  export const MAX_EVIDENCE_NAMESERVERS = 12;
@@ -308,9 +357,9 @@ export const RESPONSE_ROUTE_STALE_AFTER_DAYS = 30;
308
357
  export const MAX_RESPONSE_AUTHORISATION_CLOCK_SKEW_MS = 300_000;
309
358
  export const MAX_CASE_PACK_INPUT_BYTES = 4 * 1024 * 1024;
310
359
  export const MAX_CASE_PACK_CASES = 25;
311
- export const MAX_WORKSPACE_ARCHIVE_BYTES = 10 * 1024 * 1024;
360
+ export const MAX_WORKSPACE_ARCHIVE_BYTES = 32 * 1024 * 1024;
312
361
  export const MAX_WORKSPACE_ARCHIVE_SECTION_BYTES = 5 * 1024 * 1024;
313
- export const MAX_WORKSPACE_ARCHIVE_SECTIONS = 13;
362
+ export const MAX_WORKSPACE_ARCHIVE_SECTIONS = WORKSPACE_ARCHIVE_SECTION_IDS.length;
314
363
  export const WORKSPACE_ARCHIVE_PBKDF2_ITERATIONS = 600_000;
315
364
  export const MIN_WORKSPACE_ARCHIVE_PASSPHRASE_CHARACTERS = 12;
316
365
  export const MAX_WORKSPACE_ARCHIVE_PASSPHRASE_BYTES = 1024;
@@ -320,49 +369,49 @@ export const CASE_BROWSER_COMPATIBILITY = defineSchemaCompatibility({
320
369
  supportedVersions: CASE_BROWSER_SUPPORTED_VERSIONS, acceptsUnversionedLegacy: false,
321
370
  futureVersionBehavior: 'preserve_without_write', migration: 'normalize_to_current',
322
371
  writeSemantics: 'normalized_rewrite', byteBudget: MAX_CASE_STORE_BYTES, owner: CASE_CONTRACT_OWNER,
323
- note: 'Exact Case versions 12 and 13 migrate directly to current version 14; other retired stores are rejected and future stores remain untouched.',
372
+ note: 'Declared supported Case stores migrate to the current writer; retired stores are rejected and future stores remain untouched.',
324
373
  });
325
374
  export const CASE_EXPORT_COMPATIBILITY = defineSchemaCompatibility({
326
375
  id: 'export.cases', kind: 'export', schema: null, currentVersion: CASE_SCHEMA_VERSION,
327
376
  supportedVersions: CASE_IMPORT_VERSIONS, acceptsUnversionedLegacy: false,
328
377
  futureVersionBehavior: 'reject', migration: 'normalize_to_current',
329
378
  writeSemantics: 'non_destructive_merge', byteBudget: MAX_CASE_IMPORT_BYTES, owner: CASE_CONTRACT_OWNER,
330
- note: 'Exact Case versions 12, 13 and 14 merge non-destructively through one bounded reader; other versions fail without mutation.',
379
+ note: 'Declared supported Case exports merge non-destructively through one bounded reader; other versions fail without mutation.',
331
380
  });
332
381
  export const CASE_REPORT_COMPATIBILITY = defineSchemaCompatibility({
333
382
  id: 'export.case-report', kind: 'export', schema: CASE_REPORT_SCHEMA, currentVersion: CASE_REPORT_SCHEMA_VERSION,
334
383
  supportedVersions: CASE_REPORT_OUTPUT_VERSIONS, acceptsUnversionedLegacy: false,
335
384
  futureVersionBehavior: 'reject', migration: 'read_only', writeSemantics: 'read_only',
336
385
  byteBudget: null, owner: CASE_CONTRACT_OWNER,
337
- note: 'Published Case report version 9 and current version 10 are exact readable output contracts; retired and future report versions are unsupported.',
386
+ note: 'Supported Case reports are exact readable output contracts; retired and future report versions are unsupported.',
338
387
  });
339
388
  export const CASE_RESPONSE_PACKET_COMPATIBILITY = defineSchemaCompatibility({
340
389
  id: 'export.case-response-packet', kind: 'export', schema: CASE_RESPONSE_PACKET_SCHEMA,
341
390
  currentVersion: CASE_RESPONSE_PACKET_VERSION, supportedVersions: CASE_RESPONSE_PACKET_OUTPUT_VERSIONS,
342
391
  acceptsUnversionedLegacy: false, futureVersionBehavior: 'reject', migration: 'read_only',
343
392
  writeSemantics: 'read_only', byteBudget: null, owner: CASE_CONTRACT_OWNER,
344
- note: 'Exact packet versions 6, 7, 8 and 9 are verified independently; other versions fail closed.',
393
+ note: 'Declared supported packet versions are verified independently; other versions fail closed.',
345
394
  });
346
395
  export const CASE_RESPONSE_REVIEW_INPUTS_COMPATIBILITY = defineSchemaCompatibility({
347
396
  id: 'derived.case-response-review-inputs', kind: 'derived', schema: CASE_RESPONSE_REVIEW_INPUTS_SCHEMA,
348
397
  currentVersion: CASE_RESPONSE_REVIEW_INPUTS_VERSION, supportedVersions: SUPPORTED_CASE_RESPONSE_REVIEW_INPUTS_VERSIONS,
349
398
  acceptsUnversionedLegacy: false, futureVersionBehavior: 'reject', migration: 'read_only',
350
399
  writeSemantics: 'read_only', byteBudget: null, owner: CASE_CONTRACT_OWNER,
351
- note: 'Exact review-input versions 1, 2 and 3 remain independently readable for response authorisation; extensions and future versions fail closed.',
400
+ note: 'Declared supported review inputs remain independently readable for response authorisation; extensions and future versions fail closed.',
352
401
  });
353
402
  export const CLI_CASE_PACK_COMPATIBILITY = defineSchemaCompatibility({
354
403
  id: 'export.cli-case-pack', kind: 'export', schema: CLI_CASE_PACK_SCHEMA, currentVersion: CLI_CASE_PACK_VERSION,
355
404
  supportedVersions: SUPPORTED_CLI_CASE_PACK_VERSIONS, acceptsUnversionedLegacy: false,
356
405
  futureVersionBehavior: 'reject', migration: 'read_only', writeSemantics: 'read_only',
357
406
  byteBudget: MAX_CASE_IMPORT_BYTES, owner: CASE_CONTRACT_OWNER,
358
- note: 'Case-pack version 2 verifies exact Case/report epochs 12/8, 13/9, 14/10 and 15/11 with deterministic sorted-json-v2 integrity.',
407
+ note: 'Supported Case packs verify the declared exact Case/report epoch pairs with deterministic sorted-json-v2 integrity.',
359
408
  });
360
409
  export const WORKSPACE_ARCHIVE_COMPATIBILITY = defineSchemaCompatibility({
361
410
  id: 'export.workspace-archive', kind: 'export', schema: WORKSPACE_ARCHIVE_SCHEMA,
362
411
  currentVersion: WORKSPACE_ARCHIVE_VERSION, supportedVersions: SUPPORTED_WORKSPACE_ARCHIVE_VERSIONS,
363
412
  acceptsUnversionedLegacy: false, futureVersionBehavior: 'reject', migration: 'normalize_to_current',
364
413
  writeSemantics: 'non_destructive_merge', byteBudget: MAX_WORKSPACE_ARCHIVE_BYTES, owner: CASE_CONTRACT_OWNER,
365
- note: 'Workspace version 8 carries the current Case contract. Exact versions 5, 6 and 7 remain readable; version 5 gains an empty Review Item section without inventing decisions, and future envelopes fail without mutation.',
414
+ note: 'The current workspace carries the current Case contract. Declared historical versions remain readable; version 5 gains an empty Review Item section without inventing decisions, and future envelopes fail without mutation.',
366
415
  });
367
416
  export const WORKSPACE_SETTINGS_COMPATIBILITY = defineSchemaCompatibility({
368
417
  id: 'export.workspace-settings-section', kind: 'export', schema: WORKSPACE_SETTINGS_SCHEMA,
@@ -408,8 +457,8 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
408
457
  version: PUBLIC_CASE_SCHEMA_VERSION,
409
458
  role: 'historical',
410
459
  expectation: 'normalises_to_current_output',
411
- expectedOutputFixtureId: 'browser-case-v15',
412
- shapeId: 'case.browser-store.public',
460
+ expectedOutputFixtureId: 'browser-case-v17',
461
+ shapeId: `case.browser-store.v${PUBLIC_CASE_SCHEMA_VERSION}`,
413
462
  scope: 'repository',
414
463
  }),
415
464
  Object.freeze({
@@ -422,8 +471,8 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
422
471
  version: PUBLISHED_V2_CASE_SCHEMA_VERSION,
423
472
  role: 'historical',
424
473
  expectation: 'normalises_to_current_output',
425
- expectedOutputFixtureId: 'browser-case-v15',
426
- shapeId: 'case.browser-store.v13-v14',
474
+ expectedOutputFixtureId: 'browser-case-v17',
475
+ shapeId: `case.browser-store.v${PUBLISHED_V2_CASE_SCHEMA_VERSION}`,
427
476
  scope: 'repository',
428
477
  }),
429
478
  Object.freeze({
@@ -433,11 +482,11 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
433
482
  sha256: 'ece46f5d27a52a20196678af8236674836f3979c0d45f0ad5751c00677ec8bae',
434
483
  contentDigestSha256: null,
435
484
  schema: CASE_BROWSER_STORE_LIFECYCLE_SCHEMA,
436
- version: LATEST_PUBLIC_CASE_SCHEMA_VERSION,
485
+ version: PUBLISHED_V2_2_CASE_SCHEMA_VERSION,
437
486
  role: 'historical',
438
487
  expectation: 'normalises_to_current_output',
439
- expectedOutputFixtureId: 'browser-case-v15',
440
- shapeId: 'case.browser-store.v13-v14',
488
+ expectedOutputFixtureId: 'browser-case-v17',
489
+ shapeId: `case.browser-store.v${PUBLISHED_V2_2_CASE_SCHEMA_VERSION}`,
441
490
  scope: 'repository',
442
491
  }),
443
492
  Object.freeze({
@@ -447,11 +496,39 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
447
496
  sha256: 'a061116c9052a7f73ca6b5a88870bc58cbb083cf5fe82e942539b3847c12ad88',
448
497
  contentDigestSha256: null,
449
498
  schema: CASE_BROWSER_STORE_LIFECYCLE_SCHEMA,
499
+ version: PUBLISHED_V2_3_CASE_SCHEMA_VERSION,
500
+ role: 'historical',
501
+ expectation: 'normalises_to_current_output',
502
+ expectedOutputFixtureId: 'browser-case-v17',
503
+ shapeId: `case.browser-store.v${PUBLISHED_V2_3_CASE_SCHEMA_VERSION}`,
504
+ scope: 'repository',
505
+ }),
506
+ Object.freeze({
507
+ id: 'browser-case-v16',
508
+ path: 'test/fixtures/case-lifecycle/browser-case-v16.json',
509
+ bytes: 3186,
510
+ sha256: 'e0d9dd7d1da29ca31e1b6ccd0c514c44267d84fe9db2eff0ffce23c51fb04ce4',
511
+ contentDigestSha256: null,
512
+ schema: CASE_BROWSER_STORE_LIFECYCLE_SCHEMA,
513
+ version: INCIDENT_CASE_SCHEMA_VERSION,
514
+ role: 'historical',
515
+ expectation: 'normalises_to_current_output',
516
+ expectedOutputFixtureId: 'browser-case-v17',
517
+ shapeId: `case.browser-store.v${INCIDENT_CASE_SCHEMA_VERSION}`,
518
+ scope: 'repository',
519
+ }),
520
+ Object.freeze({
521
+ id: 'browser-case-v17',
522
+ path: 'test/fixtures/case-lifecycle/browser-case-v17.json',
523
+ bytes: 3312,
524
+ sha256: '8de3bb904b09ec07994d832738b148321902d91c4351763eebdc0cf908bf5429',
525
+ contentDigestSha256: null,
526
+ schema: CASE_BROWSER_STORE_LIFECYCLE_SCHEMA,
450
527
  version: CASE_SCHEMA_VERSION,
451
528
  role: 'current',
452
529
  expectation: 'accepted_exact',
453
530
  expectedOutputFixtureId: null,
454
- shapeId: 'case.browser-store.current',
531
+ shapeId: `case.browser-store.v${CASE_SCHEMA_VERSION}`,
455
532
  scope: 'repository',
456
533
  }),
457
534
  Object.freeze({
@@ -464,8 +541,8 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
464
541
  version: PUBLIC_CASE_SCHEMA_VERSION,
465
542
  role: 'historical',
466
543
  expectation: 'normalises_to_current_output',
467
- expectedOutputFixtureId: 'case-export-v15',
468
- shapeId: 'case.export.public',
544
+ expectedOutputFixtureId: 'case-export-v17',
545
+ shapeId: `case.export.v${PUBLIC_CASE_SCHEMA_VERSION}`,
469
546
  scope: 'repository',
470
547
  }),
471
548
  Object.freeze({
@@ -478,8 +555,8 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
478
555
  version: PUBLISHED_V2_CASE_SCHEMA_VERSION,
479
556
  role: 'historical',
480
557
  expectation: 'normalises_to_current_output',
481
- expectedOutputFixtureId: 'case-export-v15',
482
- shapeId: 'case.export.v13-v14',
558
+ expectedOutputFixtureId: 'case-export-v17',
559
+ shapeId: `case.export.v${PUBLISHED_V2_CASE_SCHEMA_VERSION}`,
483
560
  scope: 'repository',
484
561
  }),
485
562
  Object.freeze({
@@ -489,11 +566,11 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
489
566
  sha256: '50cf1df53c3558852b712844d588d9eb955af858e160969d9a6af613c257feaf',
490
567
  contentDigestSha256: null,
491
568
  schema: CASE_EXPORT_LIFECYCLE_SCHEMA,
492
- version: LATEST_PUBLIC_CASE_SCHEMA_VERSION,
569
+ version: PUBLISHED_V2_2_CASE_SCHEMA_VERSION,
493
570
  role: 'historical',
494
571
  expectation: 'normalises_to_current_output',
495
- expectedOutputFixtureId: 'case-export-v15',
496
- shapeId: 'case.export.v13-v14',
572
+ expectedOutputFixtureId: 'case-export-v17',
573
+ shapeId: `case.export.v${PUBLISHED_V2_2_CASE_SCHEMA_VERSION}`,
497
574
  scope: 'repository',
498
575
  }),
499
576
  Object.freeze({
@@ -503,11 +580,39 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
503
580
  sha256: '26cd852ee202b7a50bd2a64e5d412ab52a38aa7195f81a86b26b222398b406f9',
504
581
  contentDigestSha256: null,
505
582
  schema: CASE_EXPORT_LIFECYCLE_SCHEMA,
583
+ version: PUBLISHED_V2_3_CASE_SCHEMA_VERSION,
584
+ role: 'historical',
585
+ expectation: 'normalises_to_current_output',
586
+ expectedOutputFixtureId: 'case-export-v17',
587
+ shapeId: `case.export.v${PUBLISHED_V2_3_CASE_SCHEMA_VERSION}`,
588
+ scope: 'repository',
589
+ }),
590
+ Object.freeze({
591
+ id: 'case-export-v16',
592
+ path: 'test/fixtures/case-lifecycle/case-export-v16.json',
593
+ bytes: 3230,
594
+ sha256: 'b0c14fd4d391b1067f101d61c1549c28570999c9cebb58aed21e164d7af56ad8',
595
+ contentDigestSha256: null,
596
+ schema: CASE_EXPORT_LIFECYCLE_SCHEMA,
597
+ version: INCIDENT_CASE_SCHEMA_VERSION,
598
+ role: 'historical',
599
+ expectation: 'normalises_to_current_output',
600
+ expectedOutputFixtureId: 'case-export-v17',
601
+ shapeId: `case.export.v${INCIDENT_CASE_SCHEMA_VERSION}`,
602
+ scope: 'repository',
603
+ }),
604
+ Object.freeze({
605
+ id: 'case-export-v17',
606
+ path: 'test/fixtures/case-lifecycle/case-export-v17.json',
607
+ bytes: 3356,
608
+ sha256: 'bbce977c1045fd2b5d576619f07c6cc19388d3d192f671f467ab0ad069f01e8b',
609
+ contentDigestSha256: null,
610
+ schema: CASE_EXPORT_LIFECYCLE_SCHEMA,
506
611
  version: CASE_SCHEMA_VERSION,
507
612
  role: 'current',
508
613
  expectation: 'accepted_exact',
509
614
  expectedOutputFixtureId: null,
510
- shapeId: 'case.export.current',
615
+ shapeId: `case.export.v${CASE_SCHEMA_VERSION}`,
511
616
  scope: 'repository',
512
617
  }),
513
618
  Object.freeze({
@@ -535,7 +640,7 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
535
640
  role: 'historical',
536
641
  expectation: 'accepted_exact',
537
642
  expectedOutputFixtureId: null,
538
- shapeId: 'case.report.v9',
643
+ shapeId: `case.report.v${PUBLISHED_V2_CASE_REPORT_SCHEMA_VERSION}`,
539
644
  scope: 'repository',
540
645
  }),
541
646
  Object.freeze({
@@ -545,11 +650,11 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
545
650
  sha256: '36c8b89bb1b335d923bd5035020ff47f89c88775e14d08af2d2eb2ee2f5cc03a',
546
651
  contentDigestSha256: null,
547
652
  schema: CASE_REPORT_SCHEMA,
548
- version: LATEST_PUBLIC_CASE_REPORT_SCHEMA_VERSION,
653
+ version: PUBLISHED_V2_2_CASE_REPORT_SCHEMA_VERSION,
549
654
  role: 'historical',
550
655
  expectation: 'accepted_exact',
551
656
  expectedOutputFixtureId: null,
552
- shapeId: 'case.report.v10',
657
+ shapeId: `case.report.v${PUBLISHED_V2_2_CASE_REPORT_SCHEMA_VERSION}`,
553
658
  scope: 'repository',
554
659
  }),
555
660
  Object.freeze({
@@ -559,11 +664,39 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
559
664
  sha256: 'bbe57dac61074b7badd094b7ffaabd46d3779c10152563e7a101a2126daf09b6',
560
665
  contentDigestSha256: null,
561
666
  schema: CASE_REPORT_SCHEMA,
667
+ version: PUBLISHED_V2_3_CASE_REPORT_SCHEMA_VERSION,
668
+ role: 'historical',
669
+ expectation: 'accepted_exact',
670
+ expectedOutputFixtureId: null,
671
+ shapeId: `case.report.v${PUBLISHED_V2_3_CASE_REPORT_SCHEMA_VERSION}`,
672
+ scope: 'repository',
673
+ }),
674
+ Object.freeze({
675
+ id: 'case-report-v12',
676
+ path: 'test/fixtures/case-lifecycle/case-report-v12.json',
677
+ bytes: 4778,
678
+ sha256: '175b9ab720d95e497eb89a73f437b00c5db9595833b02b033a09bb526a926f36',
679
+ contentDigestSha256: null,
680
+ schema: CASE_REPORT_SCHEMA,
681
+ version: LATEST_PUBLIC_CASE_REPORT_SCHEMA_VERSION,
682
+ role: 'historical',
683
+ expectation: 'accepted_exact',
684
+ expectedOutputFixtureId: null,
685
+ shapeId: `case.report.v${LATEST_PUBLIC_CASE_REPORT_SCHEMA_VERSION}`,
686
+ scope: 'repository',
687
+ }),
688
+ Object.freeze({
689
+ id: 'case-report-v13',
690
+ path: 'test/fixtures/case-lifecycle/case-report-v13.json',
691
+ bytes: 4894,
692
+ sha256: '3b0e69f800a2b7a087a0ffcdf81ebbe4237863f42aea7812fd0d0f6b600b8426',
693
+ contentDigestSha256: null,
694
+ schema: CASE_REPORT_SCHEMA,
562
695
  version: CASE_REPORT_SCHEMA_VERSION,
563
696
  role: 'current',
564
697
  expectation: 'accepted_exact',
565
698
  expectedOutputFixtureId: null,
566
- shapeId: 'case.report.v11',
699
+ shapeId: `case.report.v${CASE_REPORT_SCHEMA_VERSION}`,
567
700
  scope: 'repository',
568
701
  }),
569
702
  Object.freeze({
@@ -587,11 +720,11 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
587
720
  sha256: '7bd2237f208714b92c3669c0581dbf0bc2dc22369e53b3ef9da088e8af0f4a83',
588
721
  contentDigestSha256: 'sha256:86d4d88d1d9fc969e6efa432061c64bf0725767d81c50b8655abd2d231dcc5b6',
589
722
  schema: CASE_RESPONSE_PACKET_SCHEMA,
590
- version: LATEST_PUBLIC_CASE_RESPONSE_PACKET_VERSION,
723
+ version: PUBLISHED_V2_2_CASE_RESPONSE_PACKET_VERSION,
591
724
  role: 'historical',
592
725
  expectation: 'accepted_exact',
593
726
  expectedOutputFixtureId: null,
594
- shapeId: 'case.response-packet.v8',
727
+ shapeId: `case.response-packet.v${PUBLISHED_V2_2_CASE_RESPONSE_PACKET_VERSION}`,
595
728
  scope: 'repository',
596
729
  }),
597
730
  Object.freeze({
@@ -601,11 +734,39 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
601
734
  sha256: '6dbb9b9d2c199ebb0a1f43c3a08aaac98554787b40fed0456eff60ab2f36906c',
602
735
  contentDigestSha256: 'sha256:3500158f08920e43ad16d588b8bfe3b8b92c58370d80468db4330baabeeca497',
603
736
  schema: CASE_RESPONSE_PACKET_SCHEMA,
737
+ version: PUBLISHED_V2_3_CASE_RESPONSE_PACKET_VERSION,
738
+ role: 'historical',
739
+ expectation: 'accepted_exact',
740
+ expectedOutputFixtureId: null,
741
+ shapeId: `case.response-packet.v${PUBLISHED_V2_3_CASE_RESPONSE_PACKET_VERSION}`,
742
+ scope: 'repository',
743
+ }),
744
+ Object.freeze({
745
+ id: 'case-response-packet-v10',
746
+ path: 'test/fixtures/case-lifecycle/case-response-packet-v10.json',
747
+ bytes: 12276,
748
+ sha256: '991475b878f65d9673e60c776162daf921ec5915e16715080ea0534516cff9c4',
749
+ contentDigestSha256: 'sha256:97cfe929ace59edb46ee0b84e6135614aba782e170e730c3de3fb24b82413162',
750
+ schema: CASE_RESPONSE_PACKET_SCHEMA,
751
+ version: LATEST_PUBLIC_CASE_RESPONSE_PACKET_VERSION,
752
+ role: 'historical',
753
+ expectation: 'accepted_exact',
754
+ expectedOutputFixtureId: null,
755
+ shapeId: `case.response-packet.v${LATEST_PUBLIC_CASE_RESPONSE_PACKET_VERSION}`,
756
+ scope: 'repository',
757
+ }),
758
+ Object.freeze({
759
+ id: 'case-response-packet-v11',
760
+ path: 'test/fixtures/case-lifecycle/case-response-packet-v11.json',
761
+ bytes: 12276,
762
+ sha256: '42817b82fbba58930866d9d4f5554732f56c143fd7a64c6e0acab57b66ddfdce',
763
+ contentDigestSha256: "sha256:603558cc7a9112ab759b7dd01f44c53c9408ed6d71db19f562fced2629d5c437",
764
+ schema: CASE_RESPONSE_PACKET_SCHEMA,
604
765
  version: CASE_RESPONSE_PACKET_VERSION,
605
766
  role: 'current',
606
767
  expectation: 'accepted_exact',
607
768
  expectedOutputFixtureId: null,
608
- shapeId: 'case.response-packet.v9',
769
+ shapeId: `case.response-packet.v${CASE_RESPONSE_PACKET_VERSION}`,
609
770
  scope: 'repository',
610
771
  }),
611
772
  Object.freeze({
@@ -629,11 +790,11 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
629
790
  sha256: 'dcc9aaa7cdbd79a33559095f4c212e4eea5ad635c8c36290456d8b1946845aa6',
630
791
  contentDigestSha256: null,
631
792
  schema: CASE_RESPONSE_REVIEW_INPUTS_SCHEMA,
632
- version: LATEST_PUBLIC_CASE_RESPONSE_REVIEW_INPUTS_VERSION,
793
+ version: PUBLISHED_V2_2_CASE_RESPONSE_REVIEW_INPUTS_VERSION,
633
794
  role: 'historical',
634
795
  expectation: 'accepted_exact',
635
796
  expectedOutputFixtureId: null,
636
- shapeId: 'case.response-review-inputs.v2',
797
+ shapeId: `case.response-review-inputs.v${PUBLISHED_V2_2_CASE_RESPONSE_REVIEW_INPUTS_VERSION}`,
637
798
  scope: 'repository',
638
799
  }),
639
800
  Object.freeze({
@@ -643,11 +804,39 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
643
804
  sha256: '13e0711d0a75635825af8cff4a1552efe1be153cc1892c886585f28c25ff03ae',
644
805
  contentDigestSha256: null,
645
806
  schema: CASE_RESPONSE_REVIEW_INPUTS_SCHEMA,
807
+ version: PUBLISHED_V2_3_CASE_RESPONSE_REVIEW_INPUTS_VERSION,
808
+ role: 'historical',
809
+ expectation: 'accepted_exact',
810
+ expectedOutputFixtureId: null,
811
+ shapeId: `case.response-review-inputs.v${PUBLISHED_V2_3_CASE_RESPONSE_REVIEW_INPUTS_VERSION}`,
812
+ scope: 'repository',
813
+ }),
814
+ Object.freeze({
815
+ id: 'case-response-review-inputs-v4',
816
+ path: 'test/fixtures/case-lifecycle/case-response-review-inputs-v4.json',
817
+ bytes: 7604,
818
+ sha256: 'b054fc8405663992055ec6c07998fd19ab2f12dcc581b87b42f773b1ab4acec7',
819
+ contentDigestSha256: null,
820
+ schema: CASE_RESPONSE_REVIEW_INPUTS_SCHEMA,
821
+ version: LATEST_PUBLIC_CASE_RESPONSE_REVIEW_INPUTS_VERSION,
822
+ role: 'historical',
823
+ expectation: 'accepted_exact',
824
+ expectedOutputFixtureId: null,
825
+ shapeId: `case.response-review-inputs.v${LATEST_PUBLIC_CASE_RESPONSE_REVIEW_INPUTS_VERSION}`,
826
+ scope: 'repository',
827
+ }),
828
+ Object.freeze({
829
+ id: 'case-response-review-inputs-v5',
830
+ path: 'test/fixtures/case-lifecycle/case-response-review-inputs-v5.json',
831
+ bytes: 7604,
832
+ sha256: '4a54acbc37ee4384c7a2b5c6168d3fffce6757e259d5314da537c8d423c8bee4',
833
+ contentDigestSha256: null,
834
+ schema: CASE_RESPONSE_REVIEW_INPUTS_SCHEMA,
646
835
  version: CASE_RESPONSE_REVIEW_INPUTS_VERSION,
647
836
  role: 'current',
648
837
  expectation: 'accepted_exact',
649
838
  expectedOutputFixtureId: null,
650
- shapeId: 'case.response-review-inputs.v3',
839
+ shapeId: `case.response-review-inputs.v${CASE_RESPONSE_REVIEW_INPUTS_VERSION}`,
651
840
  scope: 'repository',
652
841
  }),
653
842
  Object.freeze({
@@ -706,6 +895,48 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
706
895
  shapeId: 'case.cli-pack.current',
707
896
  scope: 'repository',
708
897
  }),
898
+ Object.freeze({
899
+ id: 'cli-case-pack-v2-case-v15-current',
900
+ path: 'test/fixtures/case-lifecycle/cli-case-pack-v2-case-v15-current.json',
901
+ bytes: 9439,
902
+ sha256: '9ce7303956589ebfb832157823c74e3ec4d3852507e991d0e1b0c542a06dc377',
903
+ contentDigestSha256: 'sha256:5a88d202efd12c522a6001fa579d2fff8196a0d2ab68571c27894040edbdc3d0',
904
+ schema: CLI_CASE_PACK_SCHEMA,
905
+ version: CLI_CASE_PACK_VERSION,
906
+ role: 'current',
907
+ expectation: 'accepted_exact',
908
+ expectedOutputFixtureId: null,
909
+ shapeId: 'case.cli-pack.current',
910
+ scope: 'repository',
911
+ }),
912
+ Object.freeze({
913
+ id: 'cli-case-pack-v2-case-v16-current',
914
+ path: 'test/fixtures/case-lifecycle/cli-case-pack-v2-case-v16-current.json',
915
+ bytes: 9602,
916
+ sha256: '2ac29a7b64b3d8930e92f6ab6b826566061224f281799f9b4b15c0acc98550f0',
917
+ contentDigestSha256: 'sha256:c6e3cfbe171a85e9318a0a6780d54dc4ad3e662113a75f483fd527c2e36e0143',
918
+ schema: CLI_CASE_PACK_SCHEMA,
919
+ version: CLI_CASE_PACK_VERSION,
920
+ role: 'current',
921
+ expectation: 'accepted_exact',
922
+ expectedOutputFixtureId: null,
923
+ shapeId: 'case.cli-pack.current',
924
+ scope: 'repository',
925
+ }),
926
+ Object.freeze({
927
+ id: CLI_CASE_PACK_WRITER_FIXTURE_ID,
928
+ path: `test/fixtures/case-lifecycle/${CLI_CASE_PACK_WRITER_FIXTURE_ID}.json`,
929
+ bytes: 9874,
930
+ sha256: '3b25440521ddcc1e3ea65a0e56907df4fb725e27b91415c8f1afabab1c4f7e58',
931
+ contentDigestSha256: 'sha256:3cbf9f6dcacdc8efdaa55319e5ce7068a5cf2ea116c80e9ff8ccf6d2dc8741c6',
932
+ schema: CLI_CASE_PACK_SCHEMA,
933
+ version: CLI_CASE_PACK_VERSION,
934
+ role: 'current',
935
+ expectation: 'accepted_exact',
936
+ expectedOutputFixtureId: null,
937
+ shapeId: 'case.cli-pack.current',
938
+ scope: 'repository',
939
+ }),
709
940
  Object.freeze({
710
941
  id: 'workspace-archive-v5-public',
711
942
  path: 'test/fixtures/case-lifecycle/workspace-archive-v5-public.json',
@@ -716,7 +947,7 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
716
947
  version: PUBLIC_WORKSPACE_ARCHIVE_VERSION,
717
948
  role: 'historical',
718
949
  expectation: 'normalises_to_current_output',
719
- expectedOutputFixtureId: 'workspace-archive-v8-empty-current',
950
+ expectedOutputFixtureId: `workspace-archive-v${WORKSPACE_ARCHIVE_VERSION}-empty-current`,
720
951
  shapeId: 'case.workspace-archive.v5',
721
952
  scope: 'repository',
722
953
  }),
@@ -730,7 +961,7 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
730
961
  version: PUBLISHED_V2_WORKSPACE_ARCHIVE_VERSION,
731
962
  role: 'historical',
732
963
  expectation: 'normalises_to_current_output',
733
- expectedOutputFixtureId: 'workspace-archive-v8-empty-current',
964
+ expectedOutputFixtureId: `workspace-archive-v${WORKSPACE_ARCHIVE_VERSION}-empty-current`,
734
965
  shapeId: 'case.workspace-archive.v6',
735
966
  scope: 'repository',
736
967
  }),
@@ -741,10 +972,10 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
741
972
  sha256: '892b0d321f42bfb34501019388da682071024af452a8263f138cc08221947f0a',
742
973
  contentDigestSha256: null,
743
974
  schema: WORKSPACE_ARCHIVE_SCHEMA,
744
- version: LATEST_PUBLIC_WORKSPACE_ARCHIVE_VERSION,
975
+ version: PUBLISHED_V2_2_WORKSPACE_ARCHIVE_VERSION,
745
976
  role: 'historical',
746
977
  expectation: 'normalises_to_current_output',
747
- expectedOutputFixtureId: 'workspace-archive-v8-empty-current',
978
+ expectedOutputFixtureId: `workspace-archive-v${WORKSPACE_ARCHIVE_VERSION}-empty-current`,
748
979
  shapeId: 'case.workspace-archive.v7',
749
980
  scope: 'repository',
750
981
  }),
@@ -755,11 +986,25 @@ const CASE_LIFECYCLE_FIXTURES = Object.freeze([
755
986
  sha256: '747062e2dbbcf96724b19718d36bf0dc50b08e96d8adb670115d2315032b6c05',
756
987
  contentDigestSha256: null,
757
988
  schema: WORKSPACE_ARCHIVE_SCHEMA,
989
+ version: PUBLISHED_V2_3_WORKSPACE_ARCHIVE_VERSION,
990
+ role: 'historical',
991
+ expectation: 'normalises_to_current_output',
992
+ expectedOutputFixtureId: `workspace-archive-v${WORKSPACE_ARCHIVE_VERSION}-empty-current`,
993
+ shapeId: 'case.workspace-archive.v8',
994
+ scope: 'repository',
995
+ }),
996
+ Object.freeze({
997
+ id: 'workspace-archive-v9-empty-current',
998
+ path: 'test/fixtures/case-lifecycle/workspace-archive-v9-empty-current.json',
999
+ bytes: 7613,
1000
+ sha256: '6786a9a892bdc21814b0f1165cd9286fb82258862a4c15140daf9caae71daff0',
1001
+ contentDigestSha256: null,
1002
+ schema: WORKSPACE_ARCHIVE_SCHEMA,
758
1003
  version: WORKSPACE_ARCHIVE_VERSION,
759
1004
  role: 'current',
760
1005
  expectation: 'accepted_exact',
761
1006
  expectedOutputFixtureId: null,
762
- shapeId: 'case.workspace-archive.v8',
1007
+ shapeId: `case.workspace-archive.v${WORKSPACE_ARCHIVE_VERSION}`,
763
1008
  scope: 'repository',
764
1009
  }),
765
1010
  Object.freeze({
@@ -859,20 +1104,14 @@ function shape(id, schema, versions, requiredKeys, normalisation, target = null)
859
1104
  };
860
1105
  }
861
1106
  const CASE_LIFECYCLE_SHAPES = Object.freeze([
862
- shape('case.browser-store.public', CASE_BROWSER_STORE_LIFECYCLE_SCHEMA, [PUBLIC_CASE_SCHEMA_VERSION], ['version', 'cases'], 'project_known_fields'),
863
- shape('case.browser-store.v13-v14', CASE_BROWSER_STORE_LIFECYCLE_SCHEMA, [PUBLISHED_V2_CASE_SCHEMA_VERSION, LATEST_PUBLIC_CASE_SCHEMA_VERSION], ['version', 'cases'], 'project_known_fields'),
864
- shape('case.browser-store.current', CASE_BROWSER_STORE_LIFECYCLE_SCHEMA, [CASE_SCHEMA_VERSION], ['version', 'cases'], 'project_known_fields'),
865
- shape('case.export.v13-v14', CASE_EXPORT_LIFECYCLE_SCHEMA, [PUBLISHED_V2_CASE_SCHEMA_VERSION, LATEST_PUBLIC_CASE_SCHEMA_VERSION], ['version', 'cases'], 'preserve_document'),
866
- shape('case.export.public', CASE_EXPORT_LIFECYCLE_SCHEMA, [PUBLIC_CASE_SCHEMA_VERSION], ['version', 'cases'], 'preserve_document'),
1107
+ ...CASE_BROWSER_SUPPORTED_VERSIONS.map((version) => shape(`case.browser-store.v${version}`, CASE_BROWSER_STORE_LIFECYCLE_SCHEMA, [version], ['version', 'cases'], 'project_known_fields')),
1108
+ ...CASE_IMPORT_VERSIONS.map((version) => shape(`case.export.v${version}`, CASE_EXPORT_LIFECYCLE_SCHEMA, [version], ['version', 'cases'], 'preserve_document')),
867
1109
  shape('case.response-packet.v6', CASE_RESPONSE_PACKET_SCHEMA, [PUBLIC_CASE_RESPONSE_PACKET_VERSION], [
868
1110
  'schema', 'schemaVersion', 'generatedAt', 'reviewRequired', 'submissionPerformed',
869
1111
  'profile', 'case', 'incident', 'contacts', 'preflight', 'escalationHistory',
870
1112
  'provenance', 'integrity',
871
1113
  ], 'preserve_signed_document'),
872
- shape('case.export.current', CASE_EXPORT_LIFECYCLE_SCHEMA, [CASE_SCHEMA_VERSION], ['version', 'cases'], 'preserve_document'),
873
- shape('case.report.v9', CASE_REPORT_SCHEMA, [PUBLISHED_V2_CASE_REPORT_SCHEMA_VERSION], ['schema', 'schemaVersion', 'generatedAt', 'application', 'case', 'currentAssessment', 'evidenceTimeline', 'analystResponse', 'responseLifecycle', 'limitations'], 'preserve_document'),
874
- shape('case.report.v10', CASE_REPORT_SCHEMA, [LATEST_PUBLIC_CASE_REPORT_SCHEMA_VERSION], ['schema', 'schemaVersion', 'generatedAt', 'application', 'case', 'currentAssessment', 'evidenceTimeline', 'analystResponse', 'responseLifecycle', 'limitations'], 'preserve_document'),
875
- shape('case.report.v11', CASE_REPORT_SCHEMA, [CASE_REPORT_SCHEMA_VERSION], ['schema', 'schemaVersion', 'generatedAt', 'application', 'case', 'currentAssessment', 'evidenceTimeline', 'analystResponse', 'responseLifecycle', 'limitations'], 'preserve_document'),
1114
+ ...CASE_REPORT_OUTPUT_VERSIONS.map((version) => shape(`case.report.v${version}`, CASE_REPORT_SCHEMA, [version], ['schema', 'schemaVersion', 'generatedAt', 'application', 'case', 'currentAssessment', 'evidenceTimeline', 'analystResponse', 'responseLifecycle', 'limitations'], 'preserve_document')),
876
1115
  shape('case.response-packet.v7', CASE_RESPONSE_PACKET_SCHEMA, [PUBLISHED_V2_CASE_RESPONSE_PACKET_VERSION], [
877
1116
  'schema', 'schemaVersion', 'generatedAt', 'reviewRequired', 'submissionPerformed',
878
1117
  'profile', 'case', 'incident', 'contacts', 'provenance', 'selectedEvidence',
@@ -880,42 +1119,26 @@ const CASE_LIFECYCLE_SHAPES = Object.freeze([
880
1119
  'escalationHistoryOmitted', 'escalationHistoryLimitations', 'responseLifecycle',
881
1120
  'authorisation', 'integrity',
882
1121
  ], 'preserve_signed_document'),
883
- shape('case.response-packet.v8', CASE_RESPONSE_PACKET_SCHEMA, [LATEST_PUBLIC_CASE_RESPONSE_PACKET_VERSION], [
884
- 'schema', 'schemaVersion', 'generatedAt', 'reviewRequired', 'submissionPerformed',
885
- 'profile', 'case', 'incident', 'contacts', 'recipientRoute', 'actionBinding',
886
- 'provenance', 'selectedEvidence', 'contradictions', 'readiness', 'artefactReferences',
887
- 'preflight', 'escalationHistory', 'escalationHistoryOmitted',
888
- 'escalationHistoryLimitations', 'responseLifecycle', 'authorisation', 'integrity',
889
- ], 'preserve_signed_document'),
890
- shape('case.response-packet.v9', CASE_RESPONSE_PACKET_SCHEMA, [CASE_RESPONSE_PACKET_VERSION], [
1122
+ ...CASE_RESPONSE_PACKET_OUTPUT_VERSIONS.filter((version) => version >= PUBLISHED_V2_2_CASE_RESPONSE_PACKET_VERSION).map((version) => shape(`case.response-packet.v${version}`, CASE_RESPONSE_PACKET_SCHEMA, [version], [
891
1123
  'schema', 'schemaVersion', 'generatedAt', 'reviewRequired', 'submissionPerformed',
892
1124
  'profile', 'case', 'incident', 'contacts', 'recipientRoute', 'actionBinding',
893
1125
  'provenance', 'selectedEvidence', 'contradictions', 'readiness', 'artefactReferences',
894
1126
  'preflight', 'escalationHistory', 'escalationHistoryOmitted',
895
1127
  'escalationHistoryLimitations', 'responseLifecycle', 'authorisation', 'integrity',
896
- ], 'preserve_signed_document'),
1128
+ ], 'preserve_signed_document')),
897
1129
  shape('case.response-review-inputs.v1', CASE_RESPONSE_REVIEW_INPUTS_SCHEMA, [PUBLISHED_V2_CASE_RESPONSE_REVIEW_INPUTS_VERSION], [
898
1130
  'contract', 'version', 'profile', 'case', 'incident', 'contacts', 'selectedEvidence',
899
1131
  'contradictions', 'readiness', 'artefactReferences', 'escalationHistory',
900
1132
  'escalationHistoryOmitted', 'escalationHistoryLimitations', 'responseLifecycle',
901
1133
  ], 'preserve_signed_document'),
902
- shape('case.response-review-inputs.v2', CASE_RESPONSE_REVIEW_INPUTS_SCHEMA, [LATEST_PUBLIC_CASE_RESPONSE_REVIEW_INPUTS_VERSION], [
1134
+ ...SUPPORTED_CASE_RESPONSE_REVIEW_INPUTS_VERSIONS.filter((version) => version >= PUBLISHED_V2_2_CASE_RESPONSE_REVIEW_INPUTS_VERSION).map((version) => shape(`case.response-review-inputs.v${version}`, CASE_RESPONSE_REVIEW_INPUTS_SCHEMA, [version], [
903
1135
  'contract', 'version', 'profile', 'case', 'incident', 'contacts',
904
1136
  'recipientRoute', 'actionBinding', 'selectedEvidence', 'contradictions',
905
1137
  'readiness', 'artefactReferences', 'escalationHistory',
906
1138
  'escalationHistoryOmitted', 'escalationHistoryLimitations', 'responseLifecycle',
907
- ], 'preserve_signed_document'),
908
- shape('case.response-review-inputs.v3', CASE_RESPONSE_REVIEW_INPUTS_SCHEMA, [CASE_RESPONSE_REVIEW_INPUTS_VERSION], [
909
- 'contract', 'version', 'profile', 'case', 'incident', 'contacts',
910
- 'recipientRoute', 'actionBinding', 'selectedEvidence', 'contradictions',
911
- 'readiness', 'artefactReferences', 'escalationHistory',
912
- 'escalationHistoryOmitted', 'escalationHistoryLimitations', 'responseLifecycle',
913
- ], 'preserve_signed_document'),
1139
+ ], 'preserve_signed_document')),
914
1140
  shape('case.cli-pack.current', CLI_CASE_PACK_SCHEMA, [CLI_CASE_PACK_VERSION], CLI_CASE_PACK_ROOT_KEYS, 'preserve_signed_document'),
915
- shape('case.workspace-archive.v5', WORKSPACE_ARCHIVE_SCHEMA, [5], ['schema', 'version', 'generatedAt', 'manifest', 'sections', 'limitations'], 'preserve_signed_document'),
916
- shape('case.workspace-archive.v6', WORKSPACE_ARCHIVE_SCHEMA, [PUBLISHED_V2_WORKSPACE_ARCHIVE_VERSION], ['schema', 'version', 'generatedAt', 'manifest', 'sections', 'limitations'], 'preserve_signed_document'),
917
- shape('case.workspace-archive.v7', WORKSPACE_ARCHIVE_SCHEMA, [LATEST_PUBLIC_WORKSPACE_ARCHIVE_VERSION], ['schema', 'version', 'generatedAt', 'manifest', 'sections', 'limitations'], 'preserve_signed_document'),
918
- shape('case.workspace-archive.v8', WORKSPACE_ARCHIVE_SCHEMA, [WORKSPACE_ARCHIVE_VERSION], ['schema', 'version', 'generatedAt', 'manifest', 'sections', 'limitations'], 'preserve_signed_document'),
1141
+ ...SUPPORTED_WORKSPACE_ARCHIVE_VERSIONS.map(version => shape(`case.workspace-archive.v${version}`, WORKSPACE_ARCHIVE_SCHEMA, [version], ['schema', 'version', 'generatedAt', 'manifest', 'sections', 'limitations'], 'preserve_signed_document')),
919
1142
  shape('case.workspace-settings.v1', WORKSPACE_SETTINGS_SCHEMA, [WORKSPACE_SETTINGS_VERSION], ['schema', 'version', 'activeProfileId', 'theme'], 'preserve_document'),
920
1143
  shape('case.encrypted-workspace-archive.v1', ENCRYPTED_WORKSPACE_ARCHIVE_SCHEMA, [ENCRYPTED_WORKSPACE_ARCHIVE_VERSION], ['schema', 'version', 'createdAt', 'content', 'kdf', 'cipher', 'ciphertext'], 'preserve_signed_document'),
921
1144
  ]);
@@ -997,6 +1220,13 @@ const CASE_LIFECYCLE_HOOKS = Object.freeze([
997
1220
  module: 'packages/cases/case-response-packet.mts',
998
1221
  exportName: 'validateCaseResponseReviewInputs',
999
1222
  },
1223
+ {
1224
+ id: 'case.editable.read',
1225
+ role: 'structure_validator',
1226
+ runtime: 'shared',
1227
+ module: 'packages/cases/case-export-input.mts',
1228
+ exportName: 'readEditableCaseExport',
1229
+ },
1000
1230
  {
1001
1231
  id: 'case.cli-pack.build',
1002
1232
  role: 'builder',
@@ -1062,6 +1292,14 @@ const CASE_LIFECYCLE_BOUNDS = Object.freeze([
1062
1292
  { id: 'serialised-bytes', path: '$', phase: 'serialised', unit: 'bytes', minimum: 1, maximum: MAX_CASE_IMPORT_BYTES, handling: 'reject' },
1063
1293
  ],
1064
1294
  },
1295
+ {
1296
+ id: 'case.editable.bounds',
1297
+ bounds: [
1298
+ { id: 'raw-bytes', path: '$', phase: 'raw_intake', unit: 'bytes', minimum: 1, maximum: MAX_EDITABLE_CASE_INPUT_BYTES, handling: 'reject' },
1299
+ { id: 'canonical-store-bytes', path: '$', phase: 'normalised', unit: 'bytes', minimum: 1, maximum: MAX_CASE_STORE_BYTES, handling: 'reject' },
1300
+ { id: 'output-bytes', path: '$', phase: 'serialised', unit: 'bytes', minimum: 1, maximum: MAX_EDITABLE_CASE_OUTPUT_BYTES, handling: 'reject' },
1301
+ ],
1302
+ },
1065
1303
  {
1066
1304
  id: 'case.domain.bounds',
1067
1305
  bounds: [
@@ -1155,14 +1393,14 @@ const CASE_LIFECYCLE_EXPIRY = Object.freeze([{
1155
1393
  }]);
1156
1394
  const CASE_LIFECYCLE_SERIALISATION = Object.freeze([
1157
1395
  {
1158
- id: 'case.browser-store.json.v15',
1396
+ id: 'case.browser-store.json',
1159
1397
  schema: CASE_BROWSER_STORE_LIFECYCLE_SCHEMA,
1160
1398
  versions: [CASE_SCHEMA_VERSION],
1161
1399
  mediaType: 'application/json',
1162
1400
  encoding: 'utf-8',
1163
1401
  bom: false,
1164
1402
  indentSpaces: 0,
1165
- terminalLf: true,
1403
+ terminalLf: false,
1166
1404
  propertyOrder: 'normalised_fixed',
1167
1405
  canonicalisation: null,
1168
1406
  integrity: 'none',
@@ -1170,10 +1408,10 @@ const CASE_LIFECYCLE_SERIALISATION = Object.freeze([
1170
1408
  verifierHookIds: [],
1171
1409
  },
1172
1410
  ...[
1173
- ['case.export.json.v15', CASE_EXPORT_LIFECYCLE_SCHEMA, [CASE_SCHEMA_VERSION], 'none', []],
1174
- ['case.report.json.v11', CASE_REPORT_SCHEMA, [...CASE_REPORT_OUTPUT_VERSIONS], 'none', []],
1175
- ['case.packet.json.v9', CASE_RESPONSE_PACKET_SCHEMA, [...SUPPORTED_CASE_RESPONSE_PACKET_VERSIONS], 'structural_only_requires_separate_verification', ['case.packet.verify']],
1176
- ['case.workspace.json.v8', WORKSPACE_ARCHIVE_SCHEMA, [WORKSPACE_ARCHIVE_VERSION], 'structural_only_requires_separate_verification', ['case.workspace.verify']],
1411
+ ['case.export.json', CASE_EXPORT_LIFECYCLE_SCHEMA, [CASE_SCHEMA_VERSION], 'none', []],
1412
+ ['case.report.json', CASE_REPORT_SCHEMA, [...CASE_REPORT_OUTPUT_VERSIONS], 'none', []],
1413
+ ['case.packet.json', CASE_RESPONSE_PACKET_SCHEMA, [...SUPPORTED_CASE_RESPONSE_PACKET_VERSIONS], 'structural_only_requires_separate_verification', ['case.packet.verify']],
1414
+ [`case.workspace.json.v${WORKSPACE_ARCHIVE_VERSION}`, WORKSPACE_ARCHIVE_SCHEMA, [WORKSPACE_ARCHIVE_VERSION], 'structural_only_requires_separate_verification', ['case.workspace.verify']],
1177
1415
  ['case.encrypted-workspace.json.v1', ENCRYPTED_WORKSPACE_ARCHIVE_SCHEMA, [ENCRYPTED_WORKSPACE_ARCHIVE_VERSION], 'structural_only_requires_separate_verification', ['case.encrypted-workspace.verify']],
1178
1416
  ].map(([id, schema, versions, integrity, verifierHookIds]) => ({
1179
1417
  id,
@@ -1224,10 +1462,10 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1224
1462
  discriminator: null,
1225
1463
  }],
1226
1464
  emittedContract: { schema: CASE_BROWSER_STORE_LIFECYCLE_SCHEMA, version: CASE_SCHEMA_VERSION, discriminator: null },
1227
- shapeIds: ['case.browser-store.public', 'case.browser-store.v13-v14', 'case.browser-store.current'],
1465
+ shapeIds: CASE_BROWSER_SUPPORTED_VERSIONS.map((version) => `case.browser-store.v${version}`),
1228
1466
  boundProfileIds: ['case.browser-store.bounds', 'case.domain.bounds'],
1229
1467
  hookIds: ['case.browser.normalise', 'case.browser.serialise'],
1230
- serialisationProfileId: 'case.browser-store.json.v15',
1468
+ serialisationProfileId: 'case.browser-store.json',
1231
1469
  privacyProfileId: 'case.privacy.browser-state',
1232
1470
  retentionEffect: 'browser_indexeddb',
1233
1471
  ...sharedEdge,
@@ -1243,7 +1481,7 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1243
1481
  discriminator: null,
1244
1482
  }],
1245
1483
  emittedContract: null,
1246
- shapeIds: ['case.export.public', 'case.export.v13-v14', 'case.export.current'],
1484
+ shapeIds: CASE_IMPORT_VERSIONS.map((version) => `case.export.v${version}`),
1247
1485
  boundProfileIds: ['case.portable.bounds', 'case.domain.bounds'],
1248
1486
  hookIds: ['case.export.merge'],
1249
1487
  serialisationProfileId: null,
@@ -1257,10 +1495,10 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1257
1495
  operation: 'build-portable-export',
1258
1496
  acceptedContracts: [],
1259
1497
  emittedContract: { schema: CASE_EXPORT_LIFECYCLE_SCHEMA, version: CASE_SCHEMA_VERSION, discriminator: null },
1260
- shapeIds: ['case.export.current'],
1498
+ shapeIds: [`case.export.v${CASE_SCHEMA_VERSION}`],
1261
1499
  boundProfileIds: ['case.portable.bounds', 'case.domain.bounds'],
1262
1500
  hookIds: ['case.export.build', 'case.portable.serialise'],
1263
- serialisationProfileId: 'case.export.json.v15',
1501
+ serialisationProfileId: 'case.export.json',
1264
1502
  privacyProfileId: 'case.privacy.portable-output',
1265
1503
  retentionEffect: 'operator_controlled_output',
1266
1504
  ...sharedEdge,
@@ -1276,7 +1514,7 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1276
1514
  discriminator: null,
1277
1515
  }],
1278
1516
  emittedContract: null,
1279
- shapeIds: ['case.report.v9', 'case.report.v10', 'case.report.v11'],
1517
+ shapeIds: CASE_REPORT_OUTPUT_VERSIONS.map((version) => `case.report.v${version}`),
1280
1518
  boundProfileIds: ['case.domain.bounds'],
1281
1519
  hookIds: ['case.cli-pack.verify'],
1282
1520
  serialisationProfileId: null,
@@ -1290,10 +1528,10 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1290
1528
  operation: 'build-report',
1291
1529
  acceptedContracts: [],
1292
1530
  emittedContract: { schema: CASE_REPORT_SCHEMA, version: CASE_REPORT_SCHEMA_VERSION, discriminator: null },
1293
- shapeIds: ['case.report.v11'],
1531
+ shapeIds: [`case.report.v${CASE_REPORT_SCHEMA_VERSION}`],
1294
1532
  boundProfileIds: ['case.domain.bounds'],
1295
1533
  hookIds: ['case.report.build', 'case.portable.serialise'],
1296
- serialisationProfileId: 'case.report.json.v11',
1534
+ serialisationProfileId: 'case.report.json',
1297
1535
  privacyProfileId: 'case.privacy.portable-output',
1298
1536
  retentionEffect: 'operator_controlled_output',
1299
1537
  ...sharedEdge,
@@ -1309,7 +1547,7 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1309
1547
  discriminator: null,
1310
1548
  }],
1311
1549
  emittedContract: null,
1312
- shapeIds: ['case.response-packet.v6', 'case.response-packet.v7', 'case.response-packet.v8', 'case.response-packet.v9'],
1550
+ shapeIds: CASE_RESPONSE_PACKET_OUTPUT_VERSIONS.map((version) => `case.response-packet.v${version}`),
1313
1551
  boundProfileIds: ['case.packet.bounds'],
1314
1552
  hookIds: ['case.packet.verify'],
1315
1553
  serialisationProfileId: null,
@@ -1328,7 +1566,7 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1328
1566
  discriminator: null,
1329
1567
  }],
1330
1568
  emittedContract: null,
1331
- shapeIds: ['case.response-packet.v6', 'case.response-packet.v7', 'case.response-packet.v8', 'case.response-packet.v9'],
1569
+ shapeIds: CASE_RESPONSE_PACKET_OUTPUT_VERSIONS.map((version) => `case.response-packet.v${version}`),
1332
1570
  boundProfileIds: ['case.packet.bounds'],
1333
1571
  hookIds: ['case.packet.structure', 'case.packet.verify'],
1334
1572
  serialisationProfileId: null,
@@ -1342,10 +1580,10 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1342
1580
  operation: 'build-packet',
1343
1581
  acceptedContracts: [],
1344
1582
  emittedContract: { schema: CASE_RESPONSE_PACKET_SCHEMA, version: CASE_RESPONSE_PACKET_VERSION, discriminator: null },
1345
- shapeIds: ['case.response-packet.v9'],
1583
+ shapeIds: [`case.response-packet.v${CASE_RESPONSE_PACKET_VERSION}`],
1346
1584
  boundProfileIds: ['case.packet.bounds'],
1347
1585
  hookIds: ['case.packet.build', 'case.portable.serialise'],
1348
- serialisationProfileId: 'case.packet.json.v9',
1586
+ serialisationProfileId: 'case.packet.json',
1349
1587
  privacyProfileId: 'case.privacy.portable-output',
1350
1588
  retentionEffect: 'operator_controlled_output',
1351
1589
  ...sharedEdge,
@@ -1361,7 +1599,7 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1361
1599
  discriminator: null,
1362
1600
  }],
1363
1601
  emittedContract: null,
1364
- shapeIds: ['case.response-review-inputs.v1', 'case.response-review-inputs.v2', 'case.response-review-inputs.v3'],
1602
+ shapeIds: SUPPORTED_CASE_RESPONSE_REVIEW_INPUTS_VERSIONS.map((version) => `case.response-review-inputs.v${version}`),
1365
1603
  boundProfileIds: ['case.packet.bounds'],
1366
1604
  hookIds: ['case.review-inputs.validate'],
1367
1605
  serialisationProfileId: null,
@@ -1379,7 +1617,7 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1379
1617
  version: CASE_RESPONSE_REVIEW_INPUTS_VERSION,
1380
1618
  discriminator: null,
1381
1619
  },
1382
- shapeIds: ['case.response-review-inputs.v3'],
1620
+ shapeIds: [`case.response-review-inputs.v${CASE_RESPONSE_REVIEW_INPUTS_VERSION}`],
1383
1621
  boundProfileIds: ['case.packet.bounds'],
1384
1622
  hookIds: ['case.review-inputs.build'],
1385
1623
  serialisationProfileId: null,
@@ -1406,18 +1644,37 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1406
1644
  retentionEffect: 'deliberate_local_file',
1407
1645
  ...sharedEdge,
1408
1646
  },
1647
+ {
1648
+ id: 'case.consumer.cli-edit',
1649
+ plane: 'cli',
1650
+ operation: 'review-and-edit-local-file',
1651
+ acceptedContracts: [{
1652
+ schema: CASE_EXPORT_LIFECYCLE_SCHEMA,
1653
+ versions: [...CLI_CASE_PACK_INPUT_CASE_VERSIONS],
1654
+ mode: 'direct',
1655
+ discriminator: null,
1656
+ }],
1657
+ emittedContract: { schema: CASE_EXPORT_LIFECYCLE_SCHEMA, version: CASE_SCHEMA_VERSION, discriminator: null },
1658
+ shapeIds: CLI_CASE_PACK_INPUT_CASE_VERSIONS.map(version => `case.export.v${version}`),
1659
+ boundProfileIds: ['case.editable.bounds', 'case.portable.bounds'],
1660
+ hookIds: ['case.editable.read', 'case.export.build', 'case.browser.serialise'],
1661
+ serialisationProfileId: null,
1662
+ privacyProfileId: 'case.privacy.portable-output',
1663
+ retentionEffect: 'operator_controlled_output',
1664
+ ...sharedEdge,
1665
+ },
1409
1666
  {
1410
1667
  id: 'case.consumer.cli-pack-build',
1411
1668
  plane: 'cli',
1412
1669
  operation: 'build-case-pack',
1413
1670
  acceptedContracts: [{
1414
1671
  schema: CASE_EXPORT_LIFECYCLE_SCHEMA,
1415
- versions: [CASE_SCHEMA_VERSION],
1672
+ versions: [...CLI_CASE_PACK_INPUT_CASE_VERSIONS],
1416
1673
  mode: 'direct',
1417
1674
  discriminator: null,
1418
1675
  }],
1419
1676
  emittedContract: { schema: CLI_CASE_PACK_SCHEMA, version: CLI_CASE_PACK_VERSION, discriminator: null },
1420
- shapeIds: ['case.export.current', 'case.cli-pack.current'],
1677
+ shapeIds: [...CLI_CASE_PACK_INPUT_CASE_VERSIONS.map((version) => `case.export.v${version}`), 'case.cli-pack.current'],
1421
1678
  boundProfileIds: ['case.portable.bounds', 'case.domain.bounds', 'case.cli-pack.bounds'],
1422
1679
  hookIds: ['case.cli-pack.build', 'case.cli-pack.serialise'],
1423
1680
  serialisationProfileId: 'case.cli-pack.json.v2',
@@ -1441,7 +1698,7 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1441
1698
  discriminator: null,
1442
1699
  }],
1443
1700
  emittedContract: null,
1444
- shapeIds: ['case.workspace-archive.v5', 'case.workspace-archive.v6', 'case.workspace-archive.v7', 'case.workspace-archive.v8', 'case.workspace-settings.v1'],
1701
+ shapeIds: [...SUPPORTED_WORKSPACE_ARCHIVE_VERSIONS.map(version => `case.workspace-archive.v${version}`), 'case.workspace-settings.v1'],
1445
1702
  boundProfileIds: ['case.workspace.bounds'],
1446
1703
  hookIds: ['case.workspace.verify'],
1447
1704
  serialisationProfileId: null,
@@ -1455,10 +1712,10 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1455
1712
  operation: 'build-workspace',
1456
1713
  acceptedContracts: [],
1457
1714
  emittedContract: { schema: WORKSPACE_ARCHIVE_SCHEMA, version: WORKSPACE_ARCHIVE_VERSION, discriminator: null },
1458
- shapeIds: ['case.workspace-archive.v8'],
1715
+ shapeIds: [`case.workspace-archive.v${WORKSPACE_ARCHIVE_VERSION}`],
1459
1716
  boundProfileIds: ['case.workspace.bounds'],
1460
1717
  hookIds: ['case.workspace.build', 'case.portable.serialise'],
1461
- serialisationProfileId: 'case.workspace.json.v8',
1718
+ serialisationProfileId: `case.workspace.json.v${WORKSPACE_ARCHIVE_VERSION}`,
1462
1719
  privacyProfileId: 'case.privacy.portable-output',
1463
1720
  retentionEffect: 'operator_controlled_output',
1464
1721
  ...sharedEdge,
@@ -1511,7 +1768,7 @@ const CASE_LIFECYCLE_CONSUMERS = Object.freeze([
1511
1768
  version: ENCRYPTED_WORKSPACE_ARCHIVE_VERSION,
1512
1769
  discriminator: null,
1513
1770
  },
1514
- shapeIds: ['case.workspace-archive.v5', 'case.workspace-archive.v6', 'case.workspace-archive.v7', 'case.workspace-archive.v8', 'case.encrypted-workspace-archive.v1'],
1771
+ shapeIds: [...SUPPORTED_WORKSPACE_ARCHIVE_VERSIONS.map(version => `case.workspace-archive.v${version}`), 'case.encrypted-workspace-archive.v1'],
1515
1772
  boundProfileIds: ['case.workspace.bounds', 'case.encrypted-workspace.bounds'],
1516
1773
  hookIds: ['case.encrypted-workspace.build', 'case.portable.serialise'],
1517
1774
  serialisationProfileId: 'case.encrypted-workspace.json.v1',
@@ -1590,7 +1847,6 @@ export const CASE_PORTABILITY_LIFECYCLE_FAMILY = defineSchemaLifecycleFamily({
1590
1847
  ],
1591
1848
  fixtures: CASE_LIFECYCLE_FIXTURES,
1592
1849
  metadata: {
1593
- metadataVersion: 4,
1594
1850
  enforcement: 'declarative_only',
1595
1851
  shapes: CASE_LIFECYCLE_SHAPES,
1596
1852
  boundProfiles: CASE_LIFECYCLE_BOUNDS,