fix(hypotheses): prune concluded entries from active.json after each run
Concluded hypotheses already live in concluded/ — keeping them in active.json causes the registry to grow unboundedly. Runner now removes them at the end of each cycle. Also cleaned up the existing social_dd concluded entry. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
97b2755e97
commit
7ffbadca09
|
|
@ -22,24 +22,6 @@
|
||||||
],
|
],
|
||||||
"baseline_scanner": "insider_buying",
|
"baseline_scanner": "insider_buying",
|
||||||
"conclusion": null
|
"conclusion": null
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "social_dd-ranker-suppression",
|
|
||||||
"scanner": "social_dd",
|
|
||||||
"title": "Does ranker suppression cause us to miss social_dd 30d winners?",
|
|
||||||
"description": "social_dd shows 60% 30d win rate (+2.32% avg) but only 41.7% 7d (-1.92%). Hypothesis: the ranker and recommendation system evaluate at 7d horizon, unfairly penalizing a slow-win scanner. Most picks (22/25) already score >=65, so score suppression is not the primary issue \u2014 horizon mismatch is.",
|
|
||||||
"branch": null,
|
|
||||||
"pr_number": null,
|
|
||||||
"status": "concluded",
|
|
||||||
"priority": 0,
|
|
||||||
"expected_impact": "medium",
|
|
||||||
"hypothesis_type": "statistical",
|
|
||||||
"created_at": "2026-04-13",
|
|
||||||
"min_days": 0,
|
|
||||||
"days_elapsed": 0,
|
|
||||||
"picks_log": [],
|
|
||||||
"baseline_scanner": "social_dd",
|
|
||||||
"conclusion": "statistical"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -427,7 +427,9 @@ def conclude_statistical_hypothesis(hyp: dict) -> None:
|
||||||
try:
|
try:
|
||||||
with open(DB_PATH) as f:
|
with open(DB_PATH) as f:
|
||||||
db = json.load(f)
|
db = json.load(f)
|
||||||
picks = [p for p in db if p.get("scanner") == scanner or p.get("strategy_match") == scanner]
|
picks = [
|
||||||
|
p for p in db if p.get("scanner") == scanner or p.get("strategy_match") == scanner
|
||||||
|
]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f" Could not read performance database: {e}", flush=True)
|
print(f" Could not read performance database: {e}", flush=True)
|
||||||
|
|
||||||
|
|
@ -439,7 +441,11 @@ def conclude_statistical_hypothesis(hyp: dict) -> None:
|
||||||
avg_score = round(sum(scores) / len(scores), 1) if scores else None
|
avg_score = round(sum(scores) / len(scores), 1) if scores else None
|
||||||
|
|
||||||
returns_7d = [p["return_7d"] for p in picks if p.get("return_7d") is not None]
|
returns_7d = [p["return_7d"] for p in picks if p.get("return_7d") is not None]
|
||||||
win_rate = round(100 * sum(1 for r in returns_7d if r > 0) / len(returns_7d), 1) if returns_7d else None
|
win_rate = (
|
||||||
|
round(100 * sum(1 for r in returns_7d if r > 0) / len(returns_7d), 1)
|
||||||
|
if returns_7d
|
||||||
|
else None
|
||||||
|
)
|
||||||
avg_return = round(sum(returns_7d) / len(returns_7d), 2) if returns_7d else None
|
avg_return = round(sum(returns_7d) / len(returns_7d), 2) if returns_7d else None
|
||||||
|
|
||||||
stats_block = (
|
stats_block = (
|
||||||
|
|
@ -489,8 +495,10 @@ def promote_pending(registry: dict) -> None:
|
||||||
# Only implementation/forward_test hypotheses count toward max_active.
|
# Only implementation/forward_test hypotheses count toward max_active.
|
||||||
# Statistical hypotheses are concluded immediately and never occupy runner slots.
|
# Statistical hypotheses are concluded immediately and never occupy runner slots.
|
||||||
running_count = sum(
|
running_count = sum(
|
||||||
1 for h in registry["hypotheses"]
|
1
|
||||||
if h["status"] == "running" and h.get("hypothesis_type", "implementation") == "implementation"
|
for h in registry["hypotheses"]
|
||||||
|
if h["status"] == "running"
|
||||||
|
and h.get("hypothesis_type", "implementation") == "implementation"
|
||||||
)
|
)
|
||||||
max_active = registry.get("max_active", 5)
|
max_active = registry.get("max_active", 5)
|
||||||
if running_count >= max_active:
|
if running_count >= max_active:
|
||||||
|
|
@ -518,8 +526,10 @@ def main():
|
||||||
# Fast-path: conclude all pending statistical hypotheses immediately.
|
# Fast-path: conclude all pending statistical hypotheses immediately.
|
||||||
# They answer questions from existing data — no cap, no worktree, no waiting.
|
# They answer questions from existing data — no cap, no worktree, no waiting.
|
||||||
statistical_pending = [
|
statistical_pending = [
|
||||||
h for h in registry.get("hypotheses", [])
|
h
|
||||||
if h["status"] == "pending" and h.get("hypothesis_type") == "statistical"
|
for h in registry.get("hypotheses", [])
|
||||||
|
if h["status"] == "pending"
|
||||||
|
and h.get("hypothesis_type") == "statistical"
|
||||||
and (not filter_id or h["id"] == filter_id)
|
and (not filter_id or h["id"] == filter_id)
|
||||||
]
|
]
|
||||||
for hyp in statistical_pending:
|
for hyp in statistical_pending:
|
||||||
|
|
@ -546,6 +556,14 @@ def main():
|
||||||
print(f" Error processing {hyp['id']}: {e}", flush=True)
|
print(f" Error processing {hyp['id']}: {e}", flush=True)
|
||||||
|
|
||||||
promote_pending(registry)
|
promote_pending(registry)
|
||||||
|
|
||||||
|
# Prune concluded hypotheses from active.json — they live in concluded/ already.
|
||||||
|
before = len(registry["hypotheses"])
|
||||||
|
registry["hypotheses"] = [h for h in registry["hypotheses"] if h["status"] != "concluded"]
|
||||||
|
pruned = before - len(registry["hypotheses"])
|
||||||
|
if pruned:
|
||||||
|
print(f"\n Pruned {pruned} concluded hypothesis/hypotheses from active.json.", flush=True)
|
||||||
|
|
||||||
save_registry(registry)
|
save_registry(registry)
|
||||||
print("\nRegistry updated.", flush=True)
|
print("\nRegistry updated.", flush=True)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue