Ledvar Diff — Companion Standard
- Version: 0.1.0 (DRAFT)
- Companion to: the Ledvar Protocol, MAJOR 0 (
SPEC.md) - Status: Draft. Optional.
1. What this is — and what it is not
This is an optional, open standard for representing the comparison of two Ledvar snapshots. It is a companion to the core protocol, not a part of it — the way JSON Patch (RFC 6902) is a separate standard from JSON itself.
The core protocol (SPEC.md) standardizes how state is represented and hashed, and
nothing more. Comparing two snapshots is a forced consequence of that — any correct implementation
reaches the same answer. So this document does not add new truth; it only fixes a shared
vocabulary for a computed comparison, so that one component can produce a result and another can
read it without guessing.
You MAY:
- adopt this standard, so your comparison results interoperate with anyone else who adopts it;
- define your own representation;
- store nothing and recompute comparisons on demand (the way
git diffderives a diff from stored objects).
The core protocol requires none of this. Conformance to SPEC.md does not depend on
this document.
2. The comparison
Given a previous snapshot and a current snapshot, match their nodes by identity_key
(SPEC.md §5). Each node receives exactly one StateStatus:
| StateStatus | Condition |
|---|---|
Baseline | there is no previous snapshot (cold start) — every node is Baseline |
Added | in current, not in previous |
Removed | in previous, not in current |
Unchanged | in both, equal content_hash |
Modified | in both, different content_hash |
These outcomes are exhaustive and mutually exclusive: every node is exactly one, and there is no
sixth case. This is not a design choice — it is what comparing two sets yields. Added, Modified
and Removed are collectively drift.
Baseline means there is no previous snapshot at all — a cold start. This is intentionally
distinct from a previous snapshot whose tree is empty: comparing against an empty previous is a
normal comparison and yields every current node as Added, not Baseline. “No comparand” and “an
empty comparand” are different states.
Whether a node changed is settled here by arithmetic. What the change means — whether it matters, whether it is allowed — is not. That is meaning, and meaning lives in higher layers (see the Manifesto, “context lives elsewhere”).
3. Result representation
A DiffNode is one node of a comparison result:
| Field | Type | Meaning |
|---|---|---|
node | Node | the node as it appears in current (or, for Removed, as carried from previous) |
identity_key | string | from SPEC.md §5 |
content_hash | string | from SPEC.md §5 |
state_status | StateStatus | §2 |
A DiffResult carries the current snapshot’s metadata (protocol_version, origin_id,
provider_name, timestamp, fingerprint, parent_origin_id, labels) plus a list of DiffNodes. It
MAY also carry an optional previous reference (the previous snapshot’s timestamp and/or
fingerprint) so a reader knows what current was compared against — otherwise that comparand is
lost once the result is serialized. This reference is a convenience only: whether a result is a
Baseline is already evident without it, since every node’s state_status is then Baseline.
This vocabulary is deliberately fact-only: a DiffNode says what changed, and nothing about whether
a change is acknowledged, silenced, severe, or allowed. Those are opinions a consumer layers on top
— they live in the consumer’s own representation, in its own layer, and are never standardized here (see
§2, and the core SPEC.md §4.4). A consumer that wants to carry, say, a suppression flag or
a severity does so in its own envelope around a DiffNode; because such judgements are
policy-specific (one system’s “silenced” is another’s “acknowledged”), standardizing them would hurt
interoperability, not help it.
4. Conformance (for adopters)
An implementation of this companion standard conforms iff, for the example snapshots
examples/snapshot-a.json (previous) and
examples/snapshot-b.json (current), it assigns the state_status
below to each node. (The hashes are the core protocol’s; see
examples/CONFORMANCE.md.)
| node (path) | in A | in B | StateStatus |
|---|---|---|---|
mydb / user:app | Medium, {SELECT,INSERT} | High, {SELECT,INSERT,DROP} | Modified |
mydb / config:max_connections | {200} | {200} | Unchanged |
mydb / user:backup | — | {SELECT,LOCK TABLES} | Added |
mydb / user:readonly | {SELECT} | — | Removed |
5. Status
Draft, optional companion to MAJOR 0. Like the core, once a non-zero MAJOR of this companion is published its result vocabulary is stable for that MAJOR.