Skip to content

Replace coined labels with the checks, handlers and fields they stand for - #190

Merged
mikemaccana merged 49 commits into
mainfrom
claude/plain-wording-sweep
Sep 30, 2026
Merged

mikemaccana merged 49 commits into
mainfrom
claude/plain-wording-sweep

Conversation

@mikemaccana

@mikemaccana mikemaccana commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Follows quicknode/solana-book#188, which did this for the Fundraiser chapter. The first commits were pushed to #188's branch after it merged, so they are cherry-picked here onto main.

Wording sweep, every chapter

The book used words that sound like jargon but are labels it had invented. Each now names the handler, field, check or error it stood for, or says who gets what out:

  • gate and guard → the check and its error ("the health gate rejects" → "liquidate_position() refuses a healthy position with PositionHealthy"). Solana's "feature gates" and Wormhole's "guardians" stay.
  • exit → the handler, or who gets their assets out. The state-machine principle now reads the same everywhere: "every participant must be able to get their assets out of every state".
  • money → the stake, the collateral, the deposit or the USDC when it means what a program holds. Everyday speech about people stays ("put money on", "get their money back", "sending money to family abroad"), as do the option terms and the chapter title The Arithmetic of Money.
  • truth → the field the program reads. The chapter title Offchain Truth stays.
  • lock as a vague noun → where the tokens went ("every resting order's full lock is in a vault" → what the vaults hold for each order).
  • proves, promise, X-based, by construction, "the rule" as a pointer, and "is an integer comparison".
  • 17 figure labels and SVG comments, with the same or shorter text.

Names that follow the companion repository

quicknode/solana-program-examples#171 renamed these identifiers; the chapters and figures now use the shipped names:

Before After
protocol_fees program_fees
accumulated_protocol_fees accumulated_program_fees
collect_protocol_fees() collect_program_fees()
protocol_fees_accrue_and_owner_can_collect program_fees_accrue_and_owner_can_collect
place_bid_locks_quote_in_vault, place_ask_locks_base_in_vault place_bid_moves_quote_into_vault, place_ask_moves_base_into_vault

Model checks, not formal proofs

The companion repository has Kani model checks and tests, and no formal proofs. The testing section is now "Model Checking Goes Further Than Testing". One paragraph says what a formal proof is and that the repository has none, and explains that the kani-proofs and proof_* names come from Kani's #[kani::proof] attribute. Every "Kani proofs", "formally verified" and "machine-checked proofs" now says model-checks. The conclusion's formal-verification paragraph is gone. The companion docs were changed to match in quicknode/solana-program-examples#170.

Glossary

  • New entries: asset (assets on Solana are represented as tokens), token (SOL is the native token; USDC, NVDAx and the rest are SPL tokens) and open source (a license that meets the Open Source Definition).
  • The degenerate-value and invariant entries say what K is and link to it.

