1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
//! # packdiff-dto — the data model
//!
//! This crate is the single source of truth for every piece of data packdiff
//! handles. It is **pure logic**: no filesystem, no subprocess, no clock, no
//! randomness — those all live in the callers (`packdiff-cli` natively,
//! `packdiff-wasm` in the browser). That is what lets the *same* compiled
//! semantics run on both sides of the tool.
//!
//! Two document families:
//!
//! - [`diff::DiffDocument`] — the **immutable build artifact**: everything the
//! CLI extracted from git (refs, commits, per-file hunks and lines). It is
//! produced once per render and embedded/consumed read-only.
//! - [`review::ReviewDocument`] — the **mutable review state**: the comments a
//! human leaves on the page. It lives in the browser's localStorage, and
//! every mutation (upsert, delete, merge/import) goes through this crate via
//! WASM — the page's JavaScript never edits the document itself.
//!
//! Schema rules:
//!
//! - JSON field names are `snake_case`; union variants are `CamelCase` and
//! encode as single-key objects — `{ "VariantName": { ...payload } }` — with
//! no discriminator field.
//! - Every struct strict-rejects unknown fields (`deny_unknown_fields`): a
//! typo or a drifted producer is a hard, loud error, never a silently
//! ignored key.
//! - Both documents carry `schema_version` ([`SCHEMA_VERSION`]). This is the
//! one deliberate opt-in to long-term compatibility (review documents live
//! in users' localStorage): parsers reject documents from a *newer* schema
//! than they understand and accept older ones (there is only v1 today, so
//! "accept" means "equal").
//! - Determinism: same inputs → byte-identical outputs. Ordering is always
//! explicit ([`review::ReviewDocument::sort`]), timestamps and ids are
//! caller-supplied, and exports are stable.
/// Version stamped into (and required of) every document this crate touches.
pub const SCHEMA_VERSION: u32 = 1;
/// Tool identifier stamped into documents.
pub const TOOL: &str = "packdiff";
/// A named ref pinned to the commit it resolved to at build time.
/// Errors surfaced by any model operation. Typed so callers branch on
/// variants; the WASM ABI ships them as `{ "Error": { "message": ... } }`.
/// The localStorage key a review document is filed under.
///
/// The key pins the exact endpoint SHAs on purpose: line numbers are only
/// meaningful against the diff they were written on. Regenerating the same
/// diff finds the same comments; new commits get a fresh store (carry
/// comments over with export → import, where [`review::ReviewDocument::merge`]
/// applies).