|
|
@@ -55,50 +55,124 @@ re-run and audited. Have it write a machine-readable
|
|
|
`analysis/$1/topology.json` and print a human summary. Run it; show the
|
|
|
summary (cap at ~200 lines for very large estates).
|
|
|
|
|
|
-## Render
|
|
|
-
|
|
|
-From the extracted data, generate **three Mermaid diagrams** and write them
|
|
|
-to `analysis/$1/TOPOLOGY.html` as a self-contained page that renders in any
|
|
|
-browser.
|
|
|
-
|
|
|
-The HTML page must use: dark `#1e1e1e` background, `#d4d4d4` text,
|
|
|
-`#cc785c` for `<h2>`/accents, `system-ui` font, all CSS **inline** (no
|
|
|
-external stylesheets). Load Mermaid from a CDN in `<head>`:
|
|
|
-
|
|
|
-```html
|
|
|
-<script type="module">
|
|
|
- import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.esm.min.mjs';
|
|
|
- mermaid.initialize({ startOnLoad: true, theme: 'dark' });
|
|
|
-</script>
|
|
|
+`topology.json` must follow this schema — it feeds the interactive viewer:
|
|
|
+
|
|
|
+```json
|
|
|
+{
|
|
|
+ "system": "<display name>",
|
|
|
+ "root": {
|
|
|
+ "id": "sys", "name": "<system>", "kind": "system",
|
|
|
+ "children": [
|
|
|
+ { "id": "dom:<domain>", "name": "<Domain>", "kind": "domain",
|
|
|
+ "children": [
|
|
|
+ { "id": "<MODULE>", "name": "<MODULE>", "kind": "module",
|
|
|
+ "language": "cobol", "loc": 1234, "file": "src/MODULE.cbl" }
|
|
|
+ ] },
|
|
|
+ { "id": "dom:data", "name": "Data stores", "kind": "domain",
|
|
|
+ "children": [
|
|
|
+ { "id": "ds:<NAME>", "name": "<NAME>", "kind": "datastore" }
|
|
|
+ ] }
|
|
|
+ ]
|
|
|
+ },
|
|
|
+ "edges": [
|
|
|
+ { "source": "<id>", "target": "<id>", "kind": "call" }
|
|
|
+ ],
|
|
|
+ "entryPoints": ["<id>", "..."],
|
|
|
+ "deadEnds": ["<id>", "..."],
|
|
|
+ "observations": ["<architect observation>", "..."],
|
|
|
+ "flows": [
|
|
|
+ { "name": "<business flow>", "persona": "<who experiences it>",
|
|
|
+ "description": "<one sentence, plain language>",
|
|
|
+ "steps": [
|
|
|
+ { "label": "<business-language step>", "nodes": ["<id>", "<id>"] }
|
|
|
+ ] }
|
|
|
+ ]
|
|
|
+}
|
|
|
```
|
|
|
|
|
|
-Each diagram goes in a `<pre class="mermaid">...</pre>` block. Do **not**
|
|
|
-wrap diagrams in markdown ` ``` ` fences inside the HTML.
|
|
|
-
|
|
|
-1. **`graph TD` — Module call graph.** Cluster by domain (use `subgraph`).
|
|
|
- Highlight entry points in a distinct style. Cap at ~40 nodes — if larger,
|
|
|
- show domain-level with one expanded domain.
|
|
|
+- Group leaf modules under `domain` containers (use the domains from
|
|
|
+ `/modernize-assess` if available). Leaf kinds: `module`, `datastore`,
|
|
|
+ `job`, `screen`. `loc` drives circle size — include it for modules.
|
|
|
+- Edge kinds: `call` (direct), `dispatch` (dynamic/router), `read`,
|
|
|
+ `write`. Every edge endpoint must be a leaf id that exists in the tree.
|
|
|
+- `deadEnds`: the dead-end candidates from the extraction, rendered with
|
|
|
+ a dashed outline in the viewer. Apply the suppression rules above —
|
|
|
+ anything that could be the target of an unresolved dynamic call does
|
|
|
+ NOT belong here; record that uncertainty in `observations` instead.
|
|
|
+- **Datastore ids and names must be logical identifiers** — DD name,
|
|
|
+ dataset name, table/schema name, at most host:port. If the resolved
|
|
|
+ config value is a URL or DSN, strip userinfo and credential query
|
|
|
+ params before it goes anywhere in topology.json: the file gets
|
|
|
+ committed and the viewer displays names verbatim. Never copy raw
|
|
|
+ config values into `observations`.
|
|
|
+- `observations`: 3–7 architect observations — tight coupling clusters,
|
|
|
+ single points of failure, service-extraction candidates, data stores
|
|
|
+ with too many writers, dispatch targets the extraction could not
|
|
|
+ resolve.
|
|
|
+- `flows` is the **persona walkthrough** section — see below.
|
|
|
+
|
|
|
+## Persona flows
|
|
|
+
|
|
|
+Trace **2–4 end-to-end business flows**, each anchored to a persona —
|
|
|
+the people who experience the system, not the people who maintain it
|
|
|
+(e.g. for a benefits system: the claimant, the caseworker, the auditor;
|
|
|
+for billing: the customer, the billing operator). For each flow:
|
|
|
+
|
|
|
+- `name` + one-sentence `description` in plain business language —
|
|
|
+ something a steering committee member relates to ("a claimant files a
|
|
|
+ weekly claim"), not a data-flow label ("CLM batch ingest").
|
|
|
+- `steps`: 3–8 steps, each with a business-language `label` and the
|
|
|
+ `nodes` (programs + data stores) that implement that step, in
|
|
|
+ execution order.
|
|
|
+
|
|
|
+This is the bridge between the technical map and non-technical
|
|
|
+stakeholders: the same diagram answers "which program does X" for
|
|
|
+engineers and "what happens when someone files a claim" for everyone else.
|
|
|
|
|
|
-2. **`graph LR` — Data lineage.** Programs → data stores.
|
|
|
- Mark read vs write edges.
|
|
|
-
|
|
|
-3. **`flowchart TD` — Critical path.** Trace ONE end-to-end business flow
|
|
|
- (e.g., "monthly billing run" or "process payment") through every program
|
|
|
- and data store it touches, in execution order. If production telemetry is
|
|
|
- available (see `/modernize-assess` Step 4), annotate each step with its
|
|
|
- p50/p99 wall-clock.
|
|
|
-
|
|
|
-Also export the three diagrams as standalone `.mmd` files for re-use:
|
|
|
-`analysis/$1/call-graph.mmd`, `analysis/$1/data-lineage.mmd`,
|
|
|
-`analysis/$1/critical-path.mmd`.
|
|
|
+## Render
|
|
|
|
|
|
-## Annotate
|
|
|
+`analysis/$1/TOPOLOGY.html` is an **interactive map**: a zoomable
|
|
|
+circle-pack of the whole system (domains as containers, modules sized by
|
|
|
+LOC) with dependency edges, search, per-node detail sidebar, edge-kind
|
|
|
+toggles, and a flow-walkthrough mode that plays each persona flow as a
|
|
|
+numbered path. Build it from the template that ships with this plugin —
|
|
|
+do not hand-write the viewer:
|
|
|
+
|
|
|
+```bash
|
|
|
+python3 - "${CLAUDE_PLUGIN_ROOT}/assets/topology-viewer.html" analysis/$1 <<'EOF'
|
|
|
+import json, sys
|
|
|
+tpl_path, out_dir = sys.argv[1], sys.argv[2]
|
|
|
+tpl = open(tpl_path).read()
|
|
|
+marker = "/*__TOPOLOGY_DATA__*/ null"
|
|
|
+assert marker in tpl, f"injection marker not found in {tpl_path}"
|
|
|
+data = json.dumps(json.load(open(f"{out_dir}/topology.json")))
|
|
|
+open(f"{out_dir}/TOPOLOGY.html", "w").write(
|
|
|
+ tpl.replace(marker, "/*__TOPOLOGY_DATA__*/ " + data))
|
|
|
+print(f"wrote {out_dir}/TOPOLOGY.html")
|
|
|
+EOF
|
|
|
+```
|
|
|
|
|
|
-Below each `<pre class="mermaid">` block in TOPOLOGY.html, add a `<ul>`
|
|
|
-with 3-5 **architect observations**: tight coupling clusters, single
|
|
|
-points of failure, candidates for service extraction, data stores
|
|
|
-touched by too many writers.
|
|
|
+The viewer is fully self-contained (the d3 subset it needs is inlined in
|
|
|
+the template) — it works offline and on air-gapped networks. If the
|
|
|
+`python3` invocation fails to find the template,
|
|
|
+`${CLAUDE_PLUGIN_ROOT}` was not substituted — report that rather than
|
|
|
+hand-writing a viewer.
|
|
|
+
|
|
|
+Mermaid stays for **small, exportable** diagrams. Generate standalone
|
|
|
+`.mmd` files for reuse in docs and PRs — but keep each under ~40 edges;
|
|
|
+collapse to domain level if the full graph is bigger (dense Mermaid
|
|
|
+becomes unreadable, which is exactly what the interactive map is for):
|
|
|
+
|
|
|
+- `analysis/$1/call-graph.mmd` — domain-level `graph TD`, entry points
|
|
|
+ highlighted
|
|
|
+- `analysis/$1/data-lineage.mmd` — `graph LR`, programs → data stores,
|
|
|
+ read vs write marked
|
|
|
+- `analysis/$1/critical-path.mmd` — `flowchart TD` of the primary flow
|
|
|
+ from `flows`, annotated with p50/p99 wall-clock if telemetry is
|
|
|
+ available (see `/modernize-assess` Step 4)
|
|
|
|
|
|
## Present
|
|
|
|
|
|
-Tell the user to open `analysis/$1/TOPOLOGY.html` in a browser.
|
|
|
+Tell the user to open `analysis/$1/TOPOLOGY.html` in a browser, and to
|
|
|
+try: search for a module, click it to see its connections, and pick a
|
|
|
+persona flow from the walkthrough dropdown.
|