docs: trim the README and split usage, resolution and development out #6

Merged
trevon merged 2 commits from docs/readme-split into main 2026-09-25 02:54:21 +00:00
4 changed files with 316 additions and 251 deletions

298
README.md
View file

@ -1,256 +1,70 @@
# Brick # Brick
Brick builds an evidence-aware visual representation of a codebase. Directories Brick turns a repository into an evidence-aware map of its structure.
become compounds, files become rooms, classes/functions become structural Directories become compounds, files become rooms, classes and functions become
elements, and dependency edges show calls, imports, and inheritance. The same elements, and edges show calls, imports and inheritance. The same model is
model is emitted as versioned JSON for other tools, including a future Fold written as versioned JSON for other tools and rendered as an interactive HTML
integration. graph.
The default extractor uses pinned Tree-sitter grammars for Rust, Dart, C Every edge keeps its evidence: lane, backend, confidence and source location.
(`.c`), C++ (including headers), JavaScript/JSX, and TypeScript/TSX. Python and Swift retain the lexical preview; Declarations are **Syntactic**; call, import and inheritance targets are
P4_16 retains its separate lexical and optional pilot paths. Declarations are **Heuristic**; findings from Fold or p4c are **Imported** (Fold's own proofs keep
Syntactic evidence. Calls, imports, and inheritance retain Heuristic target their **Symbolic** lane). Nothing is promoted to a stronger lane than its
resolution with backend, confidence, and source location, independently of evidence supports, and every unresolved call records why.
imported symbolic evidence.
## Languages
| Language | Frontend |
| --- | --- |
| Rust, Dart, C (`.c`), C++ (with headers), JavaScript/JSX, TypeScript/TSX | pinned Tree-sitter grammars |
| Python, Swift | lexical preview |
| P4_16 | lexical preview; optional Tree-sitter pilot |
How names resolve in each, and where they do not, is in
[docs/resolution.md](docs/resolution.md). Read the graph with its reported
call-site coverage in mind: on a large C++ repository only a minority of call
sites resolve.
## Quick start ## Quick start
cargo run -- build ../fold --json fold.brick.json --html fold.brick.html ```bash
cargo run -- build ../fold --json fold.brick.json --html fold.brick.html
cargo run -- build ../yams --exclude site --exclude build \
--json yams.brick.json --html yams.brick.html
```
Exclude generated or checked-in output by exact directory component (repeatable): Open the HTML in a browser. `build` prints diagnostic counts, and a scan that
finds no supported source says so.
cargo run -- build ../yams --exclude site --exclude build \ ## Commands
--json yams.brick.json --html yams.brick.html
Scans skip file and directory symlinks with repository-relative diagnostics. | Command | What it does |
This prevents outside-root traversal, cycles, and duplicate aliases. | --- | --- |
| `brick build <repo>` | Scan a repository; write JSON and HTML. Can layer Fold/SARIF or p4c findings onto the graph. |
| `brick render <model.json>` | Render an existing model to HTML. |
| `brick check <model.json>` | Gate on the structural score, cycles, a baseline diff, or a dependency policy. Metrics are recomputed from the graph, never trusted from the file. |
| `brick mcp <model.json>` | Serve read-only MCP queries: impact, cycles, bridges, evidence, and caller status (is a function called, unknown, or unreferenced). |
| `brick setup` | Report which optional frontends this binary can initialize. |
Layer Fold findings onto the building: Full usage, including the import contracts: [docs/usage.md](docs/usage.md).
cargo run -- build ../fold \ ## Limits
--fold-report ../fold/build/findings.json \
--json fold.brick.json \
--html fold.brick.html
A report must be a SARIF log or a Fold findings report; anything else is an Brick reads syntax, not compiler output: no type checking, build configuration,
error. Findings keep Fold's symbolic lane only when the report names Fold as its macro expansion, overload resolution or dynamic dispatch. The structural score
producer (`tool.name` / `tool.driver.name`); other producers' findings are is an experimental composite, not proof of correctness, maintainability or
imported, never symbolic. Findings without a file location are diagnosed, and security; use the component metrics and evidence, and do not rank teams or
SARIF `file://` URIs are decoded before matching. repositories by the score alone.
Fold artifact paths are normalized lexically across `/`, `\\`, `.`, and `..` ## Documentation
components before exact repository-relative matching; a path with `..` that
exists in this checkout follows the filesystem instead, so `link/..` resolves
through the symlink. Absolute paths are
accepted only beneath the model's scan root (including existing filesystem
aliases whose canonical targets are beneath that root); leading traversal and unrelated
suffix paths remain diagnostics. Findings for excluded, generated, or genuinely
missing files are never attached to a neighboring source file.
Layer a qualified p4c v1.2.5.16 regression diagnostic envelope onto P4 - [Usage](docs/usage.md): every command, Fold/SARIF and p4c imports, the P4
structure: pilot, diffs and policies.
- [Resolution](docs/resolution.md): per-language name resolution, limits,
cargo run -- build tests/fixtures/p4c \ schema versions.
--p4c-report tests/fixtures/p4c/reports/p4c-1.2.5.16-duplicate-state.json \ - [Development](docs/development.md): building, tests, the quality gate, the
--json p4c.brick.json --html p4c.brick.html agent skill.
- Architecture: [graph model](docs/architecture/graph-model.md),
The p4c bridge is tool/version/mode-specific and its evidence is Imported, not [structural diff](docs/architecture/structural-diff.md),
Symbolic. See `docs/architecture/p4-evidence.md` for the envelope contract and [policy](docs/architecture/policy.md), [MCP](docs/architecture/mcp.md),
real upstream fixture provenance. [P4 evidence](docs/architecture/p4-evidence.md); [roadmap](docs/ROADMAP.md).
Detect whether this Brick binary can initialize the pinned Tree-sitter P4
pilot before selecting it:
cargo run -- setup --json
cargo run --features tree-sitter-p4-pilot -- \
setup --require-tree-sitter-p4-pilot
The versioned setup report distinguishes an unavailable compile-time feature
from a usable parser. The `--require-tree-sitter-p4-pilot` form fails closed,
which makes it suitable for installation and CI setup steps.
Run the default-disabled Tree-sitter P4 pilot as an augmentation to lexical
extraction:
cargo run --features tree-sitter-p4-pilot -- build tests/fixtures/p4_tree_sitter \
--p4-frontend tree-sitter-pilot \
--json p4-pilot.brick.json --html p4-pilot.brick.html
Tree-sitter matches remain Syntactic and name-index resolution remains
Heuristic. The lexical pass still runs. See
`docs/research/tree-sitter-p4-pilot.md` for the pin, measured result, limits,
and decision not to promote the pilot to the default frontend.
Render an existing model or enforce an explicit experimental gate:
cargo run -- render fold.brick.json --html fold.brick.html
cargo run -- check fold.brick.json --min-score 70 --max-cycles 5
Compare a compatible baseline by stable IDs while retaining the existing gate:
cargo run -- check current.brick.json --min-score 70 \
--baseline baseline.brick.json --diff-json structural-diff.json \
--max-removed-nodes 0 --max-changed-edges 5
Diff gates are unlimited unless explicitly set. Models with different schemas,
roots, repository identities, exclusions, or P4 frontends are rejected by default.
For corresponding checkouts, add `--allow-root-relocation` to explicitly assert
root equivalence. This relaxes only the root check, works with saved artifacts,
and records both roots and the policy in diff schema 2. Repository display-name
and imported provenance changes remain visible. See
`docs/architecture/structural-diff.md` for the versioned diff contract.
Apply a versioned repository-relative dependency policy through the same gate:
cargo run -- check current.brick.json --min-score 70 \
--policy architecture-policy.json \
--policy-result-json policy-result.json
Unknown policy keys/kinds and scope mismatches fail closed. Matched edges retain
complete evidence. See `docs/architecture/policy.md`.
Serve read-only MCP queries over a validated, versioned model:
cargo run -- mcp current.brick.json
The four tools cover dependency/dependent impact, SCC cycles, weak-graph
bridges, and complete node/edge evidence inspection. They do not scan, mutate,
or render. See `docs/architecture/mcp.md` for protocol and query semantics.
Open the generated HTML in a browser. It loads Cytoscape.js from unpkg by
default; an internal or vendored URL can be supplied with --cytoscape-url.
## What v0.1 provides
- A deterministic schema for repository, directory, file, class, function,
external dependency, and Fold finding nodes.
- Contains, defines, calls, imports, inherits, and flags edges.
- Deterministically ordered per-edge evidence records retaining lane, backend,
producer-local confidence, and provenance.
- SCC-based cycle counts, unresolved references, isolation, fan-in/fan-out, and
an inspectable experimental structural-health composite.
- An interactive compound graph with layout switching, dependency focus, and
node/edge inspection.
- Fold native findings-json and SARIF ingestion without collapsing backend or
confidence.
- P4_16 headers, structs, parsers, controls, tables, actions, states, includes,
parser transitions, table apply calls, and scoped action calls with explicit
domain attributes.
- A fail-closed p4c v1.2.5.16 diagnostic-envelope bridge that preserves raw
identity and attaches Imported evidence to the narrowest resolvable entity.
- Explicit P4 structural metrics for parser-state and control/apply cycles,
unreachable parser states, and unresolved P4 dependencies without treating
any observation as verifier proof.
- A default-disabled, pinned Tree-sitter P4 pilot that adds parallel Syntactic
declaration evidence and control-scoped table-action relationships without
replacing lexical or imported evidence, plus a versioned setup probe that
detects whether the compiled binary can initialize it.
- Deterministic stable-ID structural diff JSON with complete before/after
evidence and optional count gates integrated into `brick check`.
- Versioned declarative repository-relative dependency policies evaluated by
the same `brick check` gate with complete matched-edge evidence.
- A thin read-only MCP 2025-06-18 stdio surface for impact, cycles, bridges, and
evidence inspection over validated Brick JSON.
- A focused Rust test suite, quality gate, bounded auto-loop, and artifact-based
benchmark runner.
## Important limits
Brick extracts syntax, without compiler type checking or build configuration.
Macro expansion, overload resolution, dynamic dispatch, generated code, and
full package/build-system resolution remain outside the default frontend.
Malformed syntax produces diagnostics; recoverable sibling facts remain visible.
A file with invalid UTF-8 is decoded lossily with a diagnostic; files with NUL
bytes are skipped as binary. `build` prints diagnostic counts, and a scan that
finds no supported source says so. `check` recomputes metrics from the graph
(stored metrics are never trusted) and fails a model with no scanned source.
Its score is not proof of correctness, maintainability,
or security. Use the component metrics and evidence records; do not rank teams
or repositories by the composite alone.
Grammar-based resolution respects language, file, declaration ownership, and
lexical namespace. Relative JS/TS and Dart imports resolve against the importing
directory (Dart `package:<own package>/` against `lib/`); missing paths never
fall back to unrelated basenames. Explicit JS/TS named/default import bindings,
module-scoped Rust grouped/aliased imports, module-qualified Rust public calls,
and public top-level Dart names from imported libraries can resolve across files
(Dart `show`/`hide` combinators are not modelled). The lexical preview resolves
Python names in the calling file, then in files it imports; Swift names in the
calling file, then by a module-wide unique name (Swift files of one module see
each other without imports).
C++ calls resolve through the include closure: a header prototype pairs with
its definition in another translation unit, lookup walks class (including
in-repository bases) and namespace scopes outward, and `static`/anonymous
definitions stay file-local. Declarations in `#elif`/`#else` branches stay in
the graph (`source.preprocessor-branch: alternative`) but are never call
targets, because Brick does not evaluate conditions; several `using`
directives that nominate different declarations make a call ambiguous. C++ and
Rust member calls resolve only through an explicitly declared receiver type
(parameter, local, field, `this`/`self`, smart pointer, or `Self`-returning
constructor) and carry `source.resolution`. Rust types are identified by their
declaring file, so same-named types in different modules resolve through the
caller's `use` binding or stay ambiguous. Calls inside Rust expression macros (`assert!`, `format!`,
`vec!`, ...) are recovered by re-parsing and carry `source.extraction`.
Every unresolved call edge records `source.unresolved-reason`, and
`metrics.resolution` reports per-language call-site coverage; read the graph
with that coverage in mind (on a large C++ repository only a minority of call
sites resolve). Ambiguous targets stay external. Virtual calls resolve to the
declared type's method only (overrides are not fanned out), and Catch2
`TEST_CASE` bodies are not yet recognized as functions. Bare package specifiers, tsconfig aliases, Rust
wildcard/block-local binding expansion, Cargo workspace module paths,
`compile_commands.json` include paths, and compiler-grade dispatch need further
adapters. File fan-out remains an observation rather
than proof of semantic coupling. Scope architecture gates to production paths
and verify candidates against source and tests.
The source-language regression corpus checks exact declarations, owners, and
dependencies across six language strata, including clean-negative files. Its
three-repeat benchmark runs in the quality gate. These labeled cases establish
the covered behaviors, not language-wide accuracy. See
`docs/research/language-correctness.md` for the acceptance evidence and limits,
and `docs/research/cpp-rust-resolution.md` for C/C++ and Rust resolution and the
agent-facing caller-status contract.
P4 extraction is a conservative P4_16 lexical preview, not a p4c frontend.
The optional Tree-sitter pilot does not preprocess macros and rejects all pilot
facts from a file when its parse has error or missing nodes. It is not the
default frontend. Implicit terminal states are modeled only when referenced.
Parser transitions
and control/action calls use scoped lexical resolution; unresolved targets stay
external. P4_14, macro expansion, architecture type checking, compiler IR, and
formal-verifier evidence require separate adapters. P4V, `p4-symbolic`, bf4,
and P4K adapters remain disabled until a real versioned machine-readable result
contract and explicit bounded-model semantics are qualified.
Schema version 4 stores scan scope (including the selected P4 frontend),
parallel relationship evidence, and a nested `metrics.p4` contract. Version-1
through version-3 JSON are rejected by CLI consumers rather than guessed;
rebuild old artifacts before rendering or checking them.
The next serious analyzer milestone should consume compiler/YAMS/Fold graph
facts through adapters while retaining the standalone lexical lane as a fast
preview. See docs/architecture/graph-model.md and docs/ROADMAP.md.
## Development
cargo fmt --check
cargo test
cargo clippy --all-targets -- -D warnings
./scripts/quality-gate.sh
python3 tests/benchmarks/runner.py self-test
Repository workflow is in AGENTS.md and docs/prompts.
Brick pins `nightly-2026-05-28` in `rust-toolchain.toml`, matching Fold's Rust
analyzer. Rustup selects it automatically for Cargo, rustfmt, and Clippy commands
run inside this repository.
## Agent skill
The evidence-aware architecture review workflow lives in
`skills/brick-sast/`. It includes a deterministic JSON summary helper and a
review reference that keeps graph observations separate from source-verified
architectural conclusions. Validate the package with:
env UV_CACHE_DIR=/private/tmp/brick-uv-cache uv run --with pyyaml \
python /path/to/skill-creator/scripts/quick_validate.py skills/brick-sast

