Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 5 Nov 2026. What's built · Install 0.3.0
jadpo
ReferenceReview and records

ToolsReview and records

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). 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 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, 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). What the first record holds that a person decides is said all the same (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 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 check1 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 yetchecked: 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 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) 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 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 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.

Markdown for agents: /docs/comparing-two-builds.md.Built from Jadpo main at aee2e8f.