← build log 2026-08-30

Dev Journal - 2026-08-30

Phase 4, D-094: eleven work units, six defects closed, and two occasions where the measurement
contradicted me rather than the code. Same convention as
2026-08-29: the decision records carry the measurements, this is the
through-line.


The throughline: six defects were one defect, and naming it deleted more code than it added

The trader gauntlet had found six things (I-40..I-45) and they looked like six things. Reading
them beside the ledger's own history, they are the same thing for the fourth time:

two clocks for one position                       D-074
two calibration numbers for one record            D-076
two cost views for one gate                       D-079
two probability measures inside one Kelly          I-41   <- this phase
...and a seam that dropped the cost view entirely  I-40   <- one layer after D-079 fixed it

The class: two layers computing one decision quantity under different assumptions. Every
previous fix had been an instance - one clock, one calibration number, one cost view. This phase
promoted the cure to a rule the code enforces: one declared measure per decision, friction
included, and a seam that loses any part of it refuses rather than substituting.

What that framing bought is not rhetorical. It made two of the nine planned patches deletions:

  • The EV hurdle above the seed floor was never built. Once p and b come from the same
    measure, the gate boundary IS EV-after-costs = 0, so a hurdle would have re-stacked haircuts
    into precisely the D-076 "verdict nobody chose" class. The cliff was never the bug; the wrong
    measure under it was.
  • The unbounded-profit refusal disappeared rather than being tuned. Kelly divides by the
    worst case, so an unbounded LOSS genuinely has no fraction - but E[win|win] is finite for a
    long call, so an unbounded PROFIT does. One refusal branch became two named ones and a whole
    category of trade (cheap convexity) stopped being banned. A fair-priced ATM call went from
    "refused at any edge" to 36 contracts.

The phase added exactly two tunable constants, both with a docstring naming the journal rows that
will eventually tune them. _render_positions came out three parameters lighter.

The one that pays: a vol view is the other half of a measure

Thesis had a drift knob and no vol knob. For a directional trade that is fine - the drift is
the view. For a vol trade the stated probability came from the agent's own vol while Kelly's
payoff came from the market's, and the consequence was not a rounding error. Swept across a
genuine, honestly stated vol edge from 0 to 12 points, full Kelly never turned positive at any
point
: a short-premium book could not earn size, ever, however large its edge, while
directional trades ramped normally. The system's most distinctive machinery - condors, breakeven
vol, a scored realized-vol forecast - fed trades that were permanently seed-sized.

Thesis.vol_view makes the forecast the vol half of the decision measure. D-079's algebra turns
out to be measure-agnostic (it is conditional-expectation arithmetic, not a fact about drift), so
the gate became exact for vol theses the way it already was for drift ones. The put credit
spread's gate now opens at 4.0% of vol edge where EV-after-costs turns positive at 4.0% - it was
three points late - and Kelly engages from seven points with size ramping 1.86% → 2.61% → 3.72%.

The nice part is what it does to the agent's incentives. The vol number was already being stated
in prose every cycle and already scored via record_forecast(metric='realized_vol'). It now
buys size. A forecast that earns capital is a forecast the agent has a reason to get right.

Two places the measurement contradicted me

The scaffold caught a wrong invariant in my own design. I had asserted size is monotone in
claimed edge. It is not, and the gauntlet said so within a minute of the sweep running: past ~10
points of vol view, the losing side of a wide condor holds under 1% of the agent's own
distribution, payoff_ratio refuses for want of a side to condition on, and (since WU-4.2)
sizing refuses with it. An extreme view self-refuses rather than manufacturing an enormous
Kelly out of a corner of the grid. That is the layers covering each other, and it is a better
property than the one I tried to assert. The invariant now pinned is the one that must hold - the
gate opens iff EV-after-costs is positive - and the refusal is recorded as a measured behaviour.

Half of I-43's headline was wrong, and I had written it. The finding claimed the flat-IV
evaluation "gates the same zero-edge trade 26pp apart purely by which side of the smile it sits
on", comparing a put credit 95/100 with a call credit 105/110. Those are not mirror structures -
one is struck at the money and the other 5% out - so most of the gap is moneyness, not skew.
Under the fix the two gates move 71.2%/96.9% → 72.2%/96.0%, which fixes nothing, and the
measurement is what killed the claim. Worse for the original framing: there is no single flat vol
that makes a leg-wise-priced board zero-EV at all, because the legs are priced under mutually
inconsistent lognormals - which is what a smile IS to a model that does not have one.

The narrower defect underneath was real and is fixed: a structure whose legs quote 19% and 21%
was being evaluated at a 25% ATM figure, worth $6.73 a contract on a structure whose whole max
profit is small. It now evaluates at the vega-weighted vol and prints the EV span across the
legs' own IVs. The headline is withdrawn - in the ledger, in the scaffold section that produced
it, and in the lesson, which carries "there is no single correct vol here" rather than the number
I had liked better.

This is the second time in two days that the instrument audited the analyst rather than the
system (2026-08-29 has the bootstrap doing it). Recording a wrong
finding openly costs a paragraph; leaving it in the ledger would have cost whoever tried to build
on it.

Corroboration: the artifact and the gap were the same number

position_mark's registry entry set immediate_overshoot = 1.0 on the reasoning that a breach
at twice the threshold "is not plausibly a quote artifact". Its own comment, four lines above,
said a wide or stale quote "can print -100%-of-credit on a HEALTHY spread". Those two sentences
name the same number: -100% against the standard -50% stop is exactly overshoot 1.0. The single
most common artifact on a credit spread was therefore the decisive case, closing healthy
positions on one print at the worst quote of the day, and the N-of-M debounce only ever protected
the shallow breaches.

The fix needed no new data: a real gap moves the underlying, which prints continuously and
tightly, and dominant_risk already answers what "adverse" means for this position from greeks
D-040 records at entry. A vol bet is hurt by a move either way; anything with a directional stake
uses the signed test, so a favourable move can never confirm a claim that the position collapsed.

The part worth remembering: a suppressed breach closes nothing, so it leaves no exit row and
would have been completely invisible. evaluate takes a counter bag and run carries the counts
onto the heartbeat that already exists. The interesting event in a capital-protection system is
often the thing that did not happen.

Testing: four pillars, and the rules stored once

The worry going in was contradictory evals - "trade more" against "refuse more", "exit fast"
against "don't churn" - and a suite that argues with itself gets ignored. The resolution is that
pillars pin relationships, never levels. PILLAR-1 is the worked example: the gate opens iff
EV-after-costs is positive
is simultaneously "never pay for a coin flip" and "never starve a real
edge". Two threshold tests would have fought over that forever; one exactness invariant cannot.

Six admission rules govern the set and they live in exactly one place, docs/principles_testing.md
- restating them at four markers would have been the phase's own defect class, committed by the
suite that exists to catch it. The mutation rule (a test ships only with proof it fails when its
fix is reverted) was performed for all six issues before any of them was struck, and it is what
turned "I think this works" into a ledger entry.

What is left, honestly

Phase 5 - the golden decision set - is not built, and while implementing phase 4 I found a real
gap in my own spec for it. The bundle it described captures the decide PROMPT's inputs, but the
decide agent is a tool-using loop: the option chain and the quotes arrive as tool responses
during the loop. Replay them absent and the agent decides about nothing, which would be a harness
that runs and proves nothing - the failure this project has now named four times. notes/024
records the fix (capture at the compactor boundary, and replay one bundle before curating any
others). Better to leave it specified correctly than built wrongly.

Source docs/dev_journals/2026-08-30_concepts.md