Onus docs
Reading a report · Onus docs

Reading a report

Reading a report: rows, ranking, evidence, the changed lines tests ran and the JSON

A report for the manifesto's example (1,408 changed lines in 23 files):

### Onus · 4 meaning-level changes · 1 needs attention · 1,408 lines in 23 files

|   | Change                                                       | Kind                      | Why it matters |
| ● | `notifications` now calls an external SMS provider (Acme SMS) | New external dependency   | Customer phone numbers leave the system via Acme SMS, a new vendor; needs a person |
| ○ | `UserPreferences` gains an optional `phoneVerified` field     | Contract change, additive | Shared contract used in 4 files across 2 components; existing callers unaffected |
| ○ | `notifications` subscribes to the `OrderShipped` event        | New event consumer        | Additive; `orders` is unchanged |
| ○ | 1,402 lines of new code and tests inside `notifications`      | Internal                  | Stays inside `notifications`, which `billing` depends on; adds 69 test cases; ... |

**Intent check:** not stated · **Boundary rules:** no new violations

The headline

The number of meaning-level changes (rows), how many need a person, and the size of the text diff: lines added plus removed, and files changed. When nothing changed in meaning (only formatting, comments or moved files), the headline says "no changes in meaning".

The rows

Each row is one change in meaning, computed from the code and described with a fixed template. Nothing in a row is generated by a language model.

  • ● or ○: ● means a person should look at this row. Onus marks a row this way when it is security-sensitive, breaking, a rules-of-the-game change (tests, CI, policies, onus.yaml, CODEOWNERS) or outside the stated intent.
  • Change: what happened, in one line.
  • Kind: the kind of change (onus help changes lists them all). "Outside stated intent · " is prepended when the row is an intent mismatch.
  • Why it matters: the consequence, with the facts behind it: who depends on the thing that changed, which labels apply, what data leaves the system.

Order

Rows are ranked so the one that deserves attention comes first. Changes outside the stated intent come first, then every row that needs a person (●), then the rest; within each of those, by kind:

  1. changes outside the stated intent
  2. security-sensitive changes
  3. breaking changes (including boundary-rule violations)
  4. new or changed dependencies
  5. rules of the game (tests weakened, CI, policies, onus.yaml)
  6. configuration
  7. additive contract changes
  8. new relationships (events, data, components)
  9. tests
  10. notable internal edits, then renames, then the internal rows
Within a group, rows Onus is unsure about come first (unknowns count as higher risk), then rows with changed lines no test ran (with coverage), then rows in components with sensitivity labels, then rows with a larger blast radius (more dependent files).

Internal rows

Every row lists the lines it explains. The changed lines no row explains collapse into one internal row per component, such as "1,402 lines of new code and tests inside notifications". Its "why" says whether other components depend on that component, how many test cases were added, which new config keys are read, and whether some of the code could not be resolved.

Intent check and boundary rules

  • Intent check: "not stated" when no intent was given, "matches stated intent", or the number of changes outside it, followed by the reason for each. See onus help intent.
  • Boundary rules: "none declared", "no new violations", or the number of new violations. Violations that already existed before the change are not reported.

Evidence

The collapsed "Evidence per row" section lists, for each row, its kind and subkind, confidence, labels, blast radius, how many other components use what it changed ("used by 3 other components"), whether tests reach its code ("tested", "traced, not tested" or "untested"), with coverage how many of its changed lines tests ran ("tests ran 3 of 5 changed lines"), novelty and line counts, and every file and line behind it. Lines marked "(before the change)" are in the base tree, for example a deleted assertion.

Tests ran

With coverage of the head (--coverage, or --evidence with runs an environment recorded at the head commit; onus help environments), the intent line gains a third part:

**Intent check:** matches stated intent · **Boundary rules:** no new violations · **Tests ran:** 34 of 40 changed lines (85%)

