Feeding post-mortem learnings into candidate selection
"how can we feed learnings from the postmortem into things like stock candidate selection?" — 2026-09-03
Part of goal #3, applied to the one place it pays off fastest.
The desk already does this, on the wrong basis
Two findings are live in learning_findings today:
grade:B- "B- recruits have lost money on average even though their
grade said they'd hold up: 5 trades, down 4.8% each"
metric_json: {"closed":5, "mean_exit_pct":-4.85,
"win_rate":0.2, "low_power":true}
source:catalyst-scan "Recruits from catalyst-scan are no longer beating that
source's own raw alerts — the vetting has stopped adding
an edge there"
metric_json: {"scored":33, "avg_excess_pct":-1.07,
"baseline_avg_pct":-0.34, "delta_pct":-0.73}
Both are computed from realised outcomes. Realised is the setup PLUS the person. So neither can separate "B− selection is bad" from "B− trades were mishandled" — and those have opposite fixes: one changes the grader, the other changes the trader.
Mechanical R is the setup alone. That is what this service adds here: not a new loop, a decontaminated basis for the loop that already exists.
The low_power flag and the comparison against that source's own raw alerts
are both good instincts already present. Nothing below replaces them.
Four feeds, in order of what they are worth
1. Grade calibration, decontaminated
Does an A-grade produce a better setup than a B? Realised is biased here in a specific direction: conviction attracts size and intervention, so the grades a desk believes in are the ones most likely to be managed — and therefore the ones realised understates. Mechanical R by grade is the honest test.
2. Scanner and source quality, same basis
Is catalyst-scan cold, or is the desk mishandling what it finds? Recompute
avg_excess_pct on mechanical R and the question answers itself.
3. Level-kind attribution — a group-by, not a model
plan_json carries reasoned levels with weights, which is more than most desks
record:
"stop_level": {"kind":"prev-high","price":177.6,"label":"yesterday's high","weight":3}
"target_level": {"kind":"round","price":182,"label":"the $182 line","weight":1}
So: do plans stopped at a prev-high resolve better than at a swing-low? Do
round-number targets get reached more often than half-dollar ones? That is
a GROUP BY level_kind over mechanical outcomes — no model, no fitting, and it
feeds level selection directly.
4. Cost-aware selection — probably the biggest
The desk already reasons this way. From plan_change:
"take → stand down: pays 2.0-to-1 once the spread is paid, under the 2-to-1 floor"
But that spread is modeled. This service can measure the real one from
tbbo at the decision instant. Measured per liquidity band it supports a much
harder statement — names like this do not survive their own spread — which
kills candidates before they are taken rather than after they lose.
The receipt that makes this urgent: on 34 BTC rides, $9.22 of an $11.54 loss was spread, not strategy.
Three traps
Survivorship — do not ship a selection finding yet
Grading a selector using only trades that were TAKEN measures the joint filter of selector-plus-human, not the selector. The correction is the cut plans, and those are currently ~51, not the 228 the table suggests.
So every selection statistic available today is biased in the flattering direction. Measuring is fine; publishing one into a decision is not.
Sample size
The live B− finding is 5 trades, and the desk flags it low_power itself.
Mechanical R does not create data — it cleans it. Every finding keeps its N
visible and a null band, and the report says which claim it is making:
"you exited early on this trade" is a fact; "you exit early" needs N.
The ratchet — the non-obvious one
If a finding suppresses B− candidates, the desk stops generating B− data, and the finding can never be revisited. It is self-sealing: the first noisy result permanently closes a door and then removes the evidence that would reopen it.
Any suppression needs a holdout — keep taking a small random slice so the estimate stays alive. A suppression without one is not a decision, it is a one-way door disguised as a decision.
And a fourth, cheaply avoided
A source going cold may be the market, not the source. Six days cannot tell those apart. Always compare against a benchmark over the same window — which, again, the existing finding already does.
The mechanism
Nothing auto-applies:
observe mechanical R grouped by grade / source / level-kind / liquidity band
->
propose learning_findings, with N, a null band, and the holdout it needs
->
GAVEL alina_gavels — built, 0 rows, never used
->
apply thresholds and suppressions are SETTINGS (reversible, settings_audit).
the grade FORMULA is code, so a finding there is a proposal for a
human, never a switch.
->
measure the same ledger scores the weeks after. a finding that did not move
its own metric is reverted, not quietly kept.
Prerequisites, honestly
| cost drag | not built — REALISED is currently computed with no costs at all |
| cut plans | ~51 usable, so the survivorship correction is not available yet |
| attribution | no user_id, so "was it the grade or the person" cannot be split per person |
| holdout policy | does not exist, and no suppression should ship without it |
Which is why the order in what this is for puts cost drag first: it is the one prerequisite that is fully unblocked and already has its data sitting in the ledger.