# Comparing two builds

Every review is a diff of two manifests. The **after** side is your
working tree. The **before** side is a git ref.

By default, the before side is the repository's default branch (`main`
or `master`, read from the git remote) at its merge base with your
current branch, as a pull request's diff is. So changes merged into the
default branch since you branched don't show as reversed. On the default
branch itself, the before side is the previous commit. Pass
`--before <branch or commit>` to compare with anything else. The same
default serves `check`, `jadpo approval` and the review web view.

The compiler reads that commit from git, builds it with the same
compiler, and caches its manifest in `build/before/<commit>/`, so this
costs one build per base commit.

- **`jadpo check`** uses the diff to fail on any change that needs a
  person and hasn't been accepted
  ([Review and sign-off](/docs/review-and-sign-off.md)). In CI, the
  base commit must be fetched: a full clone, not a depth-1 checkout.
- **`jadpo approval`** explains the same diff as Markdown and JSON in
  `build/review/`, decisions first, in the order
  [Reviewing a change](/docs/reviewing-a-change.md)
  gives. For production, pass the commit that the deployed build's events
  carry.
- **Records come with it.** The API record's diff, the migrations added,
  the lock changes and the acceptances added are part of the before and
  after trees, so the review lists them without a second mechanism.
- **A base that doesn't compile.** If the base doesn't compile with this
  compiler, for example after a language upgrade, `check` compares the
  records only and says so. Upgrade the compiler in its own change.
- **Nothing to compare with.** Outside a git repository, with no default
  branch, before the first commit, or for a project new since its base,
  there is no before side: nothing is compared and no acceptance is
  judged, and `jadpo check` says why in one line, `before  none, so
  acceptances aren't judged: …`. Outside git it says so only when the
  project holds acceptances. A record the before side doesn't have, such
  as `access.jadpo_record` arriving with this change, is compared with
  nothing, and `check` names it on the same line. So that an app's first
  outside host is still compared, an app with a `connections:` block keeps
  `network.jadpo_record` even while it reaches no host, with its header
  alone; and a before side with no network record whose
  `app.jadpo` has no `connections:` block reached no outside host, so its
  record is read as empty and the change that adds the block and a host
  needs `NetworkChange.host_added`. In the same way a before side with no
  `jadpo.lock` had no packages, and one with no `access.jadpo_record` no
  `own_sources:`, so the first package from git and the first entry are
  still compared. Only a before side with the block and
  no record, a project from before the record, is compared with nothing.
  A base commit the clone doesn't hold, as in a
  depth-1 checkout, is
  [`acceptance.base_missing`](/docs/errors/acceptance.base_missing.md),
  naming `git fetch`.
  A migration that removes data is judged all the same: with no before
  side, it needs an acceptance with a reason anywhere in the project
  ([`migration.drop_not_accepted`](/docs/errors/migration.drop_not_accepted.md)).
  What the first record holds that a person decides is said all the same
  ([What a first record holds](/docs/comparing-two-builds.md#what-a-first-record-holds)).

## What a first record holds

A first commit has nothing to compare with, so what would need a person on any
later change passes unseen. The first of all is a new project's public create,
update or delete, and personal data anyone may read. So `jadpo check` says what such a first record holds, marked
`(human)`, and [the approval report](/docs/reviewing-a-change.md)
leads with it. It is a notice and not an error, and `check` still passes: it is
a decision, not a vulnerability, since an app may mean it.

```text
$ jadpo check
1 decision compared with nothing
◆ anyone can create and change `lending.Book` records, with no sign-in  not compared
    access.jadpo_record:12

◆ decision  nothing compares this, so a person reads it before it goes in
  next      A person decides whether the app means it. This passes either way,
            and it is compared as usual once a commit holds it. (human)

  before    none, so acceptances aren't judged: no commit yet

checked: 14 files
```

It is said while there is no before side (no commit yet, the first commit
itself, a project new since its base) and, for what a record holds, while the
before side has no such record, as when `access.jadpo_record` arrives with this
change. Outside git nothing is being reviewed, so nothing is said, as with
`before none`. It is said only once `check` otherwise passes, since an agent's
errors come first, and `--json` gives each in `notice_list`: its `subject`, its
`kind`, what it `said`, `decides: human`, and its `file` and `line`. Once a
commit holds it, it goes: from then on it is compared.

| Said | Kind | Goes once |
|---|---|---|
| A create, update or delete anyone may make, or an action listed for anyone that creates, changes or deletes records, itself or through what it calls | `public_write` | A commit holds it |
| [Personal data](/docs/marking-personal-fields.md) anyone may read, with no sign-in: a field marked `personal:`, or of a standard type that is personal data such as an `Email`, on an entity whose `read:` lists `Access.public`, unless its own `policy:` keeps it from them | `public_read` | A commit holds it |
| A connection that receives personal data and can't erase it ([Erasure at providers](/docs/erasure-at-providers.md)) | `ErasureNotPossible.data_stays` | An acceptance lists it with a reason: the next change is refused until one does, since this kind says how things stand |
| A security rule declined | `PolicyChange.<rule>_declined` | A commit holds it |
| A sign-in setting past its limit | `PolicyChange.sign_in_loosened` | A commit holds it |
| An entity shared by every tenant | `PolicyChange.shared_entity_added` | A commit holds it |
| An own source in `packages:` | `PolicyChange.own_source_added` | A commit holds it |
| A third party's package from git | `PackageChange.git_source` | A commit holds it |
| A connection reaching a host someone else runs: not the app's own database or cache, which every app has | `NetworkChange.host_added` | A commit holds it |

A public write has no acceptance to write, since a new entity's grants need
none. So its notice is for the first record holding one, however old the
record: the change that adds the first entity anyone may write to says so, and
a later one is the diff's to show. A public read of personal data goes the same
way:

```text
◆ anyone can read `shop.Customer.email`, personal data, with no sign-in  not compared
    access.jadpo_record:7
```

It is the grant that is said, whether or not a route reads it yet, since
[a public read](/docs/anyone-signed-in-or-anyone.md) needs both and a route
added later is nothing new to anyone reading the record. Each field is named,
and which are personal data is what the
[report](/docs/the-personal-data-report.md#where-personal-data-goes) counts today. A widening
that lets anyone in is judged as
ever, as a decision rather than a notice. A reason already in the project for
one of the kinds in the table says it was decided, so it isn't said again.

The other kinds have no such gap. Removing or changing something (`ApiChange`,
`ThresholdChange`, an upgrade's `PackageChange`, `PolicyChange.route_public`,
`.confirmation_removed`, `.restriction_removed`, `.tenancy_loosened` and
`.listing_removed`) has nothing to remove or change in a first commit, and
`DataChange` is judged even so. The first grants, roles, listed actions and
domains (`PolicyChange.widened`, `.role_requirements_changed`,
`.listing_added`, `DomainChange.created`) are what a project is made of, so
listing them would list the whole project; a public write, and a public read of
personal data, are the ones among them that are said.

`jadpo check` reads the before side's records and acceptances from git,
and the names of its domains, and compares them with the records today's
source writes; it doesn't build the base. `jadpo approval` does, once per
base commit and per compiler: it reads every file of the commit from git
into memory, checks it with this compiler, and keeps its manifest, and the
declines the report compares, in `build/before/<commit>/`. A base that
doesn't compile is built as far as it reads, and the report says how many
errors it has.
