On this page
The codebase as a walkable graph๏
๐ต Expert ยท Lesson 19
THE GRAPH DOCUMENTS. Expert 18 addressed prose by section. The two graph documents carry the same prose surface AND a real graph: nodes, edges, traversal, and blast radius - answered at import, with nothing conjured.
md.graph_network the graph md.graph_details the prose about what the graph names
THE ONE THAT CHANGES HOW YOU WORK graph.node_at(source_path, line) You have a traceback. You have file.py:412. That call turns a line number into the NODE that encloses it, and from there impact() tells you what else moves if you change it. Stack trace to blast radius without leaving the process.
EVERY EDGE EXPLAINS ITSELF Edge(source, relation, target, cardinality, phase, origin, why) Two fields there are unusual and both are the point: why - the justification for the edge, carried WITH it origin - authored or derived: did a human assert this, or did a tool infer it? origin is a TRUST FILTER you can pass to walk() and impact(). Walk only authored when you need what someone meant; walk only derived when you need what the machine can prove. A graph that cannot tell you which is which forces you to trust all of it equally, which in practice means trusting none of it.
AND GUESSES DO NOT SHIP. edge_count excludes extractor candidates - the leads over-generate roughly eightfold and never reach the adjacency table. What you walk is evidence.
walk() YIELDS, AND THAT IS A CONTEXT BUDGET DECISION It is a generator "so an agent can stop at the first useful hop instead of materialising a subgraph it will discard" - expert 18's law again, one grain up. Breadth-first, so shallow relationships arrive first and stopping early stops at the RIGHT things.
TWO GUARANTEES THAT MAKE A WALK SAFE - CYCLES ARE HANDLED. borrows and used_by run both ways, so the graph has cycles and every node is expanded at most once. An unguarded walk would not terminate. - AN EDGE TO AN UNKNOWN NODE IS STILL YIELDED, then not expanded. "The relationship is real even where the target is not described here." A graph that hid those edges would quietly understate what touches what.
IMPACT IS MEASURED IN FILES impact(node_id) -> Impact(source, hops, nodes, edges) Ranked by PROXIMITY, nearest first. Not "here are 400 symbols" - here are the files, in the order you should look at them, in the unit you actually open and edit.
AND THE TWO DOCUMENTS JOIN details_key(node_id) -> the section key in the details document describe(node_id) -> that section's text A node in the network document addresses prose in the other one. That is why they ship as a pair.
Before you run๏
Use the Expert guide for prerequisite concepts. Run from a checkout with Melder installed and Python 3.14 free-threading selected. The collection download includes the level's local helper modules.
Run the saved script๏
python UX_and_AIX_experiences/04_expert/19_the_codebase_as_a_walkable_graph.py
py -3.14t UX_and_AIX_experiences/04_expert/19_the_codebase_as_a_walkable_graph.py
Public surface๏
md.graph_network / graph_details - node_count, edge_count, relations, node_ids, node, find_nodes, nodes_in, node_at, edges_from, edges_to, neighbors, walk, impact, details_key, describe
Code๏
1"""
2TIER: expert (19)
3GOAL: THE GRAPH DOCUMENTS. Expert 18 addressed prose by section. The two
4 graph documents carry the same prose surface AND a real graph:
5 nodes, edges, traversal, and blast radius - answered at import,
6 with nothing conjured.
7
8 md.__graph_network__ the graph
9 md.__graph_details__ the prose about what the graph names
10
11 THE ONE THAT CHANGES HOW YOU WORK
12 graph.node_at(source_path, line)
13 You have a traceback. You have `file.py:412`. That call turns a
14 line number into the NODE that encloses it, and from there
15 `impact()` tells you what else moves if you change it. Stack trace
16 to blast radius without leaving the process.
17
18 EVERY EDGE EXPLAINS ITSELF
19 Edge(source, relation, target, cardinality, phase, origin, why)
20 Two fields there are unusual and both are the point:
21 `why` - the justification for the edge, carried WITH it
22 `origin` - `authored` or `derived`: did a human assert this, or
23 did a tool infer it?
24 `origin` is a TRUST FILTER you can pass to `walk()` and `impact()`.
25 Walk only `authored` when you need what someone meant; walk only
26 `derived` when you need what the machine can prove. A graph that
27 cannot tell you which is which forces you to trust all of it
28 equally, which in practice means trusting none of it.
29
30 AND GUESSES DO NOT SHIP. `edge_count` excludes extractor
31 candidates - the leads over-generate roughly eightfold and never
32 reach the adjacency table. What you walk is evidence.
33
34 `walk()` YIELDS, AND THAT IS A CONTEXT BUDGET DECISION
35 It is a generator "so an agent can stop at the first useful hop
36 instead of materialising a subgraph it will discard" - expert 18's
37 law again, one grain up. Breadth-first, so shallow relationships
38 arrive first and stopping early stops at the RIGHT things.
39
40 TWO GUARANTEES THAT MAKE A WALK SAFE
41 - CYCLES ARE HANDLED. `borrows` and `used_by` run both ways, so
42 the graph has cycles and every node is expanded at most once.
43 An unguarded walk would not terminate.
44 - AN EDGE TO AN UNKNOWN NODE IS STILL YIELDED, then not expanded.
45 "The relationship is real even where the target is not
46 described here." A graph that hid those edges would quietly
47 understate what touches what.
48
49 IMPACT IS MEASURED IN FILES
50 impact(node_id) -> Impact(source, hops, nodes, edges)
51 Ranked by PROXIMITY, nearest first. Not "here are 400 symbols" -
52 here are the files, in the order you should look at them, in the
53 unit you actually open and edit.
54
55 AND THE TWO DOCUMENTS JOIN
56 details_key(node_id) -> the section key in the details document
57 describe(node_id) -> that section's text
58 A node in the network document addresses prose in the other one.
59 That is why they ship as a pair.
60SURFACE EXERCISED: md.__graph_network__ / __graph_details__ -
61 node_count, edge_count, relations, node_ids, node,
62 find_nodes, nodes_in, node_at, edges_from, edges_to,
63 neighbors, walk, impact, details_key, describe
64VERIFY: rides the owner's 3.14t harness; asserts are the contract.
65"""
66import melder as md
67
68
69def main() -> None:
70 graph = md.__graph_network__
71 print("__graph_network__ ->", type(graph).__name__,
72 " available =", graph.available)
73 if not graph.available:
74 print(" did not ship:", graph.reason)
75 print(" it still ANSWERS - refused is not missing (expert 18)")
76 return
77
78 # THE SHAPE, BEFORE ANY TRAVERSAL. Note edge_count excludes extractor
79 # candidates: what you can walk is evidence, not leads.
80 print()
81 print("nodes:", graph.node_count, " edges:", graph.edge_count,
82 " (candidates excluded - guesses do not ship)")
83 print("relations:", ", ".join(graph.relations))
84
85 node_ids = graph.node_ids()
86 assert len(node_ids) == graph.node_count
87 print("node_ids():", len(node_ids), "sorted ids")
88
89 # PICK A REAL NODE and read its record.
90 start = node_ids[0]
91 node = graph.node(start)
92 print()
93 print("node:", node.node_id)
94 print(f" {node.kind} {node.name!r} at {node.source}:{node.line}"
95 f" unsemantic={node.unsemantic}")
96
97 # TRACEBACK -> NODE. This is the move worth remembering: a file and a
98 # line become the thing that encloses them.
99 enclosing = graph.node_at(node.source, node.line)
100 assert enclosing is not None
101 print()
102 print(f"node_at({node.source!r}, {node.line}) ->", enclosing.node_id)
103 print(" a stack-trace line, resolved to the node that owns it")
104
105 # EVERY NODE DEFINED IN THAT FILE, in definition order.
106 same_file = graph.nodes_in(node.source)
107 assert any(n.node_id == node.node_id for n in same_file)
108 print(f"nodes_in({node.source!r}) ->", len(same_file), "nodes")
109
110 # EDGES EXPLAIN THEMSELVES. `why` carries the justification and
111 # `origin` says whether a human asserted it or a tool derived it.
112 outbound = graph.edges_from(start)
113 inbound = graph.edges_to(start)
114 print()
115 print(f"edges_from: {len(outbound)} edges_to: {len(inbound)}")
116 for edge in outbound[:2]:
117 print(f" -{edge.relation}-> {edge.target}")
118 print(f" origin={edge.origin} phase={edge.phase} "
119 f"cardinality={edge.cardinality}")
120 if edge.why:
121 print(f" why: {edge.why[:60]}")
122
123 # ONE STEP OUT, THEN A BOUNDED WALK. The walk is a GENERATOR - stop
124 # when you have enough instead of building a subgraph you discard.
125 neighbours = graph.neighbors(start, direction="both")
126 print()
127 print("neighbors(both):", len(neighbours))
128
129 seen = 0
130 for _ in graph.walk(start, depth=2, direction="both"):
131 seen += 1
132 if seen >= 5:
133 break
134 print("walk(depth=2): stopped after", seen, "hops - breadth-first,")
135 print(" so the shallow relationships were the ones I got")
136
137 # THE TRUST FILTER. Same walk, restricted to what a human asserted.
138 authored = sum(1 for _ in graph.walk(start, depth=1, origin="authored"))
139 derived = sum(1 for _ in graph.walk(start, depth=1, origin="derived"))
140 print()
141 print(f"depth-1 authored: {authored} derived: {derived}")
142 print(" a graph that cannot separate asserted from inferred makes")
143 print(" you trust all of it equally, which means trusting none")
144
145 # BLAST RADIUS, IN FILES, NEAREST FIRST.
146 radius = graph.impact(start, depth=2)
147 print()
148 print("impact(depth=2) ->", len(radius), "files affected")
149 for item in radius[:3]:
150 print(f" {item.hops} hop(s) {item.source}"
151 f" ({len(item.nodes)} nodes, {item.edges} edges)")
152 print(" ranked by proximity - the unit you actually open and edit")
153
154 # THE PAIR JOINS. A node here addresses prose in the other document.
155 key = graph.details_key(start)
156 prose = graph.describe(start)
157 print()
158 print("details_key ->", key)
159 print("describe ->", len(prose), "chars of prose about that file")
160 print(" which is why the two graph documents ship as a pair")
161
162 print()
163 print("a line number becomes a node; a node becomes a blast radius")
164 print("edges carry their own justification and their own provenance")
165 print("and the walk yields, so you can stop when you know enough")
166
167
168if __name__ == "__main__":
169 main()
Check the outcome๏
The script contains its own assertions or demonstrated refusal paths. Run it to evaluate those checks against your installed version. The code above is taken directly from the saved file; no run output is invented here.