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 violationsThe 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 changeslists 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:
- changes outside the stated intent
- security-sensitive changes
- breaking changes (including boundary-rule violations)
- new or changed dependencies
- rules of the game (tests weakened, CI, policies, onus.yaml)
- configuration
- additive contract changes
- new relationships (events, data, components)
- tests
- notable internal edits, then renames, then the internal rows
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 600sIt 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):
| Subkind | When | Kind | Effect |
|---|---|---|---|
behavior-newly-failing | A case passes at the base and fails at the head, and again when run once more; or a new case fails at the head | Behavior change, tests fail | ●; blocked until a person approves the row (/onus approve <row id>) |
behavior-changed | The 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 behavior | Behavior change, tests updated | ●; rules of the game, so a person reviews it |
behavior-newly-passing | A case fails at the base and passes at the head | Behavior change, fix | none |
behavior-output-changed | A case fails at both, with a different message | Behavior change, output | none |
/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 anid,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,dependentswhen there are any,testedfor rows that change code,ownerswhen the component has owners, andcoverage{changed, ran}when coverage was given and the row changes executable lines),locations(file, lines, side) and, for internal rows,stats.intentCheck,ruleViolations,structure,textStatsandmapDiagnostics.behavior, only with--behavior:status(complete,partialorskipped),reason, thecommandtemplate,budgetSecsandelapsedSecs,selected(each test file withchanged,depth,via, and whether it exists at thebaseandhead),truncated,runs(sidebase,head,retryorcross,commit,files, the evidencemanifest,exitCode,timedOut,cases,failed,skipped),flakyandalreadyFailing(file › case).coverage, only with coverage:sources(format, path, sha256, origin, the evidencemanifestand its run'scommandwhen recorded, files matched and not),changed,ran,notRun(head-side locations),notMeasured(changed files) andnotes.
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).