A changed line is an added or edited head line the coverage counts as executable. "no changed executable lines" means the change touched none in the files the coverage measured, and no changed file with runtime code was left out of it. When one was, the line says so ("no measured changed lines; 1 changed file not in the coverage"), and so does the summary of the section below. A collapsed "Changed lines no test ran" section then lists those lines by file, the changed files with runtime code the coverage does not include ("not in the coverage (no test loaded it)"), what was left out and why, and each coverage file with its format and origin (supplied or recorded). The percentage is rounded down, so 100% means every changed line ran.

Without coverage the report is exactly as before.

Behavior

With onus report --behavior, the tests that reach the change run at the base and at the head (onus help environments). A line under the intent line says what ran:

**Behavior:** 3 test files run at base and head (selected from the map) · 1 changed, 0 newly failing · 48s of 600s

It says "no tests reach the changed code" when the maps link no test to it, **partial:** with the reason when the budget ran out or a run failed, and skipped: with the reason when nothing ran. A collapsed "Behavior runs" section lists each run with its cases, failures and manifest, the selected test files and why each was chosen, and the cases already failing at the base or found flaky.

What the runs showed becomes rows, one per kind and component, with level behavior and confidence traced (observed at runtime):

SubkindWhenKindEffect
behavior-newly-failingA case passes at the base and fails at the head, and again when run once more; or a new case fails at the headBehavior change, tests fail●; blocked until a person approves the row (/onus approve <row id>)
behavior-changedThe base version of an edited test passes at the base but fails against the head's code, and the head's version passes: the test was edited to match new behaviorBehavior change, tests updated●; rules of the game, so a person reviews it
behavior-newly-passingA case fails at the base and passes at the headBehavior change, fixnone
behavior-output-changedA case fails at both, with a different messageBehavior change, outputnone
Messages are compared without colours, durations, addresses or the environment's /work/ path, and the row quotes the failure. A newly failing case that was not run again (the budget ran out) has confidence inferred and says so. A case that disappears at the head is left to "Tests weakened".

Without --behavior the report is exactly as before.

Structure only

Files that moved without changes, and files whose only changes are formatting, comments or updated import paths, are listed here instead of as rows.

Map confidence notes

Code in the changed files that Onus could not resolve statically: dynamic imports, calls through computed members, event names computed at runtime, unresolved imports. Rows touching these files are marked low confidence. See onus help troubleshooting.

The JSON report

--format json gives everything in the Markdown and more (schemas/semantic-report.schema.json):

  • summary: counts of rows, rows needing attention, secrets, new rule violations and intent mismatches.
  • changes: the ranked rows. Each has an id, kind, subkind, level (relationship, behavior or structure), subject (the map id it is about), component, title, whyItMatters, hints (labels, blastRadius, novelty, confidence, rulesOfTheGame, intentMismatch, needsPerson, dependentComponents, dependents when there are any, tested for rows that change code, owners when the component has owners, and coverage {changed, ran} when coverage was given and the row changes executable lines), locations (file, lines, side) and, for internal rows, stats.
  • intentCheck, ruleViolations, structure, textStats and mapDiagnostics.
  • behavior, only with --behavior: status (complete, partial or skipped), reason, the command template, budgetSecs and elapsedSecs, selected (each test file with changed, depth, via, and whether it exists at the base and head), truncated, runs (side base, head, retry or cross, commit, files, the evidence manifest, exitCode, timedOut, cases, failed, skipped), flaky and alreadyFailing (file › case).
  • coverage, only with coverage: sources (format, path, sha256, origin, the evidence manifest and its run's command when recorded, files matched and not), changed, ran, notRun (head-side locations), notMeasured (changed files) and notes.
Output is deterministic: the same two trees always give byte-identical Markdown and JSON, with no timestamps or absolute paths. A coverage file is named by its path relative to the working directory, or as given when it is outside it.

The head's map

onus report --head-map-out <file> also writes the head ref's map (schemas/codebase-map.schema.json), built with the same onus.yaml as the report. It is the map every row was computed against, so the two always agree, and it holds the traces and coverage the report was given. Ask it questions with onus query --map <file>, such as what depends on a contract a row names. Onus Cloud keeps this map for the newest head of each pull request it analyses (onus help cloud).