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
114 lines
5.6 KiB
Markdown
114 lines
5.6 KiB
Markdown
---
|
||
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 `<title>` 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.
|