207 lines
11 KiB
Markdown
207 lines
11 KiB
Markdown
# Graph model
|
|
|
|
Brick separates analysis from presentation:
|
|
|
|
analyzers canonical model consumers
|
|
grammar / lexical -\
|
|
YAMS graph ----------> nodes + typed edges ----------> JSON
|
|
Fold source/binary --/ evidence + metrics --------> Cytoscape
|
|
future traces ---------------------------------------> Fold/MCP
|
|
|
|
## Compatibility
|
|
|
|
Schema version 4 makes evidence multiplicity, the selected P4 frontend in scan
|
|
scope, and the nested P4 metric contract reader-visible. Readers must reject unsupported schema versions
|
|
instead of guessing. Two models
|
|
are structurally comparable only when they have the same schema version,
|
|
canonical scan root, repository identity, and scan scope. The top-level `root`
|
|
is absolute execution provenance; comparing artifacts from different clones or
|
|
worktrees can opt into `--allow-root-relocation` for structural diffs. This caller
|
|
assertion relaxes only root equality and is recorded in diff schema 2 alongside
|
|
both original roots. It does not verify Git identity; the repository node ID is
|
|
graph-local, not a repository-origin fingerprint. See
|
|
[structural diff](structural-diff.md).
|
|
|
|
`scope.path` is normalized and repository-relative. Each
|
|
`scope.excluded_directories` value is one non-empty path component; the array is
|
|
sorted and deduplicated before serialization. Readers reject absolute,
|
|
drive-qualified, traversing, unsorted, duplicate, or empty scope values.
|
|
`scope.p4_frontend` is `lexical` or the
|
|
explicit `tree-sitter-p4-pilot`; models from those frontends are not comparable
|
|
because their graph coverage differs. Future scope fields must become part of
|
|
the compatibility check when they can change graph coverage. The top-level
|
|
`root` must be a normalized portable absolute path (`/repo`, `C:/repo`, or a
|
|
normalized UNC root); empty, relative, drive-relative, backslash, trailing
|
|
separator, traversal, and unnormalized Windows verbatim forms are rejected.
|
|
The scanner converts `\\?\C:\repo` to `C:/repo` and
|
|
`\\?\UNC\server\share` to `//server/share` before serialization.
|
|
|
|
Compatible buildings can be compared through the separate versioned structural
|
|
diff contract. It preserves complete added/removed facts and before/after
|
|
records for shared IDs whose content or evidence changed. See
|
|
`docs/architecture/structural-diff.md`. Versioned declarative boundary policy
|
|
is a separate consumer of canonical dependency edges and never changes their
|
|
kind or evidence; see `docs/architecture/policy.md`. The read-only MCP server is
|
|
another consumer: it validates schema-v4 JSON once, then exposes versioned
|
|
impact, cycle, bridge, and evidence queries without scanning or renderer
|
|
coupling; see `docs/architecture/mcp.md`.
|
|
|
|
## Nodes and identity
|
|
|
|
Exactly one Repository node is required; missing or ambiguous repository
|
|
identity fails schema validation. Duplicate node/edge IDs, cross-kind ID
|
|
collisions, dangling edge endpoints, and edges without evidence also fail
|
|
schema validation. Repository and directory nodes provide
|
|
compound layout. File, class, and
|
|
function nodes represent source structure. External nodes make unresolved
|
|
dependencies visible instead of dropping them. Finding nodes attach analyzer
|
|
evidence without changing structural identities.
|
|
|
|
IDs derive from kind plus repository-relative semantic identity. The repository
|
|
node uses `.` as its identity rather than the checkout directory name. Source
|
|
line is provenance, not identity. Extracted symbols use:
|
|
|
|
path + semantic owner ID + coarse kind + name + same-name ordinal
|
|
|
|
The ordinal distinguishes overload-like declarations within one owner. This
|
|
keeps IDs stable under unrelated line insertions, though inserting a same-name
|
|
declaration before another remains an explicit lexical limitation.
|
|
|
|
The default C++/JS/TS/Dart/Rust grammar extractor preserves this identity format
|
|
for unchanged declarations. Namespace/module scopes additionally contribute to
|
|
identity and appear in `attributes["source.scope"]`; ordinals are local to that
|
|
scope. Rust impl methods use their resolvable type as parent. Fixing a previously
|
|
incorrect owner intentionally changes the affected method ID. Unresolved targets
|
|
in these languages include source, language, and scope in identity so unrelated
|
|
unknowns cannot merge. Legacy Python/Swift/P4 identities remain unchanged.
|
|
|
|
`source.exports` records syntax-level export names; it does not assert that a
|
|
module is reachable under a particular build configuration. Parameter-bound calls
|
|
retain `source.unresolved-reason` instead of resolving to a same-named function.
|
|
Grammar version and extraction revision live in evidence backend strings.
|
|
Schema 4 remains sufficient: consumers use the same node/edge kinds and evidence
|
|
contract, with optional opaque attributes. Rebuild baselines when adopting the
|
|
new extractor so corrected coverage is not mistaken for a source-code change.
|
|
|
|
P4 support initially retains the coarse display kind only when the exact domain
|
|
kind is also present in node attributes:
|
|
|
|
domain = "p4"
|
|
p4.kind = "header" | "header-union" | "struct" | "parser" |
|
|
"control" | "table" | "action" | "state" | "extern" |
|
|
"terminal-state" | "unresolved"
|
|
p4.dialect = "p4-16"
|
|
|
|
An architecture attribute is added only when an explicit source or imported
|
|
contract supplies it; the lexical scanner does not infer v1model from familiar
|
|
shapes. Parser states and other nested entities use their semantic owner as `parent`.
|
|
A consumer must not infer P4 semantics from `class` or `function` alone.
|
|
|
|
## Edges and evidence
|
|
|
|
Contains and defines describe hierarchy. Calls, imports, and inherits describe
|
|
dependencies and participate in the current SCC/coupling metrics. Flags attaches
|
|
analysis evidence and does not affect the structural score.
|
|
|
|
An edge has a stable relationship identity, optional attributes, and an ordered
|
|
`evidence` array. The relationship is deduplicated by `(source, target, kind)`;
|
|
independent call sites and backends add evidence records rather than replacing
|
|
one another. Evidence ordering is deterministic by lane, backend, provenance,
|
|
and confidence.
|
|
|
|
P4 relationships retain their exact domain meaning in edge attributes even
|
|
when a coarse edge kind is used:
|
|
|
|
domain = "p4"
|
|
p4.relation = "direct-transition" | "select-transition" |
|
|
"select-default" | "apply" | "action-call" |
|
|
"table-action" | "include" | "compiler-diagnostic"
|
|
|
|
Every evidence record has:
|
|
|
|
- lane: syntactic, symbolic, imported, or heuristic;
|
|
- backend: producer and mode;
|
|
- confidence: a producer-local numeric score, categorical label, or `null` when
|
|
the producer did not supply one;
|
|
- provenance: source location or report artifact.
|
|
|
|
Confidence labels from different producers are not calibrated probabilities.
|
|
Missing or unknown imported values remain unknown or produce diagnostics; they
|
|
must not be mapped to a convenient backend, lane, or scalar.
|
|
|
|
## Lane classification
|
|
|
|
| Fact | Lane |
|
|
| --- | --- |
|
|
| Filesystem containment or declaration syntax | Syntactic |
|
|
| Lexical/tree-sitter target resolution without compiler proof | Heuristic |
|
|
| External analyzer diagnostic | Imported |
|
|
| Result proved within a named bounded model | Symbolic |
|
|
|
|
A syntactic call expression, heuristic target resolution, imported diagnostic,
|
|
and bounded symbolic fact may all support the same relationship. Name
|
|
resolution never upgrades existing evidence confidence or lane.
|
|
|
|
## Health indicator
|
|
|
|
The v0.1 score remains deliberately transparent:
|
|
|
|
| Component | Weight | Meaning |
|
|
| --- | ---: | --- |
|
|
| Acyclicity | 35% | Fraction of symbols outside cyclic SCCs |
|
|
| Resolution | 25% | Dependency edges not ending at external nodes |
|
|
| Connectedness | 25% | Symbols participating in dependencies |
|
|
| Concentration | 15% | Penalty for one target dominating fan-in |
|
|
|
|
The score is experimental. It is a navigation aid, not an architectural quality
|
|
oracle. Future weights require labeled multi-project evidence and an ablation;
|
|
they must not be tuned against one repository.
|
|
|
|
The top-level score remains the original coarse, language-agnostic indicator;
|
|
its SCC inputs still include calls/imports/inherits, including coarse P4 edges.
|
|
Consumers that need P4 meaning must use `metrics.p4`, whose fields are:
|
|
|
|
| Field | Canonical observation |
|
|
| --- | --- |
|
|
| `parser_state_count` / `terminal_state_count` | P4 `state` and implicit `terminal-state` nodes |
|
|
| `parser_transition_count` | Transition edges sourced at a parser state |
|
|
| `parser_cycle_count` / `cyclic_parser_state_count` | SCCs over same-parser `direct-transition`, `select-transition`, and `select-default` edges |
|
|
| `unreachable_state_count` | Non-terminal states not reachable from a recognized `start` state within the same parser |
|
|
| `control_apply_node_count` | P4 control, table, and action nodes |
|
|
| `control_apply_relationship_count` | `apply` and `action-call` edges sourced at those nodes |
|
|
| `control_apply_cycle_count` / `cyclic_control_apply_node_count` | SCCs over resolved control/table/action apply and action-call edges |
|
|
| `unresolved_dependency_count` | P4 include, transition, apply, action-call, or table-action edges targeting an External node |
|
|
|
|
A repeated apply or action call merges call-site evidence on one directed
|
|
relationship and is not a cycle without a return path. Accept/reject terminals
|
|
have no outgoing transition by construction. Unreachable-state diagnostics are
|
|
prefixed `P4 structural observation (not verifier proof)` and are recomputed
|
|
idempotently. Compiler/verifier Flags edges never enter these structural
|
|
metrics.
|
|
|
|
## P4 compiler evidence
|
|
|
|
The qualified p4c adapter accepts only Brick envelope schema 1 for p4c
|
|
v1.2.5.16 `p4test-regression` diagnostics. It creates Finding nodes and Flags
|
|
edges with `Imported` evidence, never `Symbolic` evidence. Tool version, command
|
|
mode, result category/code, exit status, raw result identity, artifact
|
|
identity/provenance, explicit model bounds/confidence category, and source
|
|
position remain inspectable attributes or provenance.
|
|
|
|
The adapter first resolves the exact path/kind/name/owner/line P4 entity and
|
|
falls back to the matching file with a diagnostic. Unknown categories, escaping
|
|
paths, unsupported tool versions/modes, non-null symbolic bounds, and
|
|
unqualified symbolic tools fail closed. The complete envelope and real-fixture
|
|
contract is in `docs/architecture/p4-evidence.md`.
|
|
|
|
## Fold integration
|
|
|
|
The current adapter imports SARIF and native findings JSON. A deeper adapter
|
|
should map Fold function/block/operation/value fact IDs directly to Brick
|
|
identities and retain source/binary lanes. Source proved, latent, heuristic, and
|
|
concrete-witness confidence must remain distinguishable. Binary evidence must
|
|
not be promoted to symbolic evidence without corroboration.
|
|
|
|
A Fold finding with no backend is diagnosed and not imported. Missing confidence
|
|
is preserved as unknown with a diagnostic. Duplicate finding IDs merge report
|
|
provenance into the existing Flags relationship.
|