Factual fixes

  • Perps:
    • LPs do not earn fees. In all three versions of the program, open and close fees go to program_fees (the pool creator's) and the liquidation fee goes to the liquidator. LPs earn traders' losses and funding.
    • collect_fees() is not Maria's only signed handler: set_funding_rate() also requires her signature.
  • Betting market: "The Draft status is what keeps the list fixed" said the opposite of what happens. Outcomes can be added only while the event is a Draft, and the list is fixed when the admin opens betting. The rejected design is described as the naive alternative, in the conditional. The testing section says exactly when close_losing_bet() works: only on a settled event and only for a bet that lost.
  • Tokens: a footnote points to tokens.xyz for which assets are available as Solana tokens.

Linter

scripts/lint-manuscript.mjs now rejects:

  • gate, guard, exit, money and truth;
  • by construction, X-based and "is a comparison";
  • a test that proves, and proof wording for Kani harnesses;
  • a bare "key", when it should say private key or public key;
  • "protocol" anywhere, including inside identifiers. The one exception is the Solend organization's name in a GitHub link.

Each rule keeps the exceptions above. The matching style rules are in quicknode/solana-finance-claude-plugin#73, #74 and #75.

npm run lint, node scripts/check-figure-geometry.mjs and npm run build-pdf all pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn

Mike MacCana added 4 commits September 29, 2026 20:58
… for

Sweep the book for words that sound like jargon but are labels the text
invented: "gate" for a check, "exit" for a handler that pays out,
"promise" for what a program does, "truth" for a recorded field, "proves"
for a test, "X-based", "by construction", and "the rule" pointing at a
principle instead of stating it. Each now names the handler, field, check
or error, or says who gets what money out.

The state-machine principle "every state needs an exit" now reads as its
content everywhere: every participant must be able to get their money out
of every state.

Lint the labels that have no legitimate use left: gate (except feature
gates), exit, truth (except Offchain Truth), by construction, X-based, a
test that proves, and "is an integer comparison".

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
Open and close fees accrue to protocol_fees, which the pool creator sweeps
with collect_fees(), and the liquidation fee goes to the liquidator, in all
three versions of the program.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
… glossary

- "Money" becomes the stake, the collateral, the deposit, the USDC, or
  assets or amounts. The state-machine principle now reads "every
  participant must be able to get their assets out of every state"
  everywhere. Option terms of art and the Arithmetic of Money chapter
  title stay.
- "Guard" becomes check or test. Wormhole's guardians stay.
- The glossary's degenerate-value and invariant entries say what K is
  and link to its entry, instead of assuming the reader has met it.
- The betting market's rejected design reads as the naive alternative it
  is, in the conditional.
- The lint rejects "money" and "guard" outside those exceptions.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
Mike MacCana added 5 commits September 30, 2026 16:33
- The companion repository has Kani model checks and tests, and no formal
  proofs. Every "proves", "Kani proofs", "formally verified" and
  "machine-checked proofs" now says model-checks or checks, the testing
  section is "Model Checking Goes Further Than Testing", and one
  paragraph says what a formal proof is and that the repository has none.
  It explains that the kani-proofs and proof_* names come from Kani's
  #[kani::proof] attribute. The conclusion's formal-verification
  paragraph is gone.
- The glossary gains entries for asset (assets on Solana are represented
  as tokens) and token (SOL is the native token; USDC, NVDAx and the rest
  are SPL tokens).
- The lint rejects the proof wording outside the one distinguishing
  sentence.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
"Put money on" an outcome is a bet and "get their money back" is a
refund, so both are exact. The lint allows them.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
The conclusion's remittance, savings and payday sentences and the
escrow chapter's "sent money overseas" describe people, not programs,
and read naturally with "money". The lint allows those idioms.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
…them

The sweep's "The Draft status is what keeps the list fixed" said the
opposite of what happens: add_outcome() works only on a Draft, and the
list is fixed when the admin moves the event to Open.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
Mike MacCana added 7 commits September 30, 2026 17:03
"When a losing bet may close" left the reader to guess. The handler
requires a settled event (EventNotSettled otherwise) and a bet on a
losing outcome (BetWon otherwise), and the test that checks both is now
named.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
"Without cancel_offer(), an untaken offer strands the maker's tokens"
read as if the program lacked cancel_offer(). The Escrow and Options
failure modes and the state-machine example in the Part II intro now
say what would happen if the handler didn't exist.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
"His NVDAx is not sold" followed "the borrower", so it read as a
gendered pronoun for the role; it is Bob's. The same happened with
"every backer" and Alice's token account, and "a put writer" and
Carol's.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
Mike MacCana added 8 commits September 30, 2026 18:27
A private key signs; a public key is stored, recorded and checked. Every
bare "key" meaning one of them now says which: "the market owner's
private key signed it", "her public key is stored as the market's
admin", "a single trusted signer". The PDA chapter's key/value store
and the order book's critbit keys keep the database meaning.

The lint rejects a bare "key", with a per-rule exception for those
database uses; lint rules can now carry their own exception.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
It sat in the paragraph about Maria's fee, which gave it the fee's
reason. The slippage tolerance bounds how far below the oracle price a
deposit's or rebalance's swaps may fill.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
"Each share is worth about $1.07, and nothing needs to happen for that
to be true" now says what the vaults hold and how many shares exist.
The same kind of sentence elsewhere (nobody has to search, compounds on
its own, price-time priority for free) now states the mechanism.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
The managed fund's rounding formulas, the lending market's rounding
directions, the fundraiser's three lifecycle tests, and the glossary's
address kinds and clusters were lists written as prose.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
… Maria must be two people

"The manager is the threat model" overstated it. A footnote says the
program sees two public keys, not two people, and points to
proof-of-personhood services for keeping the curator and the manager
separate.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
Like "the manager is the threat model": the operator acts as the
oracle rather than their signature being it, vetting feeds is part of
what Victor sells, and a stale price is one way to exploit a program,
not the attack.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
"Every resting order's full lock is in a vault" used "lock" as a noun
the chapter never defined, and it could be read as a file lock. The
order book's invariants, testing list, headings and figures now say the
tokens are paid into a vault, held for the order, or credited back. The
standard terms "total value locked" and locked minimum liquidity stay.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
set_funding_rate() also requires her signature, and has its own test.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
Mike MacCana added 2 commits September 30, 2026 21:36
Keeps this branch's abandoned-offer sentence and main's degenerate-offers
bullet from #191.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
…nt it

"Devnet is identical machinery" becomes "runs the same software as mainnet",
"the Managed Fund chapter is the machinery" becomes "the Managed Fund chapter
builds that program", and so on in the tokens, clusters and conclusion
chapters. The linter now rejects "machinery".

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
Mike MacCana added 15 commits September 30, 2026 22:02
…in world

The shop owner's investor, the middleman, the friends' pot, the roaster's
raise, the supplier's invoice and the licenses between banks and the chain are
all everyday money, not a program's holdings. The lint rule's exception names
these phrases.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
"Go running" could read as getting excited, and "pot" appeared twice. The
sentence now reads "people go for a run when it is their own fifty at stake".

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
"It would strand the maker's tokens the day nobody took the offer" becomes
"if nobody took the offer". The same change is made for the betting market's
cancelled event, the perps pool that outgrows a transaction, and the price feed
that stops publishing.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
"One instruction handler per transition" becomes "Give each transition its
own instruction handler", "A pause may stop deposits" becomes "Let a pause
stop deposits", and so on through the What You Learnt summaries of the
concepts and building-blocks chapters.

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
…i says proof

"A test checks the inputs you thought of" becomes "the values you thought of",
since an input can mean the variable itself. The same change is made through the
testing section, its summary, the glossary's invariant entry and the escrow
chapter. The formal-proof paragraph now opens "Though Kani calls its checks
proofs, a model check is not a formal proof."

Claude-Session: https://claude.ai/code/session_01JGEoAUjMm7Evv69k46eNcn
@mikemaccana
mikemaccana merged commit 8ece0e2 into main Sep 30, 2026
1 check passed
@mikemaccana
mikemaccana deleted the claude/plain-wording-sweep branch October 13, 2026 00:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant