Parse the allowed dependency matrix (repository-owned source of truth).
The matrix file is T1.2.1's dependency-matrix.md; LAY-ADR SS2/SS7 make it
the machine-checked source of truth from which this checker derives its
import-boundary configuration. This module intentionally re-parses the
markdown table rather than duplicating it as code.
Bases: ValueError
The dependency-matrix file is missing, incomplete, or invalid.
layer_graph_cycles(matrix: dict[str, dict[str, str]]) -> list[list[str]]
Return cycles in the allowed-dependency layer digraph (should be none).
Edges are every yes/port/root cell; self is excluded.
Source code in src/symfonic/devtools/archcheck/matrix.py
| def layer_graph_cycles(matrix: dict[str, dict[str, str]]) -> list[list[str]]:
"""Return cycles in the allowed-dependency layer digraph (should be none).
Edges are every ``yes``/``port``/``root`` cell; ``self`` is excluded.
"""
edges = {
importer: sorted(
imported
for imported, cell in row.items()
if imported != importer and cell in ("yes", "port", "root")
)
for importer, row in matrix.items()
}
from symfonic.devtools.archcheck.cycles import strongly_connected_components
return [sorted(scc) for scc in strongly_connected_components(edges) if len(scc) > 1]
|
parse_matrix_file(path: Path) -> dict[str, dict[str, str]]
Parse dependency-matrix.md into {importer: {imported: cell}}.
Raises :class:MatrixError on any structural gap so a corrupted matrix
can never silently weaken enforcement.
Source code in src/symfonic/devtools/archcheck/matrix.py
| def parse_matrix_file(path: Path) -> dict[str, dict[str, str]]:
"""Parse ``dependency-matrix.md`` into ``{importer: {imported: cell}}``.
Raises :class:`MatrixError` on any structural gap so a corrupted matrix
can never silently weaken enforcement.
"""
if not path.is_file():
raise MatrixError(f"dependency matrix not found: {path}")
matrix: dict[str, dict[str, str]] = {}
for line in path.read_text(encoding="utf-8").splitlines():
if not line.startswith("|"):
continue
cells = [c.strip().strip("`") for c in line.strip().strip("|").split("|")]
if not cells or cells[0] not in LAYERS:
continue
row_name, values = cells[0], cells[1:]
if len(values) != len(LAYERS):
raise MatrixError(
f"matrix row {row_name!r}: expected {len(LAYERS)} cells, got {len(values)}"
)
matrix[row_name] = dict(zip(LAYERS, values, strict=True))
missing = [layer for layer in LAYERS if layer not in matrix]
if missing:
raise MatrixError(f"matrix rows missing: {missing}")
for importer, row in matrix.items():
for imported, cell in row.items():
if cell not in VALID_CELLS:
raise MatrixError(
f"matrix cell [{importer} -> {imported}] has invalid value {cell!r}"
)
if row[importer] != "self":
raise MatrixError(f"matrix diagonal [{importer}] must be 'self', got {row[importer]!r}")
return matrix
|