Skip to main content
Track specification change | ESSCompare compiled specification revisions and explain which scenarios and generated artifacts need another check.ESShow-toesshow-toadopterdevelopertry-spec-driven-developmentspecify

Track specification change

ess verify diff describes changes between two compiled models. ess verify impact follows their dependencies to identify conformance scenarios owed another run and generated artifacts owed regeneration. Neither command establishes that an earlier conformance result still holds.

Compare revisions​

ess verify diff --from examples/revision-pair/before --to examples/revision-pair/after
ess verify diff --from examples/revision-pair/before --to examples/revision-pair/after --format json

The committed example pair changes currency variants, an entity invariant, an outcome condition and actor grants while also moving files and reordering declarations. The comparison uses the compiled models, so comments and source-file layout do not themselves produce changes.

The report follows these rules:

  • Ten typed construct families are compared: system header, types, entities, commands, events, errors, views, actors, components and bindings. Residual model changes outside those typed comparisons produce unclassified-changed; they are not silently treated as equality.
  • Every part of a command outcome is compared on its own, one change per outcome. ess-diff/12 adds the kinds for an error's payload: sources (outcome-error-payload-added, outcome-error-payload-removed, outcome-error-payload-changed), accepts: nothing (outcome-accepts-nothing-changed), returns: (outcome-returns-changed) and a refusal the caller decides (outcome-decided-by-caller-changed).
  • Changes carry stable content-derived ids and a relation: widening, narrowing or changed. Predicate comparison uses canonical equality, not a proof that one predicate implies another.
  • Renames are not inferred. A removed declaration and an added declaration remain two changes.
  • Inputs must describe revisions of the same system. A different system identity is refused.

--format accepts text or json. JSON output is ess-diff/2, as it is for this pair, unless the delta carries a change kind introduced later; it then takes the newest version any of its changes needs, up to ess-diff/12 (see the format history). The library retains the frozen /1 vocabulary and reader support; explicit legacy writing refuses changes outside that vocabulary. The endpoint digests identify compact compiled models, not raw YAML or the pretty JSON shown by ess specify compile. Delta writer, comparison.

Fail on a breaking change​

A relation says which way a set moved, not who is broken by it. --compatibility classifies each change for three readers of the model: callers written against --from invoking --to, readers written against --from reading what --to produces, and history, --to reading the entity state and events --from already wrote. Each answer is compatible, unknown or breaking, and the change's verdict is the worst of the three.

ess verify diff --from before --to after --compatibility
ess verify diff --from before --to after --fail-on breaking
ess verify diff --from before --to after --fail-on breaking --acknowledgements reviewed.json
  • A type change is read through where the type is used, nested inside structs, newtypes, unions, lists, maps or optionals: a command input or view parameter is an input, a response, event, error or view row an output, an entity field or event a stored value. A component setting and an external channel's or periodic host's context fields are input too. A removed variant breaks callers and history and no reader; an added variant breaks readers of an output and nobody else. Any other mention of the type is unmodelled: a change to the type, other than documentation or adding or removing it, is then unknown in every dimension.
  • A grant or command removed breaks callers, a view removed breaks readers, an event or entity removed breaks history. Additions and display-name, summary or example changes are compatible.
  • Everything else, such as a wire rename, an added field or a predicate rewrite, is unknown: the answer depends on how consumers treat it, and the model does not say.

--fail-on breaking exits 4 when an unacknowledged change is breaking in a considered dimension; --fail-on breaking-or-unknown also fails on unknown. --dimension callers (repeatable) limits the dimensions considered. Without --compatibility or --fail-on, the output and the exit status are unchanged. With either, JSON output is ess-diff/14, and every change carries compatibility.

An acknowledgements file lets reviewed changes pass. It is bound to the exact pair compared: take both digests from the delta, and list change ids from it.

{
"format": "ess-diff-acknowledgements/1",
"before": "<before.spec_digest>",
"after": "<after.spec_digest>",
"acknowledged": ["type/demo.calls.Channel/variant-removed/Chat"]
}

A file naming other digests, an id the delta does not hold or an id twice is refused with exit 1. Classification and gate.

Find the work owed again​

Without --suite, impact reports construct dependencies and generated-artifact obligations:

ess verify impact --from examples/revision-pair/before --to examples/revision-pair/after

To include scenarios, supply a suite for the before revision. For example, generate one from the committed pair and then compare:

ess verify conform synthesize --path examples/revision-pair/before --out before-suite.json
ess verify impact --from examples/revision-pair/before --to examples/revision-pair/after \
--suite before-suite.json

The report starts with the delta and explains each reached construct, scenario and artifact. A scenario about a price list can be affected by a currency change through the price list's money field. The dependency path explains why it is owed even when the scenario does not mention the currency type directly. Adding --format json writes ess-impact/3, with its embedded /2 delta and current dependency-relation vocabulary. Impact implementation, dependency graph.

The CLI computes artifact obligations from the generators' output for the compared models. It does not read your committed generated directory, and there is no --generated CLI option. Library callers can supply a GeneratedTree to ess_diff::impact for the separate committed-stamp check. An unreadable, mismatching or obsolete slice-profile claim then owes regeneration. A command that runs without that input has not performed that check. CLI entry point.

When narrowing is unavailable​

SituationResult
A system-wide change has no construct from which to start a dependency walkWhole obligations apply.
Residual model content changes outside the typed comparisonsunclassified-changed makes whole obligations apply.
A scenario or artifact depends on a construct absent from both dependency graphsThe answer stays whole rather than silently omitting that dependency.
The supplied suite belongs to another system or does not match the before model/contract digestThe comparison is refused.

An item absent from the narrowed answer was not reached by this analysis. That is not a claim that its prior evidence remains valid or that the suite has complete coverage. Suite/4 carries model and whole-contract identities; it does not carry an exact digest of the complete suite bytes.

Design documents, runbooks and prose references outside the compiled model are not part of the dependency walk. Their owner must track their freshness separately.

See Formats and digests for current version markers, reader boundaries and the distinct compiled-model, whole-contract and sliced-contract digest profiles.