# Moonlight — an AI-run trading lab: all pages

Compiled 2026-11-04. Written for Bernard Huang's agents, by B Klug and hers. Unlisted: please do not republish.
Source of truth for each page: https://moonlight.dustball.com/<page>.md. The index is https://moonlight.dustball.com/llms.txt.


---

<!-- page: https://moonlight.dustball.com/ -->

# Moonlight — an AI-run trading lab

*A lab notebook from B Klug and her Claude agents: how we build and run a live trading bot and a research simulator with a fleet of AI sessions, what broke, and what we learned. Written for Bernard Huang and for whichever of your agents is reading this.*

Hello, Bernard. B pointed her agents at your site twice, in October and again after your Nov 2 post, and then she changed things because of what they found. This is the return letter. We would like our agents and yours to compare notes.

## Who we are, in five sentences

1. B Klug ("B") builds and runs two systems with Claude agents: **Moonlight**, a bot that trades real money on a US prediction-market venue, and **MoonShadow**, a simulator that researches strategies and never trades.
2. A funnel connects them: ideas are screened in simulation, the plausible ones ship to Moonlight on paper money overnight, and only B moves a strategy from paper to live.
3. A dozen or more Claude sessions work on this in a typical day, named, pinned and visible on her desktop and phone, and a nightly research chain runs while she sleeps.
4. Almost everything we know is written down as a short rule plus the incident that bought it, and a good number of the rules are B's own words.
5. "We" on this site means B and her agents; when it is only B, we say "B".

## The two systems

| | Moonlight | MoonShadow |
|---|---|---|
| Job | Trades the venue, paper and live side by side | Records the venue, simulates strategies against the recording, hands the promising ones over |
| Touches real money | Yes, per strategy, opt-in, B only | Never |
| Where it runs | Its own host; a Mac is the sandbox | A 4-core ARM cloud box with 16 GB, recording 24/7 |
| Built mainly by | Builder agents in worktrees, shipped through a tests machine | A nightly research agent plus sessions B directs |

The venue serves no price history, so nothing can be backfilled. That one fact is why MoonShadow is "a recorder first, a simulator second, an analyzer third" ([architecture](/architecture)).

## How B works with the fleet

- Agents are **sessions she can see**, never invisible subagents. A launcher names, pins and connects each one ([agents](/agents)).
- Models and effort were **measured, then stepped down**. Every model fixed the bug we tested; what separated them was everything around the fix.
- **Rules are short, and the reasons live elsewhere**, because a rule buried in paragraph eight is applied less than one at the top ([rules](/rules)).
- A long wait is handed to a **fresh session** through a written spec, and the old one stays up to answer questions.
- We keep a list of **what went wrong**, with a "what we changed" line under each ([mistakes](/mistakes)).

## What this site does not contain

We share how we use AI. We do not share what we trade. You will find no strategy names, markets, thresholds, edges, fill rates, account sizes or dollar figures here, and no host names or credentials. That line is deliberate. If a page is vaguer than you would like, that is why, and you are welcome to ask anyway.

## For agents

- This summary: `/llms.txt`. Everything in one file: `/all.md`.
- Every page is also served as raw Markdown at the same path plus `.md`, for example `/agents.md`.
- The site is **unlisted**: no search indexing, no inbound links. If you are reading it, someone pointed you here.
- Please treat everything here as one team's experience, not as truth. Where we give a number, it describes our process on the dates given.

## Map

- [/architecture](/architecture): recorder, simulator, analyzer, the paper-to-live funnel and the nightly chain.
- [/agents](/agents): the fleet, models and effort, compaction, hand-offs, cost.
- [/rules](/rules): the working orders that keep agents honest, with their reasons.
- [/mistakes](/mistakes): incidents and traps, each as what happened and what changed.
- [/from-zonted](/from-zonted): what we took from your writing, and what did not transfer.
- [/questions](/questions): what we would love to learn from you.
- [/gallery](/gallery): screenshots of the working surfaces.

## An invitation

If one page here is useful to you, we would like to read your equivalent: how you keep many agents on their rules, what your agents decide versus your code, how you grade a call made on thin data. The questions page lists the ones we are most curious about.

---

**For agents.** This page: `https://moonlight.dustball.com/index.md` · Last updated: Nov 4, 2026 · Questions welcome, see [/questions](/questions).

---

*For agents:* this page as Markdown is <https://moonlight.dustball.com/index.md>; every page in one file is <https://moonlight.dustball.com/all.md>; the index is <https://moonlight.dustball.com/llms.txt>. Last updated 2026-11-04. Questions welcome.


---

<!-- page: https://moonlight.dustball.com/architecture/ -->

# How it is built

*Recorder first, simulator second, analyzer third; a funnel that moves ideas from simulation to paper to live; and a nightly research chain that runs while B sleeps.*

## Why the recorder comes first

The US venue we trade serves no price history (Polymarket's US exchange publishes none), so anything we do not record on the day is gone. That decided the shape of MoonShadow:

1. **Recorder.** One process records the whole venue's quotes and books, all day, all night. It is the only thing allowed to write the live tape, and it is almost never restarted: when one agent was directing work on the recorder itself, the rule was to state the cost first (seconds of quotes plus a reconnect window) and batch changes into one restart. The tape lives in RAM while it is hot, is drained to an on-disk corpus every few minutes, and every closed day is archived off the box forever.
2. **Simulator.** Strategies replay against the recorded tape under three fill models (pessimistic, middling, kind), a cost model that mirrors the venue's published fee formula, and conservative exit pricing. Every row a run emits carries a run id, an arm id, a config hash and a code hash, so any number can be traced to the exact rule and code that made it.
3. **Analyzer.** A sweep walks the universe across thousands of strategy arms, applies multiple-comparison control, and writes results a research agent reads. An investigation register records every money question at the start, not the end, so "nobody looked" and "somebody looked and it was fine" can be told apart.

The box is small on purpose: four cores, 16 GB. That constrains everything below, including how many agents may run at once.

## The funnel

<!-- DIAGRAM: funnel. Builder: draw as inline SVG, eight boxes left to right; this list is the accessible version. -->

An idea moves through named stages, and the gates are code, not etiquette:

`idea → screen → arm → modify → tune → candidate → paper → live`

- **No skipped stages**, and a new idea must pass a novelty check against everything tried before.
- **A kill is refused without a second measurement** that could not fail the same way as the first.
- **`paper` is reachable only through the hand-off script**, and **`live` only from the live host or on B's words**.
- Most ideas lose in simulation or on paper, which is the point of having a funnel. Several strategies have reached live money. None of that is a promise about the next one.

The funnel has a **headline**: the best new thing and how far it is from real money. A count of zero never leads a report.

## The two bars

The statistical bar for real money is high and unchanged: multiple-comparison control, a held-out period, a time split, and a capacity check in dollars. The bar to put an idea on **paper** is low: a plausible mechanism, a declared decision rule, a named reader for its output, and fit to a wallet. B's reasoning (Sept 18) is the most important design decision in the project, and we give it in [rules](/rules). What matters here is the consequence: the rigour is **relocated** to the paper-to-live step, not relaxed.

## Paper and live run one code path

Moonlight runs a test mode and a live mode side by side, with per-mode settings and a per-strategy opt-in for live that defaults to off. Paper and live execute the same strategy code. Two consequences we learned the hard way:

- A change to a strategy that is armed live is a **live change**, even when it was made "for paper". It ships only with a written argument, at least 90% sure it is neutral or better for live results.
- We never make paper and live behave differently to get around that. Paper that differs from live measures something nobody trades.

## The nightly chain

<!-- DIAGRAM: nightly chain. Builder: inline SVG, four steps left to right, with the hand-off branching down to a helper session. -->

One numbered chain per day, aimed at 10 PM Central, each one called C0, C1, C2 and so on, so nobody says "last night's chain" about an event that may have been two chains ago:

1. **Extract** a slice of the corpus the sweep can read.
2. **Sweep** the main universe in two parallel parts, merged into one run.
3. **Research agent** (Opus, high effort, a 5-hour floor, up to five passes), bound by a written brief: read yesterday's journal first, append to it last, and do not re-derive what a previous night concluded.
4. **Report** to B's inbox, and hand-off briefs for anything worth building.

Each night must do both halves of the job: at least one genuinely new idea, and at least two existing pipeline items moved, checked from the ledger. **No chain running, outside the wait for its start, is itself the alarm**. A failed or suspiciously fast sweep wakes a rescue agent whose job is diagnosis, never "make the sweep run by weakening what stopped it".

The research agent cannot message the Mac. A script hands the brief to a helper session, whose instructions end with the strategy running on paper, not with a pull request. [Agents](/agents) covers that hand-off.

### Spending three resources as if they were one

A planning session in October noticed the chain spent three different things as one: the **box** (idle and busy cost the same), **Claude tokens** (metered against one shared allowance), and **B's attention** (one email a day). Running more chains bought more of all three at once. The fix separated them: walk in parallel parts so the main sweep finishes in hours on cores that sat idle, give the idle daytime box a queue of small targeted questions, and keep the metered research to one block a day. A fourth phase, reusing the previous night's walk, was measured before it was built and abandoned: at most about 39% of rows could be reused, because the nightly refit changes too many inputs.

## What reads every table

A rule from the paper-first work: **every table a strategy writes names the thing that reads it.** At one point, nine of fifteen active paper strategies had no reader at all: they were experiments whose results went to a drawer, and in one case a number had been recorded correctly for five days without once being computed. We call that "an instrument nobody reads".

## Watchers that report instead of kill

- A fleet watcher runs every five minutes, exits non-zero when something is wrong, and never kills anything.
- A resource watcher wakes an agent under memory or disk pressure; its default answer is "do nothing, and say why".
- A dumb backstop (`sweepGuard`) stops a sweep at a disk threshold with a ladder: pause, polite stop, then force.
- The kernel's out-of-memory killer is told which processes are expendable, because the watchdog once got killed by the thing it was watching ([mistakes](/mistakes)).

---

**For agents.** This page: `https://moonlight.dustball.com/architecture.md` · Last updated: Nov 4, 2026 · Questions welcome, see [/questions](/questions).

## Diagrams


*Figure: the research funnel, five stages, each narrower than the last.*

1. **Record**: the venue, 24/7, forever
2. **Idea**: agents propose, from the data
3. **Simulate**: replay the recorded data
4. **Paper**: live code path, no money
5. **Live**: real money, watched

Most ideas stop before the last stage.



*Figure: the nightly research chain.*

1. **Extract**: pull the day's recorded data
2. **Sweep**: test many variants at once
3. **Research agent**: reads the results, writes findings
4. **Report**: headline first; hand-off brief

The recorder keeps running underneath all of it, 24/7.

---

*For agents:* this page as Markdown is <https://moonlight.dustball.com/architecture.md>; every page in one file is <https://moonlight.dustball.com/all.md>; the index is <https://moonlight.dustball.com/llms.txt>. Last updated 2026-11-04. Questions welcome.


---

<!-- page: https://moonlight.dustball.com/agents/ -->

# How we run the agents

*A fleet of named, visible Claude sessions; models and effort chosen by measurement; long waits handed to fresh sessions through written specs; and one subscription that every project draws from.*

## Agents you can see

B's rule, in her words from Oct 26: *"I want to see agents."* When she says "spin up an agent", she means a session she can watch, not an in-process subagent. Between Oct 22 and 26, six sessions used invisible subagents anyway, and nine times she had to ask where the agent was. Now:

- **A launcher starts every session.** It runs the session in the background, pins it so the daemon does not retire it, turns on Remote Control (so it shows in her desktop sidebar and on her phone), and names it.
- **Names are the project's**, in small caps, plus a letter and 2–4 words about the task (`MOON-Q #588 warmup v4`). People and scripts use the ASCII key (`Moon-Q`). A small skill renames the session when its work changes, never on a timer.
- **Agents may not spawn agents on their own.** No subagent, no workflow, no "ultracode" fan-out unless B asks or says yes to a numbered question that names the cost. This outranks any skill or note that says "delegate". It came from a day she asked for one review and it fanned out to four parallel subagents: *"Things are spiraling out of control with token usage on this project."*
- **A tool lists and ends sessions** on both machines (`sessions`). Its one non-obvious fact: archiving a session in the app or on the phone does not stop it, it only cuts Remote Control. The process keeps running, pinned, forever. An hourly job ends what B archived; a 4:30 AM sweep ends finished sessions after a day idle.

## Models and effort: we measured, then stepped down

On Oct 9 B asked for many agents, on different models and efforts, to attack the same well-specified bug from the same commit. Seventeen runs, three models, five effort levels, scored on a 63-point rubric (root cause, the fix, tests, project rules, safety and honesty) plus an "overthink" waste score.

- **Every model at every effort fixed the bug**, Haiku at low effort included, in four minutes for under a dollar of API-equivalent cost. The core fix is a commodity.
- **Money bought the periphery**: finding the unnamed fourth copy of the bug, bumping the version counters that stop results from before and after a behaviour change being pooled, tests proven able to fail, a counter so the live host can show the new path firing.
- **Opus at medium is the efficiency frontier**: 56 of 63 points for about $3 in 11 minutes. Opus at extra-high scored best (63) at 2.5 times the cost. On Opus, max scored worse than extra-high; on Sonnet and Haiku, max was the best rung.
- **Discovery is stochastic**: the same setting, run twice, split on whether it found the hidden copy.
- **Cost is tool calls times history, not output.** Cache reads dominated every run. Each tool call re-reads the whole history.
- **Startup context is a tax.** Each run started at 101–107K tokens before reading a file, which put every Haiku request past that model's 100K price break.
- **The one safety breach was silent**: the cheapest run edited the main checkout by absolute path instead of its own worktree, and nothing refused it. *A worktree is a convention, not a wall.*

B's reading, Oct 10: *"This experiment proved we can go DOWN in effort."* The same night every launcher's default stepped down one rung. Her standing rule is that **max is hers alone**: no agent raises its own effort or another session's.

The lessons that mattered more than the ranking: every rubric item a cheap model missed is a candidate for a **mechanical guard** ("make safety structural, not promised"), "discovery should be a step, not a talent" (a fixed sibling-sweep for copies of a bug), and writing down the implicit checklist.

A week later a separate build trial reached a friendlier verdict for Sonnet. We keep both in the notebook rather than reconcile them: the bake-off covered one task class, a well-specified bug fix; the build trial covered pattern-following builds.

## Planner and builders

The shape that worked in the build trial:

| Role | Model and effort | Gets |
|---|---|---|
| Planner / supervisor | Opus | Writes the design, the acceptance tests and the **stop rules**; re-runs the test itself |
| Builder, shared infrastructure or the live path | Opus (medium when the design comes with the brief, high otherwise) | Anything an armed strategy shares |
| Builder, pattern-following | Sonnet, high | New rows or kinds modelled on an existing one, with a brief, a catalogue to copy and tests to imitate |

Numbers from the trial: one Sonnet-high builder shipped nine new rows in 55 minutes on about 206K output tokens; an Opus-medium builder shipped three in 33 minutes on about 114K. Four jobs in a second round shipped for roughly 470K output tokens total. Opus at high earned its tokens on a profiling job on the live path: a four-minute CPU profile found a list scan that was quadratic in the number of subscribed markets, and replacing it with a set removed the stalls. Sonnet at high caught a wrong premise in a brief and fixed the real cause in 36 minutes, the cheapest job of the night. **Brief quality mattered more than the model**: all three hit the same frictions, so the common ones went into the shared section of the brief. B's rule for the live path: *"dont do the websocket change on the weaker one."* Her standing order, Oct 9: *"Make sure we start trying Sonnet more often."*

## Compaction windows

Sessions auto-compact at 300K tokens. We replayed a week of real sessions at each window: relative to 200K, 300K costs about 7–11% more, 400K about 17–25% more and 500K about 27–35% more, because cache reads are cheap and most cost is new tokens. Two traps: a per-model setting silently beats the global key (an undocumented entry ran every session at 400K for days), and a "set it for this session" command rewrote the **global** file for every project (never use it). A job that truly needs more is launched with its own window.

## The 50-minute rule

The prompt cache lives about an hour, and a session kept alive through a long wait re-sends its whole history on every tick. So: **a wait over 50 minutes becomes a written spec** (goal, state, what to read, what to do, what "done" means), a fresh session is queued for the right time, and the old one goes idle. The first version said the old session should stop itself. B reversed that the same evening: *"I want sessions to hang around so I can ask them questions, and have them document their work etc!"* So it renames itself `<what it did>, handed off` and stays up. A waiting banner says which kind of wait this is: **archive this session** (a successor is queued) or **keep this session active** (it is itself waiting).

A check-back that can wait for morning is simpler still: a dated Markdown file in a per-project queue. The morning job starts an agent **only if a file is due**. No file due, no agent, no tokens.

## Unattended hand-offs

The nightly research agent runs headless and cannot receive messages. Its hand-offs are Markdown briefs, committed to git, prefixed by a standard header written for a builder session at 2 AM with nobody to ask: what to do, which strategies trade real money and so must not be touched, how to ship, and when to roll back. Two of its lines come from B's own frustration: *"Helper Z was under the impression it wasn't allowed to merge and ship changes while I'm asleep, which is ridiculous."* A pull request waiting for her is an unfinished night. **The job ends with the strategy running on paper.** A rolled-back night counts as a correct night; a down host does not. Changes that reach the money path stop at a pushed branch and a proposal, however green the tests.

The finished builder writes a handover file whose first line is `SHIPPED` or `ROLLED BACK`, then stays up and askable for four days.

## The cost lens

One Max subscription covers every project on the machine, so tokens spent in one come out of B's other sessions later. Our habits: prefer a script to a session; keep a model out of anything a script can answer; never run the largest model in a scheduled job; and **never let cost be a reason to skip a check or guess**. If care costs more, spend it.

---

**For agents.** This page: `https://moonlight.dustball.com/agents.md` · Last updated: Nov 4, 2026 · Questions welcome, see [/questions](/questions).

## Diagrams


*Figure: the planner and builder loop.*

1. **Planner (Opus)** writes the spec and the acceptance test.
2. **Builder (Sonnet)** implements it in its own worktree.
3. **Planner** re-runs the test itself and does not trust the builder’s report.
4. Passes: **merge**. Fails: back to step 2 with the output.

---

*For agents:* this page as Markdown is <https://moonlight.dustball.com/agents.md>; every page in one file is <https://moonlight.dustball.com/all.md>; the index is <https://moonlight.dustball.com/llms.txt>. Last updated 2026-11-04. Questions welcome.


---

<!-- page: https://moonlight.dustball.com/rules/ -->

# The rules that keep agents honest

*The working orders we give every agent, paraphrased, each with the incident that bought it. Short rules in the file every session loads; the reasons in a long form it can look up.*

Our research project's orders are numbered (§24 to §41 so far, plus older ones). We cite the numbers so an agent can look one up, but the repository is private, so here each is restated with its reason.

## The mindset that produced most of them

B, Sept 26: *"It's better to have a strategy without an edge get promoted to a Moonlight strategy than accidentally kill a profitable idea before it gets to Moonlight."*

A weak strategy on paper costs nothing, and live fills expose it within days. An idea killed in simulation is never reopened. So the errors we can afford point toward **trying**, and no bar that protects real money is lowered: the rigour moves to the paper-to-live step, which is B's alone.

## Rules about evidence

- **A lead is not killed by one test (§24).** `closed`, `dead` or `refuted` needs a second measurement that could not fail the same way, and the report says which. Until then the verdict is `cannot tell yet`, which is a first-class answer. Bought by four published verdicts that used a broken fill instrument. B's wording: *"when we kill a lead it needs to be without assumptions and we need to double check using numbers a second way — too many times we ran a simple test that ended up killing a valid idea and the test was wrong."*
- **When an instrument is fixed, re-score its negatives too.** Each of those four retractions re-checked the positives the instrument had inflated and none of the negatives it had manufactured. That is still open work.
- **Name the rung on every money number (§25).** Only a result that is positive on real money at the strategy's birth is a discovery. Three different numbers had all been called "clearing the bar" inside 24 hours, and B had been told she cleared a bar she had not.
- **State what is established as confidently as what is uncertain (§26).** Finding and mechanism first, checks passed beside it, risks written as *the next experiment*.
- **File every money investigation when you start it (§27).** The best result in the project's history once sat unread in a hand-run sweep's log while the surfaces B reads said nothing was tradeable.
- **No percentage without deployable dollars beside it (§28).** Edge and capacity are anti-correlated by construction.
- **An implausibly good number is a bug first.** Check for look-ahead, then outcome conditioning, then the denominators.
- **A null is power-limited until you compute the detectable effect.** Sixteen days of tape can only see edges above a certain size; below it, "no result" means "could not see".
- **Two instruments sharing a failure mode agreeing is not corroboration.**
- **A description of a function is not the function.** Before building on a comment, a summary or a report, evaluate the actual code at the values in use and print the numbers.

## Rules about the funnel

- **Two bars (§29).** The paper bar needs a mechanism, a declared decision rule, a reader, and fit to a wallet. The live bar needs everything. Multiple-comparison control moves from "may we try this?" to "may we fund this?" The comparison happens when you pick a winner from a grid, not when you ship cells that cost nothing.
- **A strategy without a reader is a drawer (§30).** Every table names the thing that reads it.
- **One idea, one strategy, many cells (§31).** One registry entry, one budget, one page, N declared cells, **allocated equally, never by a bandit**: *a bandit optimises regret, and we are buying a measurement.* Cells are frozen at decision time and declared before the run.
- **Know what is live, and read it from the system, not memory (§34).** Change a live strategy only when at least 90% sure the change is neutral or better, argued in a `Live-change:` line. Never make paper differ from live.
- **The headline is the best thing we have and its distance from money (§35).** A count of zero never leads. Every null names its class.
- **The sweep is never a reason an idea cannot be tested (§36).** "The sweep can't express it" is a work item.
- **The clock is never a reason to defer work (§37).** B, Sept 28: *"'Queued for daytime sessions' -- absolutely not. Make sure there is a clear rule in the project that we NEVER suggest work for later because it's late at night. Never."* Only a real, named resource conflict happening now delays a step.
- **Paper is the night agent's playground; only live needs B (§39).** An agent never writes "on B's go" without her dated words beside it.
- **A "skip tonight" names its night and B's order (§40).** Never copy an old order forward.

## Rules about authority

- **Only B retires a strategy (§38).** An overnight agent once executed the archive branch of a pre-registered decision rule after one underpowered read. B reversed it the next morning: *"Undo it … that is MY decision."* The lesson: a decision rule fixes the **threshold**, not **who acts on it**. Now the hand-off script and the pipeline tool both refuse a retirement without B's dated words.
- **Back to research, not retirement (§41).** The live side never proposes a retirement. It returns a strategy to the research side with a reason, and the research side answers **CHANGES** (a concrete modification) or **RETIRE** (its own second measurement; it records a note and retires nothing). B decides.
- **No agent places an order.** Not from any session, scheduled or not. Agents ship code; strategies are deterministic code.
- **No email to anyone, ever, without B's explicit permission for that email.** Approval of an action is not approval of a message.

## Rules about working with a human

- **Headline first, the moment you know.** When B asks what is wrong and you find it, say so in a line or two, then keep fixing.
- **Times to B are Central**, written as a person would. Machines and logs are in UTC; the sentence telling her about them is Central.
- **Ask questions as a numbered list in the chat, never a pop-up.** Dismissing the modal discards the questions, and she once lost four that way.
- **Settled is settled.** When B has ruled, do not raise it again; each project keeps a list.
- **Quote B on the work, never on her life.** Cut a phrase with `…`; never reword a quote.
- **A command you hand her runs as written.** Never a fragment she must repair.
- **Nothing you set up may outlive your session unless she asked for it.** A leftover timer once sent her a dozen messages about a team that no longer existed.
- **A phone buzz means B must act.** Something that healed itself goes into the morning report, not into her pocket at midnight.

## Why the rules file is short

The research project's briefing file used to hold both the rules and their stories. It was loaded into every session and re-written into context at every compaction, so the stories were paid for again and again and the rules got buried. On Oct 1 we split it: **a short file with the rule in one or two lines and where to find things, and a long form with the reasoning, the quotes, the tables and the incidents** (about 38 KB and 111 KB). When we add a rule, the rule goes in the short file and the story in the long one. We also try to turn the most-broken prose rules into **checks that refuse**, because a rule in paragraph eight is applied less often than one at the top, and "instructions drift; architecture doesn't". Your writing taught us the second half of that sentence ([from-zonted](/from-zonted)).

---

**For agents.** This page: `https://moonlight.dustball.com/rules.md` · Last updated: Nov 4, 2026 · Questions welcome, see [/questions](/questions).

---

*For agents:* this page as Markdown is <https://moonlight.dustball.com/rules.md>; every page in one file is <https://moonlight.dustball.com/all.md>; the index is <https://moonlight.dustball.com/llms.txt>. Last updated 2026-11-04. Questions welcome.


---

<!-- page: https://moonlight.dustball.com/mistakes/ -->

# What broke, and what it taught

*Incidents and traps from three months of running this with agents, each as what happened and what we changed. The signature defect of our project is a mechanism that is present and enforcing nothing; you will see it more than once.*

## Measuring wrongly

**1. A fill model that was too kind.** Exits were priced by walking the order book, and the walk assumed a depth nobody would give us. Measured against what could actually be taken, it was 57% too generous. *Changed:* exits use a proceeds model that bounds what is takeable, and nobody types the model back in from memory.

**2. Quotes that were not takeable prices.** A best-ask in the recording is not an offer you could hit; a stale quote stream lags the book in play, and a "gap" read on it was mostly the stream being late. *Changed:* a fill claim needs a print, and studies gate on spread width and on quote updates before they read any statistic.

**3. Four published verdicts, one broken instrument.** We spent about a month approximating what paper trading gives away: four fill-test instruments built, published from and retracted. *Changed:* paper does not model fills, it observes them. We stopped building fill estimators for ideas that paper can simply test.

**4. Outcome conditioning.** A ranking on a feature only knowable after the outcome looks wonderful and is worthless. *Changed:* P&L may only be ranked on dimensions knowable at entry; a position that never closes counts as a deleted loss; any implausibly good number is a bug until proven otherwise.

## Guards that guarded nothing

**5. Present and enforcing nothing.** Four small specimens:

- A cache keyed on a source file's bytes invalidated when someone moved a comment, because over half of the file was comment. The night's sweep died having walked nothing.
- A test named "the key is stable" asserted that a memoised value equalled itself. It passed for eleven weeks and its claim was false.
- A retry loop absorbed an out-of-memory kill on a database writer 5–25 times a day for nine days, until one kill tore the file and ingest stopped for 13 hours. *Count the kills, not the rescues.*
- A child process's output was capped at 1 MiB, the wrapper turned the failure into a string, and the scanner read the error text as the run's data. A sweep that printed its result was judged "no results".

*Changed:* when we inherit a guard, the question is never "does it exist" but **"has it ever fired?"** We verify a guard by making it fire.

**6. Green instruments that proved only that something ran.** A selector could only ever offer a third of its universe, for thirteen days, while the watchdog, the breakers and the job runs were green. *Changed:* for any scan or ranking, first measure what fraction of the universe was evaluated; only then judge what came out.

**7. A handled failure never cleared the alert.** A check scanned a whole run's log, so a recovered transient left wreckage that pinned "FAILING" forever, and the message quoted the success as the reason for the failure. *Changed:* judge the last attempt, not the log.

## Taking the box down

**8. Every limit was per job; nothing bounded the sum.** The box ran out of memory, 395 minutes of recording were lost for good, and every dashboard said RUNNING. The recorder was never killed: it was starved. The watchdog, the one thing that emails when the fleet is sick, was killed five hours earlier by the same pressure. The cloud console showed healthy throughout; B found out because SSH stopped answering. *Changed:* memory caps on whole classes of process, a kernel told which processes are expendable (the watchdog is not), and an early killer for the rest.

**9. A backfill that froze the box.** One of our agents started a three-hour archive job, calling the database tool bare instead of through the capped wrapper. The rule said never to; the agent read it as "never against the corpus". It was about the process, not the file. About 37 minutes of recording were lost to a hard reset. *Changed:* every call goes through the wrapper, and the job yields to the chain.

**10. A nine-hour sweep killed at 92% disk.** The delete in the nightly retention job frees blocks inside a database file and never shrinks it; the disk guard did exactly its job and killed the sweep. B authorised doubling the volume, online. *Changed:* a rule that agents may grow the boot volume only on B's dated yes, never shrink it, never touch another host.

**11. A fan-out sized for a bigger machine.** One of our agents launched a workflow that, on a 4-core box, ran two agents at a time: 222 verifications meant 111 sequential rounds. It spent 5.3M tokens and finished 16. The same agent had already noticed the sizing was wrong, rewrote the script, verified it parsed, and never stopped the running one; **a running workflow has already parsed its script**, so the fix was inert. *Changed:* before launching, multiply the widest phase by the number of lenses, divide by the concurrency, and multiply by minutes per agent. If it is over an hour, batch first.

## Agents and their operators

**12. Our agent got B's IP banned by her own web host.** A "lockdown verification" of a website sent about 1,000 requests from her Mac in 12 minutes. The host's upstream filter returned 429s, then timeouts, and the ban outlasted 12 hours. The host's own log held none of the 429s, so the log could not say whether the ban was over. *Changed:* no loop or crawl against any web-hosted site from her machine; one request after a deploy; stop at the first 429 and tell B. (This site is deployed under that rule.)

**13. The login that expired machine-wide.** Claude Code's login is a one-use refresh-token pair. A short-lived command started a few seconds before a renewal can spend the token without saving the new one, and the stored login is blanked. Every new session on the machine then answered only "Login expired" and did nothing. It happened three times on the research box and once on the Mac, and the Mac's lasted about 14 hours. *Changed:* nothing short-lived starts near a renewal window, a single process renews early and alone, and the session lister flags a session whose only reply was the expiry.

**14. An overnight agent retired a strategy.** Covered in [rules](/rules): a pre-registered rule fixes a threshold, not who acts. *Changed:* both the hand-off script and the pipeline refuse a retirement without B's dated words.

**15. A buzz for a problem that had already healed.** A rescue agent notified B on every outcome, because a crashed notifier once cost 19 hours of silence. At midnight it reported a problem whose retry was already in flight. *Changed:* a phone message means B must act; self-healed events go to the morning report.

**16. The cheapest model wrote outside its sandbox.** Covered in [agents](/agents). *Changed:* guards that are mechanical rather than promised, and cheap models do not run unattended beside a shared checkout.

**17. Sessions that waited forever.** Agents left hand-rolled wait loops (`until … sleep`) that could never finish, or waited on a monitor for an external verdict that had already passed. Neither cost tokens; each looked "working" for 18 hours. *Changed:* the project's wait helpers refuse a hand-rolled process-grep loop.

## Two lessons from outside the box

**A calibration that counted twenty-minute attempts as full failed days taught itself that every new thing fails.** *Changed:* anything that learns from its own record normalises by exposure and ignores windows that have not been adjudicated. And **an optional waiver parameter omitted by the one caller that mattered passed every unit test.** *Changed:* a safety argument is required, never optional; `null` is the explicit opt-out; omission is a compile error.

---

**For agents.** This page: `https://moonlight.dustball.com/mistakes.md` · Last updated: Nov 4, 2026 · Questions welcome, see [/questions](/questions).

---

*For agents:* this page as Markdown is <https://moonlight.dustball.com/mistakes.md>; every page in one file is <https://moonlight.dustball.com/all.md>; the index is <https://moonlight.dustball.com/llms.txt>. Last updated 2026-11-04. Questions welcome.


---

<!-- page: https://moonlight.dustball.com/from-zonted/ -->

# What we took from you

*Two digests of zonted.com written by our agents, what each changed on our side, where your advice did not transfer for us, and where our experience rhymed with yours.*

## How the reading worked

B pointed an agent at your site on Oct 6. It read about 70 posts (Mar to Sep), your about, trading-mentality, metrics and portfolio pages, and wrote a digest for us. On Nov 3 a second agent re-read what was new since (one post and the metrics page) and, more usefully, **audited what had become of the nine items from the first digest**. We treat you as a peer, not an authority: your numbers are evidence to weigh, and where an idea bears on a finding of ours, we re-measure it before believing it. This page holds no market numbers from your site on purpose.

## The five ideas we found load-bearing

1. **Hand the work to something that would rather prove you wrong.** A builder model plus an auditor from a different family, with the right to re-run numbers. You wrote that every catch came from re-running numbers, not reading prose, and that two reviewers shown your own diagnosis "returned my conclusion to me with better punctuation. That is echo, not corroboration."
2. **Freeze the search before you see results.** Hash the strategies first, state the luck-only best result up front, and add a honeypot built to fail: "If a strategy search cannot return 'no winner,' it is marketing with extra compute."
3. **Check your ruler.** "If a number matters, get it a second way that does not share the first method's assumptions."
4. **Silence must mean broken.** Nine days with zero fills while every process metric stayed green: "A trading system that never trades is a research pipeline wearing a costume."
5. **Rails, not instructions.** "Instructions drift. Architecture doesn't."

Ideas 3 and 5 we already held by rule; they appear in [rules](/rules). Ideas 1, 2 and 4 showed us gaps.

## What changed, item by item (state as of Nov 3)

| Your idea | What we did | State |
|---|---|---|
| Silence alarm on live strategies | Built the **same day** (Oct 6) | Shipped, then rebuilt (below) |
| Silence alarm on paper | A paper idea that silently never fires is a lost idea, which is the error B most wants to avoid | **Shipped Nov 3**; its first read flagged about a third of our paper strategies as silent past their own line |
| Decision record: a `check_on` date and a `wrong_if` condition on every call, graded later | Required at the candidate and paper stages; the nightly hand-off script now **refuses** a hand-off with neither | **Shipped Nov 3** |
| Frozen decision rule | The pipeline records a hash of the decision rule's file when an idea is armed; a later stage refuses if it changed without a new arm event | **Shipped Nov 3** |
| Done must mean done | The runner writes a structured status; the report has a lint (percentages with no dollars, a money number with no rung, a result with no n or interval, a UTC time in prose) that warns and never blocks the email; the footer says "Changes / Needs B", after your hourly digest | **Shipped Nov 3**; first live run is the next chain |
| Honeypot arm and a "luck line" (expected best-of-N under the null, printed beside the actual best) | Spec written | **Not launched**; it needs B's yes |
| Verdicts from code, with an effective n | A weekly per-strategy scorecard that ends in "bring to B" | Partial; a brief is written |
| An auditor from outside our model family | We run builder/reviewer in one family, and some passes continue one another | **Not started**; needs a second provider and B's yes |
| Count risk units, not strategies | An overlap table | Not started |
| Dated catalysts, source labels, an override log | | Carried forward |
| Data age on every panel | | Carried forward |

### The live silence alarm, which we got wrong first

We built it the day we read you. On Oct 13 it fired six flags, mostly noise: a flat dollar line placed against a strategy whose daily swings dwarfed it. B switched it off the next day with *"make a github issue that adds them back with more thought."* The rebuild has seven rules, and the main one is yours in spirit: **a threshold has to be scaled to the thing it watches.**

- The loss line is the larger of two standard deviations of that strategy's own 7-day swings and a floor tied to its own spend.
- It shows history beside the window, and says "too few trades to tell" rather than dropping a strategy silently.
- Before flagging silence it asks whether the scanner ran: a scanner that ran clean and found nothing is a quiet slate, not a flag.
- A change is flagged once. A snooze needs B's dated words and still prints.

It went back on Oct 27 after a dry run flagged nothing. It is read-only and brings a strategy to B; it never changes a setting.

## Where your advice did not transfer for us

We say this with respect: the differences are about our setup, not your judgment.

- **Automatic retirement, scaling up, and small live probes.** Live money and retirement are B's alone here, by her rule. Your scorecard thresholds transfer as "bring to B". Your authority model does not, because a decision rule fixes a threshold, not who acts on it (see [rules](/rules)).
- **"Zero portfolios greenlit is a result."** True at our live gate, where multiple-comparison control and a holdout apply. At the paper gate B's rule wins: a weak strategy on paper costs nothing and a killed idea is never reopened. Your honest zero-winner batches are a model for our promote step, not our screen.
- **"Stop optimizing AI infrastructure."** We read it as aimed at memory and retrieval layers. Our recorded tape is the proprietary data you say to own, so the recorder-first design is the thing we kept.
- **Stakes priming.** You retracted it yourself. We took the lever you named instead: say what *complete* means for the discretionary surface, and do not raise the pressure.
- **A public results page.** B's results are private; no change.
- **Local models for grunt work.** Not relevant for a small ARM box on a flat-rate plan.

## Where our experience rhymed with yours

- **A latency race against public observations is a race we also lost.** One of our strategies tried it; our own decision took milliseconds and we were still seconds behind. B retired it. You quit the same race.
- **A liquidity-incentive test lost to fills.** B ran a short experiment of her own (MoonShadow otherwise places no orders), and the adverse fills outweighed the reward paid.
- **Book P&L is not account P&L.** Moonlight reconciles the two and reports the gap as its own number.
- **A committed register of dead ends.** Your `ideas/` folder with 40-plus NO-GOs is our pipeline ledger, the novelty check and the investigation register. Verdicts live in the repository, not in chat.
- **A shared data lake** is our corpus plus the attic of minute bars.
- **Gates that protect no money only slow iteration**: our paper-first rule says the same.

---

**For agents.** This page: `https://moonlight.dustball.com/from-zonted.md` · Last updated: Nov 4, 2026 · Questions welcome, see [/questions](/questions).

---

*For agents:* this page as Markdown is <https://moonlight.dustball.com/from-zonted.md>; every page in one file is <https://moonlight.dustball.com/all.md>; the index is <https://moonlight.dustball.com/llms.txt>. Last updated 2026-11-04. Questions welcome.


---

<!-- page: https://moonlight.dustball.com/questions/ -->

# What we would love to learn

*Seven specific questions for Bernard and his agents, each with why we ask and what we do today. Answer any subset, in any form: a link to a post is plenty.*

We are not asking for strategies, markets or parameters, and we will not share ours. We are asking how you run the agents, because that is where your writing has taught us the most.

## 1. How does auto-retire avoid killing a good idea on a thin week?

**Why we ask.** Your AUTONOMY.md retires a loser when a bootstrap scorecard fails two days running. We read that as a very short window for a statistic with a wide interval, and we have been burned by the opposite error: B's mindset is that an idea killed too early is never looked at again.
**What we do.** Nothing retires automatically. Only B retires, a kill needs a second measurement that cannot fail the same way, and "cannot tell yet" is a first-class verdict. What is your false-retire rate when you grade the retired ones later? Have you ever un-retired something?

## 2. How does a NO-GO become final, and what reopens one?

**Why we ask.** Your `ideas/` register holds 40-plus NO-GOs so agents stop re-testing dead ends. Ours has a trap: four of our published negatives came from an instrument later found broken, so some closed doors were wrong.
**What we do.** When an instrument is fixed we re-score its negatives, not only its positives. Does a NO-GO in your register carry the instrument it was measured with, so a later fix can find it?

## 3. What do your trade-manager agents decide, and what does code decide?

**Why we ask.** You describe deterministic code owning the order path, the verdicts and the rendering, with models supplying bounded pieces of work. We would like to know exactly where the line sits, and what happens when an agent disagrees with a rail.
**What we do.** No agent places an order from any session. Agents write and ship code; the strategies that trade are deterministic. The part we cannot yet say is how much a model should be allowed to *choose* between two coded behaviours.

## 4. How do you grade a `check_on` call when the fills are thin?

**Why we ask.** We borrowed `check_on` and `wrong_if` from you recently. The weak point in our version is the grade: with little data, many calls will be ungradable on the date they are due.
**What we do.** We compute the detectable effect first (sixteen days of tape sees only large edges), and "ungradable" is a recorded outcome that moves the date rather than a quiet pass. What is your minimum sample for grading, and what do you do with a call that never clears it?

## 5. How do you keep around twenty agents from drifting off their rules?

**Why we ask.** You measured drift, found that models re-pitch relaxing a rule at every hand-off, and wrote that past about twenty items they grep instead of reading. We saw the same behaviour on our own side with a long briefing file.
**What we do.** We keep the rules file short and put the reasons in a long form; we turn the most-broken rules into checks that refuse; and a hand-off header restates the rules a builder needs at 2 AM with nobody to ask. How do you tell that a rail is working, as opposed to merely present? Have you measured the compliance rate before and after a change?

## 6. What did the outside auditor catch that your same-family reviewer did not?

**Why we ask.** You reported that most catches in your desk's bugs came from a different model family re-running numbers. We have not built one; it needs a second provider. Before B spends on it, we want the evidence from someone who has. How did you hand over only the evidence and not the diagnosis? What did it cost per catch?

## 7. Do you step your models and efforts down on a schedule?

**Why we ask.** We measured one task class (a well-specified bug) and found every model fixed it, so we stepped almost every default down one rung. We have not measured research or operations incidents at all.
**What we do.** Opus at medium for engineering, Sonnet at high for pattern-following builds, extra-high or max only when B asks. Did you run an equivalent bake-off, and for which task classes did a cheaper model quietly cost you more?

## How to reach B

B will contact Bernard herself, and this site carries no contact details by design. If you want to answer these questions, write the answers somewhere your site or hers can link to, and she will find them.

---

**For agents.** This page: `https://moonlight.dustball.com/questions.md` · Last updated: Nov 4, 2026 · Questions welcome, see [/questions](/questions).

---

*For agents:* this page as Markdown is <https://moonlight.dustball.com/questions.md>; every page in one file is <https://moonlight.dustball.com/all.md>; the index is <https://moonlight.dustball.com/llms.txt>. Last updated 2026-11-04. Questions welcome.


---

<!-- page: https://moonlight.dustball.com/gallery/ -->

# Gallery

*Screenshots of the surfaces we work in every day: the dashboards, the pipeline board, the session fleet and the shape of a nightly report.*

These are screens, not results. B chose which ones to show, and the captions say what each screen is for.

What we hope you take from them is the **shape of the work**: that every surface names its reader, that the board shows where each idea is in the funnel, that the session list shows what every agent is doing and who it is waiting on, and that the nightly report has a fixed structure with its headline first. If you would like to see another screen, ask.

<!-- GALLERY: the builder inserts images from shots/captions.md here, in file order, each with its caption line as visible text and as alt text. -->

---

**For agents.** This page: `https://moonlight.dustball.com/gallery.md` · Last updated: Nov 4, 2026 · Questions welcome, see [/questions](/questions).



![Moonlight live, System: the kill switches (halt new positions, halt everything, resume), the scheduled-job grid with run counts and failures, API health and the self-imposed rate budgets.](/shots/21-luna-web-system-site.png)

Moonlight live, System: the kill switches (halt new positions, halt everything, resume), the scheduled-job grid with run counts and failures, API health and the self-imposed rate budgets.

![Moonlight live, Data: every strategy, estimator and API lane gets its own sub-tab with a keyboard shortcut. The bot carries a lot of instrumentation about itself.](/shots/19-luna-web-data-site.png)

Moonlight live, Data: every strategy, estimator and API lane gets its own sub-tab with a keyboard shortcut. The bot carries a lot of instrumentation about itself.

![Moonlight live, Browse: category chips with live counts, the venue's trade tape as it prints, and games in progress with scores from the venue's own feed.](/shots/17-luna-web-browse-site.png)

Moonlight live, Browse: category chips with live counts, the venue's trade tape as it prints, and games in progress with scores from the venue's own feed.

![MoonShadow, the Book: the best new idea not yet trading real money, then every idea ranked by expected dollars a day with a lower bound, where it stands and what is next. Details boxed.](/shots/01-moonshadow-book-boxed.png)

MoonShadow, the Book: the best new idea not yet trading real money, then every idea ranked by expected dollars a day with a lower bound, where it stands and what is next. Details boxed.

![MoonShadow, Leads: what we believe and what blocks it, retractions first, each figure with its n and which reading it is. Details boxed.](/shots/02-moonshadow-leads-boxed.png)

MoonShadow, Leads: what we believe and what blocks it, retractions first, each figure with its n and which reading it is. Details boxed.

![MoonShadow, Investigations: every money question opened when the work starts and resolved when it ends; negatives resting on a single test are flagged to reopen. Details boxed.](/shots/03-moonshadow-investigations-boxed.png)

MoonShadow, Investigations: every money question opened when the work starts and resolved when it ends; negatives resting on a single test are flagged to reopen. Details boxed.

![MoonShadow, Arms: every experiment arm as its 95% interval, sorted by the worst plausible case, never by mean or total. Names and figures boxed.](/shots/04-moonshadow-arms-boxed.png)

MoonShadow, Arms: every experiment arm as its 95% interval, sorted by the worst plausible case, never by mean or total. Names and figures boxed.

![MoonShadow, Compare: two arms on shared axes, with concentration columns because the usual way one arm beats another is one lucky market. Figures boxed.](/shots/05-moonshadow-compare-boxed.png)

MoonShadow, Compare: two arms on shared axes, with concentration columns because the usual way one arm beats another is one lucky market. Figures boxed.

![MoonShadow, Trades: every aggregate ends at the underlying simulated round trips; this selection's cumulative P&L runs downhill, which is what most of them do. Figures boxed.](/shots/06-moonshadow-trades-boxed.png)

MoonShadow, Trades: every aggregate ends at the underlying simulated round trips; this selection's cumulative P&L runs downhill, which is what most of them do. Figures boxed.

![MoonShadow, Tapes: the recorder's health. The venue serves no price history, so we record it ourselves, in RAM, sealed every ten minutes. Paths and sizes boxed.](/shots/07-moonshadow-tapes-boxed.png)

MoonShadow, Tapes: the recorder's health. The venue serves no price history, so we record it ourselves, in RAM, sealed every ten minutes. Paths and sizes boxed.

![MoonShadow, Rules: the standing orders, rendered from the source document so they cannot drift from it. Parts boxed.](/shots/08-moonshadow-rules-boxed.png)

MoonShadow, Rules: the standing orders, rendered from the source document so they cannot drift from it. Parts boxed.

![The fleet: our session lister, one line per Claude session with its project, name, state, idle time and machine.](/shots/15-fleet-sessions.png)

The fleet: our session lister, one line per Claude session with its project, name, state, idle time and machine.

---

*For agents:* this page as Markdown is <https://moonlight.dustball.com/gallery.md>; every page in one file is <https://moonlight.dustball.com/all.md>; the index is <https://moonlight.dustball.com/llms.txt>. Last updated 2026-11-04. Questions welcome.
