ovecc architecture diff
The reflexion report between the contract and the stored graph, in the Murphy/Notkin/Sullivan vocabulary: what you declared, what the code actually does, and every place the two disagree.
Usage: ovecc architecture diff [OPTIONS]
The contract file is re-read on every run and judged against the persisted graph, so
editing architecture.toml never requires re-indexing. The same findings also land in
violations and gate at each
ovecc index.
Example
$ ovecc architecture diff
Architecture contract: 13 components, 25/25 declared dependencies implemented, mode new-violations
Files outside every component (1):
[Low] 1 file(s) belong to no component
npm/ovecc/bin/ovecc.js
Components that change together without depending on each other (2):
[Low] graph and parser change together without depending on each other
crates/ovecc-graph/src/dupes.rs (with crates/ovecc-parser/src/tokenize.rs in 5 commits (6bb034a0, ccf12c8e, cb0c6e87, 386878d0, 7a029512))
crates/ovecc-graph/src/cycles.rs (with crates/ovecc-parser/src/tokenize.rs in 4 commits (6bb034a0, cb0c6e87, 386878d0, 7a029512))
3 finding(s).
Convergences:
db -> core (41 import(s))
graph -> core (14 import(s))
parser -> core (12 import(s))
rules -> core (30 import(s))
rules -> graph (1 import(s))
...
A breach names the file and the import behind it:
Divergences (1):
[High] cli -> parser is not in the contract
crates/ovecc-cli/src/render.rs:12 (ovecc_parser::outline)
The verdicts
| Verdict | Severity | Means |
|---|---|---|
| convergence | — | Declared and implemented, with the import count |
| divergence | High | An import the contract does not allow |
| forbidden dependency | High | An import a cannot_depend_on names outright |
| restricted access | High | An import of a component whose consumed_by does not admit it |
| required dependency | High | A file never makes a must_depend_on import |
| slice isolation | High | An import between sibling slices of a slices = true component |
| interface bypass | High | An import that skips a component's declared entry files |
| deprecated use | Medium | A dependency marked deprecated = true is still imported |
| external deny | Medium | An external package the contract bans |
| capability | Medium | A denied ambient capability, with the exact API and line |
| complexity budget | Medium | A function over the component's per-function ceiling |
| coverage floor | Medium | A component under its min_coverage |
| unassigned | Low / High | Files no component claims, per the unassigned policy |
| absence | Low | A declared edge no import implements (contract hygiene) |
restricted-access and forbidden-dependency replace the divergence the edge would
otherwise have been — a sharper answer, not an extra one.
mode = "warn" caps everything at Low, so nothing gates.
Behavioral coupling
One verdict reads no code at all. Behavioral coupling names two components the contract declares independent, that no import connects, whose files the history keeps changing in the same commits. No static analysis can see it: the only witness is the commits, and they come with the finding.
Two components must share at least two coupled file pairs before it is reported — one is an accident, and the honest exception is real (a version field every implementer of a protocol must bump).
It is Low by default, under every gate's threshold, because the deviation is a question for the reader. In the contract:
coupling = "medium" # or "high" — put it in the gate
coupling = "off" # stop reporting it
See coupling for the underlying file-pair signal.
Options
| Option | Effect |
|---|---|
--format json|markdown | Structured output for tooling or a PR comment |
Plus the global options.
Related
- The contract — every field these verdicts come from
architecture check— the same report, as a CI gate- Rules reference — each
architecture/*rule id