Commit graph Warrior_EA/Expert/Persistence/AIBasePersistenceViewImpl.mqh
Author SHA1 Message Date
AnimateDread
d9092a2408 fix(vote): persist the member's skill verdict - a converged model was ruled no-skill on every restart
SP500 resumed converged at era 136 with its tier ladder correctly restored and still
swept 4999 bars reporting "0 had a snapshot, drew 0 arrow(s)" while the other five
charts drew 221-312.

HasDemonstratedEdge() - added with the no-skill exclusion - compares m_eraStatPrecPct
against m_eraStatChancePct. Both are written once per era by EnsembleStashEraStats. A
converged model runs no eras, so after a restart both sat at their -1 ctor defaults,
every member was ruled no-skill, ReconstructionWeight() returned 0 for all four, and
the overlay divisor was zero on every bar. Exactly the failure the WST7 ladder
persistence fixed one level down: the ladder says how much a member votes, this says
whether it may.

RankTiersFromOos already computes the pair (pooled holdout precision and the
zero-skill reference rate) and now records it as the CERTIFIED edge. That path is
reached by the era end AND by the deployed replay, which is the only measurement a
converged model will ever make. Persisted as WST8; HasDemonstratedEdge() prefers the
era pair and falls back to it.

The census line also had to be fixed: it reported "NOT ONE of those bars had a single
member snapshot ... no enrolled member has published m_overlaySigSnap" for a condition
that was purely a skill verdict. The snapshots were there. It now counts the two causes
separately and names the one that fired.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 16:53:16 -04:00
AnimateDread
cb1d86e477 fix(vote): persist the tier ladder - a converged model was mute after every restart
THIS IS NOT A DISPLAY BUG. A deployed model could not vote, or trade, at
any point after a terminal restart, and never would have.

LiveVoteContribution() returns 0 for every call until m_tiersSelfRanked
is set - deliberately, and correctly: before RankTiersFromOos() runs,
m_pattern_0..3 hold the constructor's stock 25/50/75/100, which since the
2026-08-18 currency change is the WRONG UNIT rather than a weak opinion,
and one unranked member would drag the whole ensemble over any threshold.

But that ladder is produced ONLY by a completed pass 3, and it was never
persisted - the code comment at LiveVoteContribution says so outright.
A converged model runs no further passes. So on every restart it lost its
entire vote permanently:

  LiveVoteContribution -> 0  => no live vote          ("0 vote/4 flat")
  ReconstructionWeight -> 0  => overlay divisor 0     ("0 had a snapshot")
                             => no arrows
                             => no fired bars, so g_ensCumOosTotal stays 0
                             => "measuring..." forever

Every symptom reported over the last three exchanges is that one cause.
The log is unambiguous: six H4 charts resumed at era 70/71, all 24
rescans completed with ~2700 Buy / ~2200 Sell per model, and the overlay
then swept 4999 bars finding "0 had a snapshot". The calls were there;
nothing was permitted to count them.

WST7 now stores the four tier weights, the module trust weight and the
self-ranked flag beside the model. Restored only when the stored flag
says the ladder was MEASURED - a .stats written before a model's first
pass 3 holds the stock ladder, and adopting that as if measured is the
exact error the flag exists to prevent.

A .stats predating WST7 has no ladder, so existing converged models stay
silent until their next scoring pass mints one. That case now prints a
warning naming all three of its symptoms, because each one independently
looks like a different bug.

Compile-verified in _claude_stage: 0 errors, 0 warnings.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 14:26:33 -04:00
AnimateDread
8f2164698b feat(target): delete the barrier/geometry stack - the label is the verdict
Step 3 of the swing-pivot plan, whole-hog. The swing label is now the ONE
target and the era verdict is precision + recall per class against the
label's own base rate - no win rate, no break-even, no expectancy, no
geometry anywhere in training.

DELETED
- Expert/Excursion/ (4), Expert/BarrierHorizon/ (4), GeometrySweep,
  FirstPassageLadder, Labeling/TripleBarrier.mqh (CLabelOverlap survives
  in Labeling/LabelOverlap.mqh), 3 test EAs.
