fix: 6 workflow flaws detected via full system test
1. CRITICAL FIX - Reports 500 Internal Server Error:
Root cause: {{}} in onclick was Jinja2 template expression
Fix: Changed to single {} in reports_index.html onclick
2. Score history chart always empty:
Root cause: score_update only emitted inside wfv.passed block
Fix: Emit score_update after every hypothesis run with {promoted:false}
Fix: Baseline run also pushes to chart via run_complete handler
3. IS gate too strict - optimizer produces 0 candidates forever:
Root cause: min_calmar=0.35 but best EA has calmar=0.165
Fix: Two-tier IS check - passes if composite_score improves vs baseline
(absolute thresholds still apply as alternative pass condition)
4. Findings emitted twice (double UI display):
Root cause: baseline analyzed once after run, then re-analyzed in iter 1
Fix: Cache baseline findings, reuse in iteration 1 without re-emitting
5. Chart labels improved:
'Baseline' for first point, 'It1·h1' for hypothesis runs
Calmar normalized -0.5..2.0 -> 0..1 for chart display
6. Best score header only updates on actual promotion (not per-hypothesis)
This commit is contained in:
@@ -258,9 +258,15 @@ function addCandidate(d) {
|
||||
|
||||
function pushChartPoint(d) {
|
||||
const labels = scoreChart.data.labels;
|
||||
labels.push(`Iter ${d.iteration}`);
|
||||
// Label: 'Baseline' for first point, 'Iter N · run_id' for hypothesis runs
|
||||
const lbl = d.run_id
|
||||
? (d.run_id.startsWith('baseline') ? 'Baseline' : `It${d.iteration}·${d.run_id.split('_').pop()}`)
|
||||
: `Iter ${d.iteration}`;
|
||||
labels.push(lbl);
|
||||
scoreChart.data.datasets[0].data.push(d.score);
|
||||
scoreChart.data.datasets[1].data.push(d.calmar > 1 ? 1 : d.calmar / 4); // normalize calmar to 0-1
|
||||
// Normalize calmar: clamp -0.5..2.0 → 0..1 for display
|
||||
const calmarNorm = Math.max(0, Math.min(1, (d.calmar + 0.5) / 2.5));
|
||||
scoreChart.data.datasets[1].data.push(calmarNorm);
|
||||
if (labels.length > 50) {
|
||||
labels.shift();
|
||||
scoreChart.data.datasets.forEach(ds => ds.data.shift());
|
||||
@@ -309,10 +315,14 @@ socket.on('run_started', d => {
|
||||
|
||||
socket.on('run_complete', d => {
|
||||
updateMetrics(d);
|
||||
const sign = d.score > 0 ? '✓' : '•';
|
||||
const sign = d.score > 0 ? '\u2713' : '\u2022';
|
||||
addLog(d.score > 0.3 ? 'success' : 'info',
|
||||
`${sign} ${d.run_id}: Score=${d.score} | Calmar=${d.calmar} | PF=${d.profit_factor} | DD=${d.drawdown_pct}%`
|
||||
);
|
||||
// Push baseline run to chart immediately (hypothesis runs pushed via score_update)
|
||||
if (d.run_id && d.run_id.startsWith('baseline')) {
|
||||
pushChartPoint({ iteration: 0, run_id: d.run_id, score: d.score, calmar: d.calmar });
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('run_failed', d => {
|
||||
@@ -333,7 +343,10 @@ socket.on('hypothesis_testing', d => {
|
||||
|
||||
socket.on('score_update', d => {
|
||||
pushChartPoint(d);
|
||||
document.getElementById('hdr-score').textContent = d.score.toFixed(4);
|
||||
// Update best score header only when a candidate is actually promoted
|
||||
if (d.promoted) {
|
||||
document.getElementById('hdr-score').textContent = d.score.toFixed(4);
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('candidate_promoted', d => {
|
||||
|
||||
Reference in New Issue
Block a user