Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions skills/solana/DIAGRAMS.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
## The curve on top, columns beneath

- **The cluster curve is the part of the ball-shaped Ed25519 curve near X=0: flat at the top-left, gently sloping down and to the right.** Canonical path: `M 0,33 Q 400,33 640,113` on a width-640 canvas. It must be monotone - **never a curve that droops down in the middle, and never one that raises up in the middle** (no domes). The gentle slope leaves room underneath the right side of the curve for the rightmost column, and open empty space in the top-right corner **where all titles go**: the cluster label is right-aligned there (e.g. `x="628" y="24" text-anchor="end"`, white-haloed).
- **Every oncurve address dot - each person, each mint, the program - sits ON the curve.** For the canonical path, a dot at `cx` sits at `t = 2.5 − √(640000 − 640·cx)/320`, `cy = 33 + 80·t²` (reference points: x 0→33, 104→34, 210→39, 300→46, 404→59, 500→75, 548→87, 600→100, 640→113). The dot's `PUBLIC KEY` label sits above the dot in the open sky, or in the dot-to-box gap where the sky is taken, white-haloed.
- **Every oncurve address dot - each person, each mint, the program, and every account created from a key pair the client generated - sits ON the curve.** For the canonical path, a dot at `cx` sits at `t = 2.5 − √(640000 − 640·cx)/320`, `cy = 33 + 80·t²` (reference points: x 0→33, 104→34, 210→39, 300→46, 404→59, 500→75, 548→87, 600→100, 640→113). The dot's `PUBLIC KEY` label sits above the dot in the open sky, or in the dot-to-box gap where the sky is taken, white-haloed.
- **Everything else hangs below the curve; a box's top sits at least 9 below the dot's centre at the box's RIGHT edge** (the curve descends rightward, so the right edge is the binding point). Nine is what keeps the dot off the box: the ring reaches 7 from the centre (`r="6"` plus half its 2-wide stroke) and the border reaches 0.9 outside the rect, and a unit of white stays between them. The geometry check measures that unit for every dot against every box, oncurve and offcurve alike; a ring cut by a border reads as a hole in the account. Wallet boxes hang close beneath their dots on the left and progressively deeper toward the right; the rightmost (program) column's box top clears the curve's end height. **No line, arrow, or box ever crosses the curve.** A mint's small box sits in the open top-right region beneath the title (or in the thin strip above the curve's flat left), ≥6px clear of the curve, with its dot on the curve beneath it.
- **The curve is the heaviest line in the figure**: `stroke="#111" stroke-width="3.5"`. Token-movement arrows stay at `1.8`, box borders at `1.5` or below - nothing else may approach the curve's weight, so the cluster reads as the backbone at a glance.
- **A public-key account hugs its dot.** Put the dot at the point along the box's span where the curve comes *closest to the box* - for a box below the curve that is its **right** edge, for a box above the curve (a mint in the top strip) its **left** edge - then the box sits 9px below the dot's centre instead of floating below it. Placing the dot mid-box is the classic mistake: the curve descends across the box's width, so the required clearance gets measured at the far edge and the box drifts tens of pixels away from the dot it belongs to. Aim for a 9–19px gap from centre to box top; never exceed 23px. **If a box still cannot reach its dot, reduce the font size of every piece of text in that figure by one step** (10.5→9.5, 9.5→8.5, 8.5→8, 7.5→7, monospace 8.5→8) and re-fit - a narrower box sits closer.
Expand Down Expand Up @@ -175,10 +175,12 @@ Draw the glyphs exactly as specified - one vocabulary book-wide, no per-figure v

## Addresses are white-centered dots

- **Every address dot has a white center**, oncurve and offcurve alike: `<circle r="6" fill="#fff" stroke="#111" stroke-width="2"/>`. Do not fill address dots with ink.
- **Every address dot has a white center**, oncurve and offcurve alike: `<circle r="6" fill="#fff" stroke="#111" stroke-width="2"/>`. Do not fill address dots with ink. **The radius says what the placement says**: an oncurve dot is `r="6"`, an offcurve dot `r="5.5"`, and `check-figure-geometry.mjs` fails a figure where the two disagree - an `r="6"` dot clear of the curve, or an `r="5.5"` dot touching it.
- **A faded dot still occludes the curve.** `<g opacity="0.3">` composites the whole group, so a faded dot's white centre goes translucent along with everything else and the curve - the heaviest line in the figure - shows straight through the dot, which no unfaded dot ever does. Back the dot with an opaque white disc drawn immediately *before* its faded group, so it sits above the curve and beneath the dot: `<circle cx="X" cy="Y" r="7" fill="#fff"/>` for an `r="6"` dot, `r="6.5"` for an `r="5.5"` one. The extra unit covers the dot's 2-wide ring, so the curve is hidden under the whole mark rather than showing through the ring.
- **A dot on the curve carries no label.** Its position on the curve already says the address is a public key with a private key behind it. Do not write `PUBLIC KEY` beside it - teach the convention once, in prose, where the reader first meets a person and their token account.
- **Seed lists and addresses are set in Andale Mono.** Every seed line, and a built-in address, is `font-size="7" font-family="'Andale Mono', monospace" fill="#555"`, upper case, with no letter-spacing: a monospace face spaces itself, and Andale Mono stays legible where a serif's small capitals blurred. Handler names keep the book's code face (DejaVu Sans Mono), because they are code.
- **A key pair is never off the curve, and never a label.** An account created from a key pair the client generated - an order book too large for a program to allocate, or any account made with `create_account` rather than derived - has a public key for its address, so its dot sits on the curve like a wallet's, `r="6"`, with no seeds, whoever generated the pair and whatever became of the private key afterwards. It is never drawn off the curve, and no caption ever names a key pair: a key pair is two keys, of which the public one is the address; the pair is not an address, and the private key is not public. Seven order-book figures once hung four such accounts in the program column as `r="5.5"` dots captioned `A CLIENT KEYPAIR`, which said "no private key" with the placement and "a private key" with the words, about the same address. `check-figure-geometry.mjs` fails the placement and `lint-manuscript.mjs` fails the caption.
- **Such an account's box hugs its dot like any other.** When the column beneath the curve is taken - program-wide accounts stack under the program, so an order book created from a key pair cannot hang from the curve there - the box goes above the curve in the open top-right, where a mint's box would, with its dot on the curve at the box's left edge and the box's bottom at least 9 above the dot's centre. The mints those figures name only as seeds and fields make room: name them in a not-drawn note instead of drawing them. A dot is never named on the curve with its box somewhere below it: a first attempt at the order book did that and left four dots 300 units from the accounts they stood for. `check-figure-geometry.mjs` fails any address dot more than 20 from an account box, legend keys aside.
- **An offcurve dot carries its seed list, and nothing else.** Write the seeds themselves - `"offer" + ALICE'S ADDRESS + ID`, or for an ATA `ALICE'S ADDRESS + TOKEN PROGRAM + USDC MINT`. No `SEEDS:` prefix: a list of seeds is self-evidently a list of seeds, and the absence of a curve dot is what marks it as derived.
- **A seed list names seeds, and the deriving program is not one of them.** An ATA's seeds are the owner, the token program that manages the mint, and the mint, in that order; the Associated Token Program is the program those seeds are derived against, not a seed: `ALICE'S ADDRESS + TOKEN PROGRAM + USDC MINT`, never `ATA PROGRAM + ...`. A program's own PDA leaves its program out for the same reason, and there the figure's program is the one that derived it.
- **Seeds name the persona, not the role.** A figure has no surrounding prose to bind "the maker" to anybody, so the seed reads `ALICE'S ADDRESS` where the chapter's maker is Alice. Prose keeps the role, because the sentence around it says who holds it.
Expand Down Expand Up @@ -207,5 +209,6 @@ Draw the glyphs exactly as specified - one vocabulary book-wide, no per-figure v
- `opacity` values other than the fade value `0.3`.
- Mermaid, Graphviz, or generated diagrams for account figures - the layout decisions (stable columns, fade grouping) are the content, and generators cannot make them.
- Filled address dots, bare dots with no account rectangle, seeds inside account rects, coins on non-token arrows, or bare handler names without `()`.
- A caption that names a key pair, or an address made from one drawn off the curve. A key pair is two keys; its public key is the address, and that address is always on the curve.
- Hand-drawn substitutes for the five account glyphs, or a heading left at the top of a box that carries nothing else.
- A faded address dot with the cluster curve showing through its centre.
2 changes: 2 additions & 0 deletions skills/solana/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ Use these official documentation sources:

- Name handlers by one rule: **if the domain has a word for it, use the domain's word; if the handler only stamps out a container, it is `initialize_`.** Domain verbs are what make a program read like finance, and they come in pairs: `make_offer()`/`take_offer()`, `open_position()`/`close_position()`, `place_order()`/`cancel_order()`, plus `borrow`, `repay`, `liquidate`, `contribute`, `refund`. Setup has no domain meaning, so it is always `initialize_x()`, naming what it initializes: `initialize_market()`, `initialize_pool()`, `initialize_config()`, never `create_pool()`, `init_reserve()`, or a bare `initialize()`. The test is whether the handler moves money or takes a market action, or only writes parameters into a new account. A third family, `add_x()`, extends a container that already exists: `add_liquidity()`, `add_outcome()`, `add_asset()`.

- A **key pair** is two keys: a private key that signs, and a public key. The **public key is the address**; the pair is not an address, is not an account, and is never "at" one, and the private key is never shown or named as if it were public. An address made from a key pair is always on the Ed25519 curve, whoever generated the pair and whatever they did with the private key afterwards; only a PDA is off it. So never write "a keypair address", "the keypair's account", "an off-curve keypair", or a caption such as `A CLIENT KEYPAIR`; write "a public key the client generated", "the account's address", or name the account.

- Say **PDA** for an address and **account** for the data at it. They are not synonyms: a program derives the offer PDA and then writes the offer account. Use PDA where the subject is derivation, seeds, authority, ownership, or signing, and account where the subject is fields, balances, rent, creation, or closure.

## Do not use
Expand Down