- TripleBarrierLabel + walk, fractal label, geometry derivation/scan/
  adoption, exit-policy replay, excursion MI targets, the drift verdict
  (DIRECTION_INTELLIGENT), the recall floor, balanced-accuracy telemetry,
  the barrier defines, the .cfg geometry adopt (slots kept as zeros for
  the positional layout), the derived-geometry live-order override.
- TRAINING_TARGET input/enum: direction models are always swing; META2
  re-keys the meta head onto label agreement (descriptor loses its two
  geometry slots).

REWORKED
- Labels.mqh (1795 -> ~370 lines): AdvanceSwingLabelState with
  FINALITY-GATED CACHING - an unresolved bar (pivot pair uncommitted) is
  never cached, so it can never freeze as a false Neutral; training,
  calibration, OOS scoring and online learning all skip unresolved bars.
- SDeployVerdict: significance-only; SOosTally chance = larger
  directional class share; pooled gate poolability = timeframe (record v2).
- Purge/embargo/declustering gaps: the measured mean label resolution
  lag (LabelResolutionBars), not a barrier horizon.
- Pool purge key + backfill DB rows: marked at the bar the label
  resolved on (m_labelResolveAge), not a fabricated barrier touch.
- Online learning frontier: finality, not a horizon delay.
- m_bestBalancedOos -> m_bestSelectionScore, m_erasSinceBestBalanced ->
  m_erasSinceBest, ensemble vote outcome arrays -> label arrays.

STEP 4 folded in: Entry_Multiplier / SL_Mode / TP_Mode / tradingdirection
are inputs again - trade management is the tester GA's search space.

Fingerprints: every direction model re-keys (TGT:SWG1 now unconditional,
CUT token gone); META1 -> META2. Full retrain, as planned.

Compile-verified in _claude_stage: Warrior_EA + both surviving test EAs,
0 errors, 0 warnings each.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 20:42:31 -04:00
AnimateDread
87382748d3 refactor(persistence): ModelPersistence is a real collaborator, not a raw-include partial (S3)
Expert/AIBase/Persistence.mqh (598 lines, 8 methods) -> Expert/Persistence/:
IPersistenceView.mqh (abstract, 68 read+write accessors) + AIBasePersistenceView.mqh/
AIBasePersistenceViewImpl.mqh (the adapter) + ModelPersistence.mqh (CModelPersistence,
the real collaborator - signal owns m_modelPersistence and binds it to m_persistenceView,
same shape as ChartUI's S2).

Grep-verified before starting: every field these 8 methods touch is ALSO touched
elsewhere in the class (Training/Lifecycle/OnlineLearning/Topology/FeatureScreen/
Labels.mqh) or already exposed via ChartView. Zero exclusive state, unlike ChartUI's
arrow-restore/rescan queues - CModelPersistence is stateless, holding only the
borrowed view pointer, operating entirely through 68 Persist*/PersistSet*() accessors
on the signal.

ValidateCpuInference's Net-pointer/throwaway-clone core is ONE consolidated view call
(PersistRunCpuInferenceSelfCheck) rather than field-by-field - irreducible pointer/
object work, not signal state, same doctrine as ChartScoreBarForRescan.
LoadNetWithRetry keeps its original CheckPointer(Net)-free Net.Load() call unchanged
(no guard added - would change failure behaviour on what must be a pure relocation).

This code writes the actual on-disk .cfg/.stats binary layouts every deployed model
depends on (explicit "DO NOT REORDER" comment in the original), so beyond compiling
clean (0 errors, 0 warnings) this was verified with a positional field-order diff:
every FileWrite*/FileRead* call's target field, extracted and normalized from both
the original and the new file, matches 1:1 in the same order (43/43 on the write
side covering SaveModelStats+SaveTopologyConfiguration, 17/17 on LoadModelStats'
read side; LoadAndCompareTopologyConfiguration's local-variable read block was
copied verbatim, untouched, so nothing to diff there). The magic-version
conditionals (WST2-6, haveDerivedStages/haveBarrierGeometry/etc.) moved unchanged.

All 8 methods keep their exact original signatures as one-line forwards - zero
external call sites changed.
2026-08-23 21:45:09 -04:00