Changeset JSON schema¶
A changeset JSON document is a tree of DiffNode values wrapped
in a Changeset envelope. The shape is deliberately open:
action, item_type, and tags are unbounded strings that plugins extend.
Consumers should treat unknown values as opaque and fall through to generic
handling.
The machine-readable schema (JSON Schema draft 2020-12) lives alongside this
page at changeset-schema.json and is generated
from the Rust IR types. The tables below are a rendering of that schema.
What is not in the changeset¶
- Significance classification. Changelog grouping is a renderer concern, applied at render time from configured headings and tag lists. The IR is judgment-free. See Significance classification.
- Transient session data.
source_itemsandartifactsare wire-visible because the plugin ABI carries them across (potentially process-isolated) boundaries, but they are stripped at the output boundary viaDiffNode::strip_transientbefore changeset JSON is written for users. They appear in the schema below, but callers writing changeset files should not expect to see populated values. See the Transient fields on wire ADR.
Stability¶
The IR is still evolving. Once a first stable version is cut, the schema will be versioned and this page will document compatibility guarantees. Until then, treat the shape as informative and pin your downstream pipeline to known plugin versions.
Where to go next¶
- IR and changesets — the conceptual model behind the shape documented here.
- Save and render changesets — producing and combining changeset JSON from the CLI.
- Extract changed data — using the provenance fields to pull actual changed content out of a changeset.
Types¶
Changeset¶
A structured description of how to get from one snapshot to the next.
| Field | Type | Required | Description |
|---|---|---|---|
claims |
array of GlobalClaim |
no | Run-scoped claims that do not belong to one tree node. Reserved for the CFM-41 global-claim prototype; empty in current engine output. |
diagnostics |
array of Diagnostic |
no | |
from_snapshot |
string | yes | |
metadata |
object (map of string → string) | no | |
root |
DiffNode | null |
no | |
to_snapshot |
string | yes |
DiffNode¶
A node in the projected diff tree — the durable changeset structure consumed by renderers, serializers, and bindings.
| Field | Type | Required | Description |
|---|---|---|---|
action |
string | yes | Open enum: "add", "remove", "modify", "move", "reorder", "schema_change", etc. Plugins may define new actions. |
annotations |
array of Annotation |
no | Renderer-visible annotations supplied by rule packs. |
artifacts |
array of ArtifactDescriptor |
no | Published artifacts for this node. Session-scoped working data: carried across the plugin ABI wire as descriptors (the bytes live in the shared data_root cache), but not meaningful outside a session. Callers writing changeset output must strip this via [DiffNode::strip_transient] before serializing. |
children |
array of DiffNode |
no | Child diff nodes forming the tree structure. |
detail_blocks |
array of DetailBlock |
no | Renderer-visible, structured evidence blocks. Rule packs populate these with bounded examples while they still have domain knowledge; renderers decide how much to display. |
details |
object (free-form) | no | Structured payload, schema determined by item_type/action convention. |
diagnostics |
array of Diagnostic |
no | Node-scoped diagnostics emitted during a run. Transient: the controller hoists them into [Changeset::diagnostics] at the end of the diff, then clears this field so the output shape stays as one durable top-level diagnostics list. |
item_type |
string | yes | Open string: "directory", "file", "tabular", "zip_archive", etc. No built-in types — conventions, not enforcement. |
path |
string | yes | Location within snapshot (logical path, including interior paths like "archive.zip/>data/file.csv"). /> marks a decompose boundary; a literal segment beginning with > is escaped as \>. |
source_items |
ItemPair | null |
no | The original item pair associated with this projected node when one is available. Session-scoped working data: available during a live run for rules and extractors that need to re-read source data. Callers writing changeset output must strip this via [DiffNode::strip_transient] before serializing. |
sources |
array of Source |
no | Renderer-visible provenance for this projected node. |
summary |
Summary | null |
no | Optional structured one-liner describing the change. Set during projection; renderers format each [Segment] by its type. Build it with [Summary]'s builder, or pass a plain string — impl Into<Summary> wraps it as a single [Segment::Text]. |
tags |
array of string | no | Open bag of semantic tags, namespaced by convention. e.g. "binoc.column-reorder", "biobinoc.gap-change" |
ItemPair¶
A pair of items to compare. Either side may be None (add/remove).
| Field | Type | Required | Description |
|---|---|---|---|
left |
ItemRef | null |
no | |
right |
ItemRef | null |
no |
ItemRef¶
Metadata-only view of one side of a comparison. Carries logical identity and content metadata but NOT a filesystem path — data access goes through DataAccess. # Metadata invariants content_hash, size, and media_type are opportunistic hints. Producers (expand rules like directory/zip, or data backends) populate them when doing so is cheap — typically as a byproduct of work they were already performing. Consumers must not assume presence, but may trust presence: when a field is set, the value accurately reflects the current bytes. Use [ItemRef::resolve_hash] / [ItemRef::resolve_size] to obtain a value with a transparent fall-back read. This keeps fast paths (directory-only listings, short-circuit identical detection) cheap while letting consumers that need a value — most notably the move detector, which correlates leaves across container boundaries — hydrate on demand.
| Field | Type | Required | Description |
|---|---|---|---|
content_hash |
string | null | no | |
handle |
string | no | Opaque identifier used by DataAccess implementations to locate data. Plugin authors should not create or interpret this value directly. |
is_dir |
boolean | yes | |
logical_path |
string | yes | User-meaningful location within a snapshot. /> marks a decompose boundary; a literal segment beginning with > is escaped as \>. |
media_type |
string | null | no | |
projection_hint |
ProjectionHint |
no | Optional projection metadata supplied by rule packs while they still know the vocabulary. Core carries this through but does not interpret file names, media types, or plugin-specific tags. |
size |
integer | null | no |
ArtifactDescriptor¶
Descriptor for a published artifact attached to a node. Artifacts are the unified mechanism for both private reuse and cross-plugin composition. Parse rules publish artifacts; downstream rules consume them by format.
| Field | Type | Required | Description |
|---|---|---|---|
format |
ArtifactFormat |
yes | |
handle |
string | yes | Opaque handle managed by the SDK's DataAccess implementation. Plugins should not create or interpret this value directly. |
producer |
string | yes | |
subject |
ArtifactSubject |
yes |
ArtifactFormat¶
Identifies an artifact's data format as a structured tuple of (package, name, version). - package — the package that owns and defines this format, resolvable through the language's normal package system (e.g. "binoc", "binoc-csv", "acme-parquet"). - name — the format name within that package (e.g. "tabular", "relational-schema"). - version — a single integer. Bump only for breaking schema changes. Adding optional fields to an existing version is fine and does not require a bump (JSON/serde naturally ignore unknown fields and default missing ones).
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | |
package |
string | yes | |
version |
integer (uint32) | yes |
ArtifactSubject¶
Which side of a comparison an artifact describes.
String enum. One of:
leftrightpair
Annotation¶
Renderer-visible metadata attached to a projected diff node by a rule pack. Annotations are intentionally progressively typed: producers can start with a string or simple JSON value, and renderers can either display the generic value shape or add package/key-specific handling later. The package namespace keeps independently-authored plugins from colliding on common keys.
| Field | Type | Required | Description |
|---|---|---|---|
key |
string | yes | |
package |
string | yes | |
value |
any | yes |
DetailBlock¶
Renderer-visible, bounded evidence attached to a diff node.
| Field | Type | Required | Description |
|---|---|---|---|
examples |
array of DetailExample |
no | Captured examples for inline rendering. |
extract |
array of ExtractHint |
no | Named extract aspects for exhaustive retrieval. |
id |
string | yes | Stable within this node, for anchors and extract selection. |
kind |
string | yes | Open, namespaced kind such as binoc.tabular.cell_changes.v1. |
label |
string | null | no | Short renderer-facing label. |
total_count |
integer | null | no | Total matching items if known, including omitted examples. |
truncated |
boolean | no | Whether the producer truncated capture before exhausting candidates. |
DetailExample¶
One bounded example inside a detail block.
| Field | Type | Required | Description |
|---|---|---|---|
after |
ValuePreview | null |
no | Value after the change, if present. |
before |
ValuePreview | null |
no | Value before the change, if present. |
fields |
object (free-form) | no | Domain-specific structured context. |
locator |
object (free-form) | no | Structured locator such as row/column, line range, or key path. |
Diagnostic¶
| Field | Type | Required | Description |
|---|---|---|---|
code |
string | yes | |
location |
string | null | no | |
message |
Summary |
yes | |
severity |
DiagnosticSeverity |
yes |
DiagnosticSeverity¶
String enum. One of:
errorwarningsuggestion
ExtractHint¶
Pointer to an extract aspect that can return exhaustive content.
| Field | Type | Required | Description |
|---|---|---|---|
aspect |
string | yes | Aspect name accepted by binoc extract. |
label |
string | null | no |
GlobalClaim¶
Reserved run-scoped claim slot. The shape is intentionally provisional pending the CFM-41 global-claim prototype. It gives renderers and serialized changesets a stable place for non-tree claims without committing the claim vocabulary yet.
| Field | Type | Required | Description |
|---|---|---|---|
params |
object (free-form) | no | Claim-specific structured parameters. |
summary |
Summary | null |
no | Optional renderer-facing summary for the claim. |
verb |
string | yes | Open claim verb such as a future global find/replace action. |
ProjectionHint¶
Product-facing projection metadata supplied by rules, not inferred by core.
| Field | Type | Required | Description |
|---|---|---|---|
action |
string | null | no | |
item_type |
string | null | no | |
retract_tags |
array of string | no | Tags this hint removes from the accumulated projection. Tag overlay is union-only, so an annotator that supersedes an earlier framing (e.g. a CFM-71 container reshape replacing a pair-time binoc.move) needs a way to drop the now-stale tag — otherwise the IR carries contradictory tags (inert in rendering, but incoherent in JSON). A retraction is honored whenever tags are merged: the named tags are removed from the result and can never be re-introduced by the same hint. |
summary |
Summary | null |
no | |
tags |
array of string | no |
Segment¶
(unrecognised schema shape)
Side¶
(unrecognised schema shape)
Source¶
Renderer-visible provenance for a projected diff node. Most nodes have one source. Move and copy nodes use a from source whose path differs from the projected node path; many-to-one projections such as merges and deduplications carry multiple sources.
| Field | Type | Required | Description |
|---|---|---|---|
action |
string | null | no | Open action associated with this source in the projection. |
evidence |
string | null | no | Open evidence string from the rule/link that established provenance. |
path |
string | yes | Logical path of the source item. |
side |
Side |
yes | Snapshot side where path resolves. |
Summary¶
(unrecognised schema shape)
ValuePreview¶
A bounded preview of one value in a detail example.
| Field | Type | Required | Description |
|---|---|---|---|
media_type |
string | null | no | |
truncated |
boolean | no | |
value |
any | yes |