From 237b470be895e3ceec2616f59cea73744a2a7a4c Mon Sep 17 00:00:00 2001 From: Dan Connolly Date: Sun, 11 Oct 2026 14:22:44 -0500 Subject: [PATCH] wiring-diagram: who holds what, drawn like MarkM's ERTP slides A capability wiring diagram as a self-contained HTML/SVG page plus a headless-Chromium PNG. Every arrow has to point to something in the code, and a Mallory holding what's likeliest to leak shows what that doesn't reach. template.html has the drawing helpers, adapted from capsite's cookie-rotation-wiring. README: a TODO to consider adapting agoric-sdk's sequence-diagram-actor-sim as its companion. Generated-by: Claude Opus 5.5 --- README.md | 6 ++ wiring-diagram/SKILL.md | 113 ++++++++++++++++++++++++++++ wiring-diagram/template.html | 138 +++++++++++++++++++++++++++++++++++ 3 files changed, 257 insertions(+) create mode 100644 wiring-diagram/SKILL.md create mode 100644 wiring-diagram/template.html diff --git a/README.md b/README.md index c93b0e9..2006c79 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,12 @@ Code](https://code.claude.com/docs/en/skills) and TADA, then how, then the challenges, tagged for an emoji retro. - [ibis-design](ibis-design/SKILL.md) — search a design space: issues, positions, and arguments. +- [wiring-diagram](wiring-diagram/SKILL.md) — who holds what, drawn + like MarkM's ERTP slides: every arrow cites the code, and Mallory + shows what a leak doesn't reach. + TODO: consider copying or adapting its companion for message order, + sequence-diagram-actor-sim (agoric-sdk `.agents/skills/` on branch + `connolly/ago-1299-agentic-planning-tdd`). - [obsidian-markdown](obsidian-markdown/SKILL.md) — the workspace is an Obsidian vault: one line per paragraph, relative links, no file symlinks you expect Obsidian to show. diff --git a/wiring-diagram/SKILL.md b/wiring-diagram/SKILL.md new file mode 100644 index 0000000..bcd13ee --- /dev/null +++ b/wiring-diagram/SKILL.md @@ -0,0 +1,113 @@ +--- +name: wiring-diagram +description: >- + Capability wiring diagram, "who holds what" — use when asked for a wiring diagram, a picture of who holds what, a capability diagram, or "a diagram like the cookie-rotation one"; when reviewing a design for POLA and wanting to see the reference graph. MarkM ERTP-slide style: actors are balls, makers pale regions, objects rounded squares, state ledger tables, references dot-to-arrowhead; HTML/SVG plus a headless-Chromium PNG. Not for message order over time: that's a sequence diagram (sequence-diagram-actor-sim in agoric-sdk). +--- + +# Capability wiring diagram + +One picture that answers, for a design: **who holds a reference to what, +and therefore who can do what.** It complements a sequence diagram, +which shows *when* messages flow. This one shows the standing graph of +authority that makes those messages possible. For sequences, see +`~/projects/ymax-workspace/agoric-sdk/.agents/skills/sequence-diagram-actor-sim/SKILL.md` +(on agoric-sdk branches `connolly/ago-1264-agentic-planning` and +`connolly/ago-1299-agentic-planning-tdd`, not yet on master). + +Exemplars: +- `~/oros-bots/capsite-cookie-rotation/docs/cookie-rotation-wiring.html` + (+ `.png`): the original. +- `~/qtrx/packages/umb-download/docs/wiring.html` (+ `.png`): three + makers, two outside parties, and an adversary holding a webkey. + +Start from [`template.html`](template.html), next to this file. It has +the drawing helpers and a small example scene to replace. + +## Read the graph from the code, not the story + +Every arrow must correspond to something real: a constructor argument, a +stored id, a binding, a held token, or a file someone keeps. Before +drawing, list the references as `holder → target: where in the code`. +Read the factories (`make…`, `newX`, `configure`) and anything that +stores an id: a DO id held as a string *is* a reference. If you can't +cite where a reference comes from, it doesn't get an arrow. + +Watch for references that are dropped on purpose (e.g. a setup route +that mints an instance, hands its id to one holder and forgets it). +That's often the point of the design. Say so in a caption, or just +leave the arrow out. + +## Vocabulary + +| element | helper | means | +|---|---|---| +| blue ball | `actor(cx, cy, label)` | a person or a program with its own agency | +| grey ball | `actor(cx, cy, label, "url(#ext)")` | outside the system: a browser extension, a third-party service | +| pale region | `maker(x, y, w, h, "makeFoo")` | a maker (factory, DO class) and the instances it made; the stacked inner panes say "there are many" | +| rounded square | `obj(x, y, w, h, label, stacked)` | an object or facet; `stacked` when one is made per instance | +| ledger table | `table(x, y, title, rows, [colW0, colW1])` | an object's state; rows are key/value; `rowY(i)` and `colX` give arrow anchors | +| dot → arrowhead | `ref(x1, y1, x2, y2, bend)` | holder references target; `bend` (±0.05–0.3) curves around things | +| speech bubble | the `path` + `code` block | the one call the picture is about, in `E(target).method(args)` form | +| caption | `cap(x, y, text, attrs)` | what an actor holds, and what it can't reach | + +Facets are separate objects (`store` vs `readOnly`): drawing them apart +is how the picture shows attenuation. + +## Include an adversary + +Add a Mallory who holds whatever is most likely to leak (an instance +id, a webkey, a URL), with an arrow to exactly what it reaches. The +caption says what she *can't* reach. Absent arrows are the security +argument, and Mallory makes them visible. + +## Layout + +- Actors in a row along the top (y≈200), makers below (y≈320 onward), + captions along the bottom (y≈ height − 14). +- Put each maker under the actors that mostly use it, so arrows run + short and downward. +- Speech bubble at the top, its tail pointing at the speaker. Move the + bubble's path (`M x,y`) and the tail segment (`h… l-38,48 l6,-48`) + together. +- Captions: two or three short lines, never on top of an arrow or a + ball. Use `"text-anchor": "start"` to set one beside a ball. +- Long arrows that cross a maker: increase `|bend|` until the curve + clears tables and objects. The control point is the midpoint offset + by `bend × (−dy, dx)`. + +## Accessibility + +Keep `` short. Write `<desc>` as prose that names every actor and +maker, every reference, the bubble's call, and what the adversary +can't reach. Someone who can't see the picture should get the same +argument from it. + +## Render and check + +The page is self-contained (no network). Render a PNG with headless +Chromium. The viewport comes out shorter than `--window-size`, so render +taller and crop to the SVG size: + +```sh +chromium --headless=new --disable-gpu --no-sandbox --hide-scrollbars \ + --window-size=W,$((H+100)) --screenshot=full.png "file://$PWD/NAME.html" +python3 -c "from PIL import Image; Image.open('full.png').crop((0,0,W,H)).save('NAME.png')" && rm full.png +``` + +Then **look at the PNG** (Read it) and fix overlaps: captions on arrows, +arrows through tables, text clipped at the bottom. Expect two or three +rounds. Commit the HTML (source) and the PNG separately, so the source +diff stays readable. + +## Review checklist + +- Does every arrow cite something in the code? Is any real reference + missing? +- Does each actor hold only what its job needs (POLA)? If the picture + shows an actor holding more, that's a finding about the design, not a + drawing problem. +- Are facets drawn apart where they differ in authority? +- Does the adversary's caption match what the arrows show? +- Does `<desc>` tell the same story in prose? +- Is any secret value drawn? Elide values (`session=…`, `{…}`): the + picture shows *that* a row exists, not its contents. diff --git a/wiring-diagram/template.html b/wiring-diagram/template.html new file mode 100644 index 0000000..bb8c73d --- /dev/null +++ b/wiring-diagram/template.html @@ -0,0 +1,138 @@ +<!doctype html> +<html><head><meta charset="utf-8"> +<title>TITLE: who holds what + + + + + TITLE: who holds what + Prose for screen readers: name every actor and maker, every +reference (who holds what), the speech bubble's call, and what the +adversary can and cannot reach. + + + + + + + + + + + + + + + + + + + +