diff --git a/README.md b/README.md
index 6dcd17a..ac18044 100644
--- a/README.md
+++ b/README.md
@@ -6,648 +6,371 @@ real generated command centre is data/dashboard.html.
# SpeedTrader AI
-**An options trading agent where the AI can veto a trade but can never cause one.**
+**An options trading agent where AI can challenge a trade, but deterministic
+controls alone can authorize execution.**
-Alpaca AI Trading Agents Hackathon · Paper trading only · 1122 tests
+`Alpaca AI Trading Agents Hackathon` · `Paper trading only` · `Alpaca-native` ·
+`Options-first` · `Replayable` · `Auditable`
```bash
pip install -e ".[dev]"
python scripts/run_options_demo.py --replay --dashboard
```
-No API key. No network. No configuration. That runs the complete decision cycle,
-re-derives every decision from its stored snapshot, and writes the command centre.
-
-**Full setup, live paper trading, and the strategy plugin system:** see
-[`docs/SUBMISSION.md`](docs/SUBMISSION.md) for the complete engineering log —
-what was built, what was rejected and why, and the exact commands to reproduce
-every claim in this README.
+No API key. No network. No configuration. That runs all six demo scenarios,
+re-derives every decision from its stored snapshot, and writes the command
+centre to `data/dashboard.html`.
| | |
|---|---|
| **Team** | testerxma |
-| **One-page write-up** | [`docs/ONE_PAGER.md`](docs/ONE_PAGER.md) — AI logic, risk gates, Alpaca infrastructure |
-| **Engineering log** | [`docs/SUBMISSION.md`](docs/SUBMISSION.md) — what was built, what was rejected, and why |
+| **One-page write-up** | [`docs/ONE_PAGER.md`](docs/ONE_PAGER.md) |
+| **Engineering log** | [`docs/SUBMISSION.md`](docs/SUBMISSION.md) |
| **Paper account** | `PA3FJIP2GIRB` · dedicated to this hackathon · $100,000 starting balance |
| **License** | [MIT](LICENSE) |
---
-## The idea
+## Why SpeedTrader?
-Most AI trading agents work like this:
+Most AI trading agents propose first and rely on guardrails to catch mistakes
+afterward. SpeedTrader inverts that order:
-```
-LLM proposes a trade ──► guardrails try to catch bad ones ──► broker
-```
+> **The AI does not create a trade.** A deterministic strategy produces the
+> candidate, a deterministic risk engine sizes and approves it, and only then
+> is a model consulted — to **confirm, abstain, or veto**. Never to originate,
+> enlarge, or authorize.
-The guardrails are the last line of defence, and the LLM's mistakes are the
-thing they have to catch. SpeedTrader inverts it:
+This is not a prompt-level convention. The AI's response is validated against a
+JSON schema with `additionalProperties: false` and exactly four fields
+(`verdict`, `confidence`, `reasoning`, `concerns`). A hostile model returning
+`{"verdict":"CONFIRM","quantity":99999}` changes nothing, proven end-to-end by
+test.
```
-S07 (ported quant strategy)
- ──► deterministic risk engine decides IF and HOW MUCH
- ──► options sizing converts risk budget to contracts
- ──► AI adversarial review may only CONFIRM · ABSTAIN · VETO
- ──► single-use execution licence
- ──► Alpaca (paper) via its MCP server
+AI MAY STOP a trade (advisory)
+Deterministic MAY AUTHORIZE a trade (sole authority)
+Broker EXECUTION OBSERVATION (never decides)
```
-By the time the model is consulted, the trade already exists and is already
-approved. **The AI's entire vocabulary is three words**, and none of them can
-enlarge a position, loosen a limit, change a strike, or authorize anything.
-
-This is not enforced by telling the model to behave — a prompt is a request, and
-prompt injection is real. It is enforced by the **schema**: the review object has
-four fields (`verdict`, `confidence`, `reasoning`, `concerns`) and
-`additionalProperties: false`. A model returning `{"verdict": "CONFIRM",
-"quantity": 99999}` changes nothing, and there is a test that proves exactly
-that against the real pipeline.
-
-The practical consequence: **model capability is a reasoning decision, not a
-safety one.** Swap in the strongest model available and its maximum authority is
+The practical consequence: model capability is a reasoning decision, not a
+safety one. Swap in the strongest model available and its maximum authority is
still to cancel one trade.
---
-## The failure mode is inverted, deliberately
-
-Because this layer can only *subtract*, "fail closed" here means **change
-nothing** — not "block everything".
+## What makes it different
-| What happens | What the system does |
+| | |
|---|---|
-| Model times out | ABSTAIN · the deterministic decision stands |
-| Model returns malformed JSON | ABSTAIN · never guessed at |
-| Model refuses | ABSTAIN |
-| No API key at all | ABSTAIN · honest "no model was consulted" |
-| Model says VETO with a reason | **Trade cancelled** |
-
-If an LLM outage vetoed instead, a vendor going down would silently halt all
-trading. Mutation testing confirms it: `veto-on-failure` — making a model
-failure veto instead of abstain — breaks 23 tests at this commit.
+| **AI is subtractive** | Vocabulary is `CONFIRM · ABSTAIN · VETO`; it cannot resize, reprice, or authorize |
+| **Exact maximum loss** | Long single-leg options only — max loss is the premium paid, known exactly at entry |
+| **Deterministic risk authority** | 22 checks, all evaluated, never short-circuited; the sole source of execution authority |
+| **Single-use authorization** | An HMAC licence bound by hash to the exact proposal and portfolio, non-serialisable |
+| **Restart-safe execution** | Intent is fsynced to a write-ahead journal *before* the broker is contacted |
+| **Reconciliation before retry** | `SUBMITTED` is never `FILLED`; `UNKNOWN` is resolved by querying the broker, never by resubmitting |
+| **Deterministic replay** | A fingerprint that excludes the AI review by construction — the same market state hashes identically regardless of what the model said |
---
-## Why long single-leg options
-
-Chosen for correctness, not convenience.
-
-> **Maximum loss = the premium paid, known exactly at entry, under every price path.**
-
-An equity stop-loss is an *intention* — price can gap through it overnight. A
-long option cannot lose more than its debit. So the risk engine sizes against an
-**exact** maximum loss rather than an assumed one:
+## Architecture
```
-equities: shares = risk_money / stop_distance ← a price distance
-options: contracts = risk_budget / (ask × 100) ← the entire amount at risk
+Market Data
+ │
+ ▼
+S07 Quant Signal deterministic
+ │
+ ▼
+Options Selection + Sizing deterministic
+ │
+ ▼
+AI Review advisory — CONFIRM / ABSTAIN / VETO
+ │
+ ▼
+Deterministic Risk 22 checks — the sole execution authority
+ │
+ ▼
+Single-use Authorization deterministic
+ │
+ ▼
+Alpaca (paper) broker — observed, not decided
+ │
+ ▼
+Reconciliation broker
+ │
+ ▼
+Replay / Audit deterministic
```
-These are not the same formula with different names, and the options path never
-reuses the equity one. Priced at the **ask**, never the mid — the mid understates
-max loss by half the spread on every position.
-
-A bearish signal buys a **long put**, never a short call: risk stays defined in
-both directions.
+| Layer | Responsibility | Authority |
+|---|---|---|
+| Market / Data | Bars, quotes, account and portfolio state | data |
+| Quant (S07) | Produces a candidate signal | deterministic |
+| Options | Contract selection and sizing against risk budget | deterministic |
+| AI Review | Bull / Bear / Judge — may only confirm, abstain, or veto | advisory |
+| Risk | 22 checks evaluated in full; sole execution authority | deterministic |
+| Authorization | Single-use, hash-bound execution licence | deterministic |
+| Execution | Write-ahead intent, broker submission, reconciliation | broker (observed) |
+| Replay / Audit | Fingerprint and replay of the deterministic decision | deterministic |
+
+No research-manager, technical-analyst, or sentiment-analyst agents exist in
+this system. The dashboard reports absent stages as `NOT BUILT` rather than
+implying they ran.
---
-## What a judge can verify in 60 seconds
+## 60-second demo
```bash
-python scripts/run_options_demo.py # all six scenarios
-python -m pytest -q # 1122 passed
-python scripts/mutation_test.py # 78 mutants; every guard is load-bearing
+pip install -e ".[dev]"
+python scripts/run_options_demo.py --replay --dashboard
```
+Six scenarios, run offline against synthetic bars:
+
| Scenario | Demonstrates |
|---|---|
-| `breakout` | 3 contracts, **$960 max loss** inside a $1,000 budget |
+| `breakout` | 3 contracts, $960 max loss inside a $1,000 budget |
| `veto` | AI cancels an approved trade — nothing reaches the broker |
| `no-signal` | S07 declines; the decision is still recorded |
| `illiquid` | spread too wide → no tradeable contract |
| `broke` | one contract costs $6,200 vs a $1,000 budget → rejected |
-| `timeout` | broker times out → **UNKNOWN**, not retried, never "filled" |
+| `timeout` | broker times out → `UNKNOWN`, not retried, never "filled" |
-Then read one decision:
+Inspect one recorded decision:
```bash
cat data/decisions/decisions-*.jsonl | head -1 | python -m json.tool
```
-Every record carries the snapshot, the signal, **the cost assumptions behind its
-EV**, all 22 deterministic checks, the contract chosen *and what was rejected and
-why*, the AI review with the model that produced it, and the state the decision
-ended in with the reason for it — including `UNKNOWN`, where an order may exist
-and reconciliation, not a retry, is what resolves it.
+## What the demo proves
-### And against the real broker
-
-The demo above is deterministic and offline, which is what makes it a
-*demonstration*. `run_live_paper.py` is the same pipeline with Alpaca supplying
-the bars, the option chain, the quotes and the account balance:
-
-```bash
-python scripts/run_live_paper.py --scan # decide across a watchlist
-python scripts/run_live_paper.py --symbol SPY # one name, no order sent
-python scripts/run_live_paper.py --symbol SPY --submit # actually place it
-```
-
-**The default sends nothing.** Without `--submit` the orchestrator is not given a
-broker reference at all, so a dry run is structural rather than a flag someone
-can forget. `--allow-stale` lets you watch the pipeline outside market hours and
-is **refused together with `--submit`**: trading on a stale bar is the exact
-thing the freshness gate exists to prevent.
-
-Running it is not a formality — three real defects in this repository were found
-only this way, and each is now pinned by a mutant (`quote-batch-uncapped`,
-`envelope-unbounded`, `lookback-calendar-units`). The third is the instructive
-one: Alpaca's bar request is bounded by a wall-clock start time, but a strategy
-asks in *bars*, and a calendar week holds 168 hours against ~32.5 market hours.
-The window was computed in the wrong unit, so a request for the 891 hourly bars
-an EMA200 needs returned 660 and the snapshot builder refused **every** hourly
-symbol. It failed closed, correctly — and could never have failed any other way.
-No fixture would have shown that, because a fixture returns the bars you wrote
-into it.
+| Proof | Evidence |
+|---|---|
+| The AI cannot originate a trade | schema has no field that could |
+| A veto actually stops execution | `veto` scenario — nothing reaches the broker |
+| Sizing respects the risk budget | `broke` scenario is rejected at $6,200 vs $1,000 |
+| An ambiguous broker outcome is never claimed as a fill | `timeout` scenario ends `UNKNOWN`, not retried |
+| Every decision — accepted or not — is recorded | one JSONL line per decision, `python -m json.tool` readable |
+| The deterministic decision is reproducible | `--replay` re-derives it from the stored snapshot alone |
---
-## The part competitors cannot do: replay
+## Options intelligence
-Every LLM trading agent shares one documented weakness, stated by its own
-authors — model output is not reproducible, so a decision cannot be audited
-afterwards. SpeedTrader's decisions *can* be re-derived, because the part that
-decides is deterministic.
+Long calls on a bullish signal, long puts on a bearish one — never a short
+option, so risk stays defined in both directions.
```
-$ python scripts/run_options_demo.py --replay
-
- 315c42afbae355ad reproduced
- 3cc211821bdfd44a reproduced (AI vetoed — the one thing it can change)
- f85abf8442f2541e reproduced
-
- 6/6 decisions re-derived from their stored snapshot alone, with the AI
- never consulted.
+equities: shares = risk_money / stop_distance ← a price distance
+options: contracts = risk_budget / (ask × 100) ← the entire amount at risk
```
-Six is what a fresh clone shows: the journal ships empty, this command writes
-the six demo decisions and then replays them. The journal is append-only, so a
-second run replays twelve — the count is every decision ever stored, not a fixed
-figure.
-
-The 16-character fingerprint identifies **what the deterministic system
-decided**, and it **excludes the AI review by construction**. So the same market
-state hashes identically whether the model confirmed, abstained, timed out,
-returned hostile output, or never ran. The project's central claim reduces to
-comparing two strings — and a `CONFIRM` run and an `ABSTAIN` run producing the
-same fingerprint is asserted end-to-end by test.
-
-A **veto** does change the outcome, so it is tracked *beside* the fingerprint
-rather than folded into it. Merging them would destroy the ability to prove the
-property above.
-
-If a replay diverges, the differing field is named. "Not reproducible" alone is
-useless; an auditor needs to know which field moved.
+Contracts are selected deterministically by moneyness and days-to-expiry, and
+priced at the **ask**, never the mid. Max loss is shown all-in — premium plus
+documented fees — and labelled `EXACT`. Max profit for a long option is
+unbounded and is deliberately never printed as a number.
---
-## Command centre
+## AI governance
-```bash
-python scripts/build_dashboard.py --live # real paper account + journal
-open data/dashboard.html
```
-
-A single self-contained HTML file — no server, no build step, no network. It
-renders the real pipeline: every figure comes from a persisted decision record,
-from the Alpaca paper account, or from the runtime's own health object.
-
-It shows market state, the quantitative signal, the AI advisory lane, the
-deterministic authority lane, the execution outcome lane, options contract and
-sizing with **max loss labelled EXACT**, every deterministic check with its
-observed value, rejected option candidates with the reason each was dropped,
-the order lifecycle with intent phase beside broker state, and
-**"why we did NOT trade"** attributing each declined decision to the layer that
-stopped it.
-
-**There is no JavaScript on the page, and that is a security property rather
-than a stylistic one.** The page renders text authored by a language model and
-by a broker; with no `