30
docs/development.md Normal file
View file

@ -0,0 +1,30 @@
# Development
```bash
cargo fmt --check
cargo test
cargo clippy --all-targets -- -D warnings
./scripts/quality-gate.sh
python3 tests/benchmarks/runner.py self-test
```
`scripts/quality-gate.sh` runs formatting, Clippy with warnings as errors, the
tests with and without the P4 pilot feature, the Python unit tests, and the
benchmark self-tests and runs. The repository workflow is in `AGENTS.md` and
`docs/prompts/`.
Brick pins `nightly-2026-05-28` in `rust-toolchain.toml`, matching Fold's Rust
analyzer; rustup selects it automatically for Cargo, rustfmt and Clippy inside
this repository.
## Agent skill
The evidence-aware architecture review workflow lives in `skills/brick-sast/`.
It includes a deterministic JSON summary helper and a review reference that
keeps graph observations separate from source-verified architectural
conclusions. Validate the package with:
```bash
env UV_CACHE_DIR=/private/tmp/brick-uv-cache uv run --with pyyaml \
python /path/to/skill-creator/scripts/quick_validate.py skills/brick-sast
```

84
docs/resolution.md Normal file
View file

@ -0,0 +1,84 @@
# Resolution and limits
Brick extracts syntax, without compiler type checking or build configuration.
Macro expansion, overload resolution, dynamic dispatch, generated code and full
package/build-system resolution are outside the default frontend. Malformed
syntax produces diagnostics; recoverable sibling facts stay visible.
Every unresolved call edge records `source.unresolved-reason`, resolved member
calls carry `source.resolution`, and `metrics.resolution` reports per-language
call-site coverage. Ambiguous targets stay external. Read the graph with that
coverage in mind: on a large C++ repository only a minority of call sites
resolve. File fan-out is an observation, not proof of semantic coupling; scope
architecture gates to production paths and verify candidates against source and
tests.
## Per language
- **All grammar-based languages:** resolution respects language, file,
declaration ownership and lexical namespace.
- **JavaScript/TypeScript:** relative imports resolve against the importing
directory, and missing paths never fall back to unrelated basenames. Explicit
named and default import bindings resolve across files.
- **Dart:** relative imports resolve against the importing directory, and
`package:<own package>/` against `lib/`. Public top-level names from imported
libraries resolve across files; `show`/`hide` combinators are not modelled.
- **Rust:** module-scoped grouped and aliased imports and module-qualified public
calls resolve. Types are identified by their declaring file, so same-named
types in different modules resolve through the caller's `use` binding or stay
ambiguous. Calls inside expression macros (`assert!`, `format!`, `vec!`, ...)
are recovered by re-parsing and carry `source.extraction`.
- **C and C++:** calls resolve through the include closure. A header prototype
pairs with its definition in another translation unit, lookup walks class
(including in-repository bases) and namespace scopes outward, and
`static`/anonymous definitions stay file-local. Declarations in `#elif`/`#else`
branches stay in the graph (`source.preprocessor-branch: alternative`) but are
never call targets, because Brick does not evaluate conditions. Several
`using` directives that nominate different declarations make a call
ambiguous. Virtual calls resolve to the declared type's method only
(overrides are not fanned out), and Catch2 `TEST_CASE` bodies are not yet
recognized as functions. `.c` files use the C grammar.
- **C++ and Rust member calls** resolve only through an explicitly declared
receiver type: a parameter, local, field, `this`/`self`, smart pointer, or a
`Self`-returning constructor.
- **Python (lexical preview):** names resolve in the calling file, then in files
it imports.
- **Swift (lexical preview):** names resolve in the calling file, then by a
module-wide unique name, since Swift files of one module see each other
without imports.
Not yet handled, and needing further adapters: bare package specifiers,
tsconfig aliases, Rust wildcard and block-local binding expansion, Cargo
workspace module paths, `compile_commands.json` include paths, and
compiler-grade dispatch.
## P4
P4 extraction is a conservative P4_16 lexical preview, not a p4c frontend.
Implicit terminal states are modelled only when referenced. Parser transitions
and control/action calls use scoped lexical resolution; unresolved targets stay
external. The optional Tree-sitter pilot does not preprocess macros and rejects
all pilot facts from a file whose parse has error or missing nodes. P4_14, macro
expansion, architecture type checking, compiler IR and formal-verifier evidence
need separate adapters; P4V, `p4-symbolic`, bf4 and P4K adapters stay disabled
until a real versioned machine-readable result contract and explicit
bounded-model semantics are qualified.
## Evidence for these rules
The source-language regression corpus checks exact declarations, owners and
dependencies across six language strata, including clean-negative files; its
three-repeat benchmark runs in the quality gate. These labelled cases establish
the covered behaviours, not language-wide accuracy. See
[language correctness](research/language-correctness.md), and
[C/C++ and Rust resolution](research/cpp-rust-resolution.md) for that
resolver's research, validation and the agent-facing caller-status contract.
## Schema
Schema version 4 stores scan scope (including the selected P4 frontend),
parallel relationship evidence and a nested `metrics.p4` contract. CLI consumers
reject version 1-3 JSON rather than guess; rebuild old artifacts before
rendering or checking them. Consuming compiler, YAMS and Fold graph facts
through adapters, while keeping the lexical lane as a fast preview, is on the
[roadmap](ROADMAP.md); see also the [graph model](architecture/graph-model.md).

137
docs/usage.md Normal file
View file

@ -0,0 +1,137 @@
# Usage
## build
```bash
cargo run -- build ../fold --json fold.brick.json --html fold.brick.html
cargo run -- build ../yams --exclude site --exclude build \
--json yams.brick.json --html yams.brick.html
```
`--exclude` drops generated or checked-in output by exact directory component
(repeatable). File and directory symlinks are skipped with repository-relative
diagnostics, which prevents outside-root traversal, cycles and duplicate
aliases. A file with invalid UTF-8 is decoded lossily with a diagnostic; files
with NUL bytes are skipped as binary. `build` prints diagnostic counts, and a
scan that finds no supported source says so.
The HTML loads Cytoscape.js from unpkg by default; pass `--cytoscape-url` for an
internal or vendored copy.
### Layering Fold findings
```bash
cargo run -- build ../fold --fold-report ../fold/build/findings.json \
--json fold.brick.json --html fold.brick.html
```
A report must be a SARIF log or a Fold findings report; anything else is an
error. Findings keep Fold's Symbolic lane only when the report names Fold as its
producer (`tool.name` / `tool.driver.name`); other producers' findings are
Imported, never Symbolic. Findings without a file location are diagnosed, and
SARIF `file://` URIs are decoded before matching.
Paths are normalized lexically across `/`, `\`, `.` and `..` before exact
repository-relative matching; a path with `..` that exists in this checkout
follows the filesystem instead, so `link/..` resolves through the symlink.
Absolute paths are accepted only beneath the scan root (including filesystem
aliases whose canonical targets are beneath it); leading traversal and
unrelated suffix paths stay diagnostics. Findings for excluded, generated or
missing files are never attached to a neighbouring file.
### Layering p4c diagnostics
```bash
cargo run -- build tests/fixtures/p4c \
--p4c-report tests/fixtures/p4c/reports/p4c-1.2.5.16-duplicate-state.json \
--json p4c.brick.json --html p4c.brick.html
```
The bridge accepts a qualified p4c v1.2.5.16 regression diagnostic envelope. It
is tool/version/mode-specific, fails closed, and its evidence is Imported, not
Symbolic. See [P4 evidence](architecture/p4-evidence.md) for the envelope
contract and upstream fixture provenance.
### The Tree-sitter P4 pilot
```bash
cargo run -- setup --json
cargo run --features tree-sitter-p4-pilot -- setup --require-tree-sitter-p4-pilot
cargo run --features tree-sitter-p4-pilot -- build tests/fixtures/p4_tree_sitter \
--p4-frontend tree-sitter-pilot --json p4-pilot.brick.json --html p4-pilot.brick.html
```
`setup` reports whether the compiled binary can initialize the pilot; the
`--require-...` form fails closed, for install and CI steps. The pilot is
default-disabled and augments the lexical pass, which still runs: its matches
stay Syntactic and name-index resolution stays Heuristic. See
[the pilot study](research/tree-sitter-p4-pilot.md) for the pin, measured
result, limits, and the decision not to make it the default.
## render
```bash
cargo run -- render fold.brick.json --html fold.brick.html
```
## check
```bash
cargo run -- check fold.brick.json --min-score 70 --max-cycles 5
```
`check` recomputes metrics from the graph (stored metrics are never trusted)
and fails a model with no scanned source.
Compare against a compatible baseline by stable IDs:
```bash
cargo run -- check current.brick.json --min-score 70 \
--baseline baseline.brick.json --diff-json structural-diff.json \
--max-removed-nodes 0 --max-changed-edges 5
```
Diff gates are unlimited unless set. Models with different schemas, roots,
repository identities, exclusions or P4 frontends are rejected by default; for
corresponding checkouts, `--allow-root-relocation` asserts root equivalence. It
relaxes only the root check, works with saved artifacts, and records both roots
and the policy in diff schema 2. Repository display-name and imported
provenance changes stay visible. See [structural diff](architecture/structural-diff.md).
Apply a versioned repository-relative dependency policy through the same gate:
```bash
cargo run -- check current.brick.json --min-score 70 \
--policy architecture-policy.json --policy-result-json policy-result.json
```
Unknown policy keys and kinds, and scope mismatches, fail closed. Matched edges
keep their complete evidence. See [policy](architecture/policy.md).
## mcp
```bash
cargo run -- mcp current.brick.json
```
A read-only MCP 2025-06-18 stdio server over a validated model. Its six tools
cover dependency/dependent impact, SCC cycles, weak-graph bridges, complete
node/edge evidence inspection, and caller status: `brick_callers` reports
whether a function is `resolved`, `unknown` (with the reasons callers may
exist) or `unreferenced`, and `brick_uncalled` lists unreferenced functions per
language. Unreferenced is a review candidate, never proof of dead code. The
tools never scan, mutate or render. See [MCP](architecture/mcp.md).
## What the model contains
- Repository, directory, file, class, function, external-dependency and Fold
finding nodes; contains, defines, calls, imports, inherits and flags edges.
- Deterministically ordered per-edge evidence: lane, backend, producer-local
confidence, provenance.
- SCC cycle counts, unresolved references, isolation, fan-in/fan-out, per-language
call-site coverage (`metrics.resolution`) and the experimental structural-health
composite.
- For P4_16: headers, structs, parsers, controls, tables, actions, states,
includes, parser transitions, table apply calls and scoped action calls, with
parser-state and control/apply cycle, unreachable-state and unresolved metrics
that are observations, not verifier proof.