Both latent bugs: a recreated Dagster instance would silently not arm the nightly schedule; and the
Argo build marked Error on the MinIO log-sink (masking real failures + skipping the auto-deploy step).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
write_features_bulk writes many symbols in a single transaction (one fsync/checkpoint vs one per
symbol); ingest_crypto_pit collects all 155 symbols then one bulk call. Equivalence test proves
identical result. Targets the ~52min nightly crypto ingest in the Dagster combined-book run.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire the 4 B0 assets into combined_book_forward_job and a
ScheduleDefinition (cron 30 23 * * *, UTC) via a Dagster Definitions
object; dagster definitions validate passes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extend FeatureStore protocol with catalog() and read_panel() so WarehouseSource
can be typed against the port (mypy strict clean)
- Add silver_ingest_helpers.ingest_crypto_pit — shared bronze→silver→warehouse
write path for assets and tests
- Implement WarehouseSource in combined_book_source.py; delegates crypto panel
to read_panel+_panel and futures to WarehousePriceProvider
- Add equivalence test: warehouse-fed panel == raw-file-fed panel (A→B gate)
- 291 tests pass, 0 regressions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds the `warehouse` branch to `_data_provider` (the cutover seam for
hunt/run --data-source warehouse), plus two new commands: `warehouse-ingest`
(bronze→silver→gold for futures and crypto) and `warehouse-catalog`
(per-symbol inventory/freshness view of the SSOT).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Real Ollama test showed qwen2.5:3b inventing invalid strategy kinds (FUTURES_CONTRACTS, MARKET_RETURN, ...)
because the prompt never listed the engine's available() kinds. Now the analyst is given the allowed kinds,
the prompt forbids inventing others, and proposals with an unknown/empty kind are dropped — so the fleet only
emits backtestable hypotheses. The gauntlet still filters the rest.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
Part A: factory-cycle now runs the full chain. Analyst fleet (LlmAnalyst
per specialty, graceful LLM-absent fallback) gathers proposals; a
proposal→Territory bridge groups them by kind and merges with the standing
fixed-grid hunters; FleetOrchestrator.hunt() + ForwardValidationService.run()
execute the judge step; FactoryLoop.allocate_and_promote() does the
diversification-gated promote+HRP step. Funnel counts (proposed/tested/
survived/forward/deployed/retired/global_trials) are persisted via
FactoryStore.record_cycle() in --execute mode with real values from each
layer's report object. Dry-run safe; kill-switch respected.
Part B: RegimeConditionalExecutor.assemble() sizes deployed legs by HRP
weights from the latest factory cycle allocation (injected via hrp_weights
kwarg). Legs not in the allocation (newly promoted) get an equal share of the
unallocated gross budget. No allocation recorded (hrp_weights=None) → previous
equal-weight behaviour preserved. Gross budget is always renormalised.
FactoryStore.latest_weights() added to retrieve the most-recent cycle's HRP
dict (None = no cycle, {} = cycle with no sleeves).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fix 1 (CRITICAL): FleetOrchestrator.hunt now passes n_trials =
store.total_trials() + local_eff to evaluate_by_regime so the deflated-
Sharpe bar scales with the full cumulative search across all prior hunts,
not just the current territory's candidate count. The immune system is
no longer decorative. add_trials() was already called once after the loop,
so no double-counting is introduced.
Fix 2 (IMPORTANT): ForwardValidationService._review no longer auto-
promotes a FORWARD sleeve to DEPLOYED when forward_mean() > 0. That path
bypassed the factory_loop's diversification gate entirely and could route
capital around governance. _review now only retires (CUSUM decay or
negative forward mean after min_days); promotion to DEPLOYED is the
factory_loop's sole responsibility. test_forward.py updated accordingly.
Fix 3 (MINOR): hrp._ivp wraps both 1.0/diag(cov) and iv/iv.sum() inside
np.errstate(divide="ignore", invalid="ignore") so a zero-variance asset
no longer emits a RuntimeWarning before the uniform fallback catches it.
New test: tests/integration/test_global_n_flows.py asserts the n_trials
expression (store.total + local_eff) and that hunt() records
n_trials_at_discovery >= 5000 after seeding 5000 prior trials.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>