TASK PLAN — ab-reward-registry-b3b8

Source: TASK-PLAN-ab-reward-registry-b3b8.md · Rendered: 2026-07-04 05:54 UTC · agents read the .md, humans read the .html.

1. Problem

The A/B substrate must answer "is the challenger better?" — but better by what objective? Total return, Sharpe, dodged-loss, and drawdown give different winners. Today research/rewards/ is a stub: register(name, fn) with an empty REGISTRY and an implicit TradeRecord → float shape. There is no way to declare an objective's role (the thing being optimized vs a guardrail that blocks promotion), no input typing (a trade-series reward applied to a screener basket would silently compute nonsense), and no screener-shaped rewards at all.

2. The fix

@register("sharpe", input_type="basket", role="primary", direction="increase")
def sharpe(outcomes: BasketOutcomes) -> float: ...

REGISTRY ── keyed by name ──► {fn, input_type, role, direction, threshold}
             score(candidate_type, reward_name) → refuses input_type mismatch

3. Expected files

4. Test plan (one line each)

5. Non-goals

6. Worker contract

Per the Subagent Dispatch Contract (~/.claude/CLAUDE.md): unit tests with the feature; codex + /review loops to clean; PR against main; PR URL in the return message.