Session 15. Defend the capstone — Fri 02 Oct
Defend the capstone
Friday, October 2, 2026 · presentation day
Outcome
You present your Gecko capstone, your own store and a buyer that pays or says why not, from your own repository. Then the judge draws one card you did not choose, and your buyer has to refuse it on its own, by field, while the room watches. A purchase that lands proves the plumbing. A purchase refused by field proves you.
This is the Gecko capstone, not the final assignment. The final assignment (your research agent) earns the certificate on its private questions and has no defence: the final assignment.
Contract and threat boundary
| Input | Your my-gecko-buyer repository, your store on devnet, and one live ask: "one espresso". |
| Output | One receipt read from the ledger, and one refusal that names the field and both values. |
| Budget | Six minutes each, hard-timed. Nothing signs unless all seven checks agree. |
| Failure to handle | One card, drawn face down at 3:15: quantity, budget, tampered bytes or stale bytes. |
The threat is not a hostile question. It is a buyer that signs what it was handed. The card is how the room finds out whether yours does.
The six minutes
Script them in your repository's docs/DEFENCE.md. Everything you show ends in a
receipt or a refusal.
| Minute | On screen |
|---|---|
| 0:00 | Your README's first lines: one sentence and the explorer link |
| 0:45 | Your assistant with Gecko connected: list_stores shows your store |
| 1:30 | The live buy: uv run buyer "one espresso" --devnet (finalists may use mainnet) |
| 2:30 | The landing: the explorer, then receipts/<sig8>.md with the ledger deltas |
| 3:15 | The card: the judge draws one, and your buyer refuses and signs nothing |
| 4:30 | Tests and the five cases: one test that was red first |
| 5:15 | The ADR: the decision, and what would reverse it |
The four cards
| Card | What the judge does | Your buyer refuses on |
|---|---|---|
| Quantity | asks for two espressos: uv run buyer "two espressos" --devnet |
quantity: asked 2, prepared 1 |
| Budget | halves the budget: uv run buyer "one espresso" --budget-raw <half> --devnet |
price_raw, with both numbers |
| Tampered bytes | uv run buyer "one espresso" --devnet --card tampered |
signed bytes: verify refuses, nothing is submitted |
| Stale bytes | uv run buyer "one espresso" --devnet --card stale |
blockhash: prepare again, never re-sign |
Measured live on devnet on 30 September: quantity and budget take about 3 seconds, tampered 8, and stale about 40, because the runner waits for the bytes to expire. Say what it is waiting for while it waits.
Which network you present on
| Lane | Who | Command |
|---|---|---|
| Mainnet | the finalists, with a registered, funded wallet | uv run buyer "one espresso" --mainnet --store geckocoffee |
| Devnet | everyone | uv run buyer "one espresso" --devnet |
| Recorded | anyone, when the network or Gecko is down on stage | GECKO_SOURCE=recorded uv run buyer "one espresso" --devnet |
The recorded lane is the same code on real answers we recorded. Using it is honest as long as you say so. Pretending a replay is live is the one thing that fails.
What to have in your repository
store/store.json; intents/, receipts/ and at least four refusals/; tests that
trigger every refusal offline; the ADR (docs/adr/0001-refusals-before-signing.md),
docs/ISSUES.md and docs/EVAL_REPORT.md; and a README that opens with one sentence and
the explorer link. No key anywhere.
Behind on the week? Present projects 01 and 02 offline, and explain one refusal.
Before you present
uv run buyer --cases --recorded # 6/6
uv run buyer --cards --recorded # 4/4
uv run pytest # green
python3 scripts/scan_secrets.py # nothing found
Then the checklist in docs/DEFENCE.md: a devnet receipt committed, your buyer holds SOL
and your token, your connector answered list_stores today. Finalists also run
uv run python scripts/mainnet_wallet.py show and see 300000 raw USDC.
The whole week, step by step: the capstone, step by step.