Dev Journal - 2026-08-30 (second entry): the sibling sweep
Phase 6, D-095. The first entry today covered phase 4 (One Measure). This one covers what a
whole-system review found afterwards, and what implementing the review found in turn.
The through-line: the oldest defect class, wearing this week's clothes
Four parallel audits over everything phase 4 had not touched produced fifteen findings. The
useful move was not triaging them one by one - it was noticing they were all the same thing, and
that the thing was not new:
every hard-won pattern exists once, next to N places that lack it - notes/019 §1.2, written
during the refactor plan, about a codebase that has since fixed that class twice
Discovery excludes the funnel's own names from nomination; the muse excludes nothing. WU-4.8 made
the pre-trade layer skew-aware; everything after entry stayed flat. store.write_atomic reached
every state writer except the lock guarding them all. Health had probes for every subsystem
except the two journal kinds shipped that same morning. The run loop degrades on any failure;
the single-shot path cron actually calls hands over a traceback.
Naming it turned a list of fifteen into one rule that made the phase small: every fix lands
inside a mechanism that already exists, and a fix that seems to need new machinery means the
finding was misread. That held. The whole phase added one Probe, one registry entry, one gauge,
four dataclass fields, two state checks and one constant - and zero new subsystems, stores or
row kinds.
The best fix was the one that needed no new machinery
I-48 was the finding with real capital consequence: a leg vanishing at the broker (early
assignment) was journalled while the remainder - possibly a naked short, the exact thing INV-19
refuses to create through our own close path - kept being priced on the legs it still had.
Three constraints collided. The deterministic layer must not wait for an LLM. Reconcile has no
tools and should not grow them. And one stale snapshot must not liquidate a healthy spread. The
resolution was to stop thinking of it as one job: reconcile counts, the exit registry closes.
Reconcile increments a persisted counter and clears it (with its own journal row) when the legs
come back; a leg_divergence signal reads that count at deadline priority, implicit on every
position. Reconcile runs immediately before the exit engine in the same tick, so confirmation
costs one tick - five minutes - and INV-19's all-legs close does the rest.
One registry entry and one _normalise clause. That is the D-037 recipe verbatim, the same shape
as the deadline rule and the gamma-wall stop. The registry was built for exactly this and had
been waiting.
Two defects the review could not have found by reading
The one implementing found. Position.frontmatter() is a hand-maintained allowlist and
_parse is its hand-maintained mirror. Adding leg_divergence_count meant touching both - and
doing so revealed that thesis_vol_view had never been there at all. WU-4.5 shipped it that
morning; it was set at record time and gone on the next read. The whole point of that field is
that a vol thesis stays scoreable after the cycle that formed it, and it had been silently
discarded every time.
No test caught it because every test checked the fields it already knew about - which is exactly
the blind spot an example has and an invariant does not. So the fix is the property:
test_every_position_field_survives_a_save_load_round_trip walks dataclasses.fields(Position)
and fails on anything that does not survive, unless it is on an exclusion list with a stated
reason. Adding to that list is a decision; forgetting a field is not.
The one tracing found, and it is the worst thing in either phase. WU-6.9 was written as an
investigation with two permitted outcomes - pin the containment if it holds, ledger it if it does
not - explicitly forbidding reconnect machinery built in anticipation. The trace found it does
not hold.
analytics.snapshot degrades on a failed broker read and leaves broker_positions == []. That is
indistinguishable from the broker holds nothing, which is the one conclusion a failed read
cannot support - and reconcile treated it as proof. A dead MCP session therefore marked every
open position closed, scored each through learning, and left the real exposure running at the
broker with no exit rules watching it, because a terminal position is never evaluated again.
Reproduced end to end before the fix: phantom=['pos_live'], status closed.
The shape is familiar enough to be embarrassing. It is D-038's absence-as-zero. It is I-46's
unpriced-counted-as-free, which I had fixed four hours earlier in this same phase. Same fix
shape too: a broker_readable flag defaulting False, because fail-closed is the only
defensible default on a capital guard, set only where the read actually succeeded, with the
failure routed through the health.degraded mechanism that already existed so it escalates into
the report rather than printing into an unattended log.
That is three seams now where an absent measurement was read as a measured absence. The pattern
is worth more than any of the three fixes: whenever a value can be missing for two different
reasons, the code must be able to tell them apart, and the default must be the one that refuses
to act.
What was deliberately not built, and why that mattered
Seven of the fifteen findings became no work at all, and writing the reasons down was as much of
the phase as the code:
- The muse exclusion list the review recommended was rejected. The muse prompt is the Coach's
one live A/B lever - editing it from outside corrupts an open trial's pairing and re-fingerprints
the artefact mid-experiment - and the premise is unproven anyway, since the muse's mandate is
novel theses, not novel names. It became a gauge instead, and a gate must earn its existence
from that trajectory. Same discipline that held the vega cap in D-094. - Scoring declines (I-16) was routed to the gate-regret workstream it actually belongs to: it
needs the D-070 gaming question answered first, and a ledger schema change. - Research's missing options gate was reclassified as a deliberate limitation. Research runs
while the market is closed. There is no chain to check.
The count
490 tests (+21). Every fix revert-verified before its issue was struck - ten issues, I-46 through
I-55. Both scaffolds clean. trdrbot health reporting 0 problems against live data. One new
tunable constant in the whole phase, with a docstring naming the journal rows that will tune it
rather than the taste that set it.