Traceability graph
The traceability graph is the central artifact produced by swax discover and
consumed by swax plan. It models API path → list of dependent paths.
Architectural rule
The graph stores paths only — no HTTP methods, no resource abstraction. This is an architectural rule of Swax: minimal abstraction.
- Nodes = API paths (e.g.
/users,/users/{id}). - Edges = discovered dependencies between paths
(
sourcedepends ontarget).
File format
.swax/traceability.yml:
/payment:
- /users
- /orders
/orders:
- /payment
/users/{id}: [] # endpoint with no dependencies — still a node
- Keys are paths.
- Values are lists of dependent paths.
- An endpoint with no dependencies is still a node — every endpoint discovered in the parsed specs appears in the graph with at least an empty adjacency list.
Determinism
save_traceability writes deterministic YAML:
- Parent directories are created as needed.
- Keys and values are explicitly sorted in Python — not deferred to the YAML serializer.
- Output is stable across runs for clean diffs.
deduplicate runs before saving:
- Removes duplicate edges.
- Removes self-loops.
- Sorts each adjacency list.
- Preserves sources with empty adjacency lists — paths with no dependencies remain graph nodes.
Building the graph
TraceabilityGraph accumulates edges via add_edge:
from swax.traceability import TraceabilityGraph
graph = TraceabilityGraph(edges={})
graph.add_edge(source="/payment", target="/users")
graph.add_edge(source="/payment", target="/orders") # duplicates tolerated
graph.add_edge(source="/orders", target="/payment")
graph.deduplicate()
- Duplicates at insertion time are acceptable — they are removed by
deduplicate. - Self-loops are permitted at insert time and filtered by
deduplicate. deduplicateis idempotent — safe to call multiple times.
Loading the graph
from pathlib import Path
from swax.traceability import load_traceability
graph = load_traceability(Path(".swax/traceability.yml"))
- File is read as UTF-8.
- Parsing uses a safe YAML loader.
- An empty file yields an empty graph, not an error.
- Each adjacency value is normalized to a list.
Finding affected endpoints
find_affected_endpoints(changed_paths, graph) returns every endpoint
transitively affected by a set of changed paths — the changed paths plus every
endpoint whose dependency chain reaches one of them (reverse reachability).
- Result is sorted and deduplicated.
- Changed paths not present as graph nodes are still returned.
- The routine is read-only — does not mutate the graph.
- Accepts plain path strings — does not depend on the
openapicell.
from swax.traceability import find_affected_endpoints
affected = find_affected_endpoints(
changed_paths=["/users", "/users/{id}"],
graph=graph,
)
# ['/orders', '/payment', '/users', '/users/{id}']
Errors
| Exception | Cause |
|---|---|
TraceabilityGraphMissingError(path) |
The graph file does not exist — swax discover has not been run yet. Raised by run_plan. |
See also
- Impact Report — how the graph feeds the plan command.
- Architecture / traceability cell — full API reference.