Files
fxhnt/tests
jgrusewski 8a63f69130 fix(factory): closure hardening — zero-sum HRP guard, read-only dry-run, single trial-count authority, funnel + E501
I1 (crash): zero-sum HRP ZeroDivisionError — `hrp_sum = sum(...) or 0.0` was a no-op since
`0.0 or 0.0 == 0.0`. Guard BOTH divide sites in `_size_active`: all-allocated branch and
mixed branch now fall back to equal-weight when `hrp_sum <= 0`.

I2 (honest dry-run): `factory-cycle --dry-run` previously ran the full discovery chain
(gather+hunt+forward) and wrote to the store (mark_seen, upsert DISCOVERED, set_status
RETIRED). Gate the entire GENERATE→JUDGE→PROMOTE→PERSIST block behind `if execute:`.
In dry-run, only the FactoryLoop runs in kill-gated mode (promotes nothing) and reports
the current pool state without any store writes.

M1 (double-count + dedup namespace split): analyst fleet AND hunt each called `add_trials`,
and used different key formats (`market:kind:k=v` vs `kind|market|params`). Fix:
- `candidate_key(market, kind, params)` added to `fxhnt.domain.factory` as the single
  canonical key helper (format: `market:kind:k1=v1,k2=v2` — params sorted, 10g floats).
- `Proposal.key()` delegates to `candidate_key` (unified namespace).
- `FleetOrchestrator.hunt` uses `candidate_key` for its `cand_key` (was `kind|sym|params`).
- `AnalystFleet.gather` is now read-only: no `add_trials`, no `mark_seen`. The hunt is the
  single counting authority. gather only filters proposals already in `store.is_seen`.

M2 (funnel double-count): `forward` was sampled BEFORE `loop.allocate_and_promote()` so
sleeves promoted this cycle appeared in both `forward` and `deployed`. Now `forward` is
computed as `fwd_report.forward_tracking - len(res.promoted)` after promotion.

M3 (E501): wrap `assemble` signature in `regime_execution.py` (was 123 chars).

Pre-existing lint (UP042, E501) in `domain/factory/models.py` also fixed:
`StrategyStatus(str, Enum)` → `StrategyStatus(StrEnum)`;
`forward_returns` comment moved above the field to fit in 120 chars.

Tests: 246 pass (was 241). New tests in test_regime_execution.py:
  test_hrp_zero_weights_all_allocated_no_crash
  test_hrp_zero_weight_single_leg_no_crash
  test_hrp_zero_weights_mixed_branch_no_crash

Updated test_analyst_fleet.py: dedup-only contract assertions (trials==0, seen==0 after gather;
fresh proposals not pre-emptively marked seen; canonical key format check).

Updated test_factory_cycle_wiring.py: aligned with M1 — gather is read-only, hunt is the
single counting authority.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 21:27:23 +02:00
..