Skip to content
On this page

Comparisons

A comparison puts two sides of contracts beside each other and gives every contract a verdict: Kept, Moved, Changed, Gone or New. You use it to see what a rewrite still owes the app it replaces, or what shipping a branch would change for the systems that call it. It compares contracts by their keys, never the boards themselves.

The Comparisons screen lives on the root board. Each side is one or more sets.

A Live app reads the app's aspects as they are now. A Captured app is a copy taken when you saved it. A Tracked branch is filled by /aspects runs on that branch. A Document is an OpenAPI document or a DDL dump you paste in.

One table says what the new side still owes the old one, contract by contract.
  1. 1

    Headline

    The headline counts the old side's contracts: N of M contracts kept, then what is accepted.

  2. 2

    Dots

    A filled dot opens the contract on its app's Aspects screen; a hollow dot opens the captured shape in place.

  3. 3

    Rail

    Select a board on a rail to narrow the table to it and the boards under it.

Set up

Note

Owners and admins declare and edit comparisons. Every member reads them.

A comparison compares under change rules. Open Organization settings → Change Rules. Under Compared across apps, each rule names the kinds it compares. Reads as Changed when sets how deep it reads before a difference counts, Interface or Shape. The provided Schema rule compares tables. API contract compares endpoints and channels.

Under Interface, a column, parameter, response status or event type present on one side only, or a nullability or required flag that differs, reads as Changed. A type or schema spelled differently is a note on a Kept row. Under Shape, those notes read as Changed too. Start with Interface: two extractions of near-identical code spell types differently more often than code changes them.

Declare a comparison

Pick a shape, then say what sits on each side.

  1. Open the root board's Comparisons screen and choose New comparison.
  2. Pick a preset: Rewrite, Monolith split, Consolidation, Database move, Auth rewrite or Release check. The preset fills the sides and narrows Compared by; you can change anything it filled.
  3. Under Before and After, give each set its app. A Tracked branch also takes its branch, a Document its name. Captured app copies the app's contracts the moment you create the comparison.
  4. With two or more apps after, tick which before apps each one carries. A contract kept only by an app that carries none of them reads Moved.
  5. Pick the Epic its work items go on, or leave it to be made with the first one. Choose Create comparison.

An app can sit live on one side and captured or tracked on the other, never live on both.

Read the table

The headline counts the old side's contracts: "N of M contracts kept", then what is consumed and missing, accepted, kept with notes or kept with the shape not read. Each group is one rule, with its own counts.

  • A filled dot opens the contract on its app's Aspects screen. A hollow dot belongs to a captured or imported set and opens the stored shape in place, with where the extractor read it.
  • Notes list the shape differences on a kept row. Not read names an interface field neither side cited, such as a column's nullability; it never counts as a change.
  • A flag marks a Gone or Changed contract under a critical rule, or a Gone contract something outside the comparison depends on. "Used by" names the system.
  • Select a board on a rail to narrow the table to it and the boards under it. The headline keeps its whole counts.

Keep a captured side current

A Captured app is the old side as it was. When its app pushes contracts the capture lacks, the sets panel says so: "The app now serves 6 contracts this capture lacks". The table does not change on its own. Re-capture copies the app's contracts again and stamps the set with the commit they were pushed at.

Import a document

A Document set starts empty. In the sets panel choose Import, pick the format, paste or pick the file and choose Import. The document's contracts replace what the set held.

OpenAPI or Swagger takes JSON or YAML. Each operation becomes an endpoint with its parameters, body and responses. DDL dump takes CREATE TABLE statements from any dialect. Each table becomes a table with its columns.

Compare a branch against live

A Release check compares an app's live contracts with a branch of the same app.

  1. Declare it with the Release check preset: the app's Live app before, the same app as a Tracked branch after, with the branch name. The branch must differ from the one the app already pushes from.
  2. In the repo, switch to that branch and run /aspects. The run's contracts land in the comparison's set and the app's own boards stay as its pinned branch pushed them. The result says where they landed.
  3. On that branch, /sync and /changes stop before extracting and name the comparison. Run them on the pinned branch.

The app's hub shows a chip, "Beta on develop compared with live", and a flagged row's attention line says the contract is on the way to release. A Release check stays open; close it when the branch ships.

Act on a row

Open a row's menu:

  • Make a work item on an after app drafts a work item there, with the old contract attached and the comparison's epic. It closes on its own when a later /aspects run on that app serves the contract.
  • Pair with a new contract says a Gone contract and a New one of the same kind are the same contract under another name. They fold into one row marked paired. Unpair separates them.
  • Accept as intended… records a Gone or Changed contract as what you meant, with a reason. The row keeps its verdict, loses its flag and leaves the owed count. Withdraw acceptance reverses it.

From the code plugin

The code plugin's /aspects reads the comparison before it extracts. pmap-aspects.js --charter prints the contracts an open comparison expects the board to serve, so the extraction looks for those first and never invents one it cannot find. Every contract it pushes carries where it was read, and a field it cannot cite stays empty rather than guessed. A row whose file is unchanged since the last push keeps the last push's reading, so a re-extraction cannot drift a contract nobody touched.

A push is refused when it reads the shape of fewer than half the contracts the board's last push read. The refusal says why: "Landing it would wipe shapes a previous run read." Extract the shapes and push again, or push with --force when the loss is real.

FAQ

Does a comparison compare the boards' nodes and edges?

No. It compares contracts by their keys. A table is its name, an endpoint its method and path, a channel its broker and name, a page its route, a client the service it calls. The boards are where a contract opens, not what is compared.

Why does a kept row carry a note instead of reading Changed?

The note is a shape difference: a type or a schema spelled differently. Under Interface strictness it stays a note so extraction noise never flags a work item. Set the rule to Shape in Change Rules when those differences matter to you.

What happens to work items when I delete a comparison?

They stay, as ordinary work items on their apps. Deleting a comparison removes its sets, pairings and acceptances, nothing on the boards.

What's next