docs(dashboard): add health-check reference section
This commit is contained in:
@@ -45,8 +45,8 @@ CRITIC_C, ACTOR_C = "#1f77b4", "#ff7f0e"
|
||||
ALPHA_C = "#9467bd" # alpha line on the losses panel
|
||||
RELOAD_JS = ('<script type="text/javascript"><![CDATA[ '
|
||||
'setTimeout(function(){ location.reload(); }, 60000); ]]></script>')
|
||||
W, H = 1400, 1720
|
||||
TITLE_H, GUIDE_H = 80, 80
|
||||
W, H = 1400, 1850
|
||||
HEALTH_H = 205 # bottom "Reading the signs" cheat-sheet band
|
||||
# rows: (header_y, panel_top_y, panel_bottom_y, x_left, x_right)
|
||||
# panel_top sits low enough to leave room under header+sub for the
|
||||
# per-panel how-to-read guide (3 italic lines, see panel_guide)
|
||||
@@ -79,9 +79,36 @@ GUIDES = {
|
||||
"X = eval cycle number; Y = best score achieved.",
|
||||
"higher is better; a rising trend means the bot is improving."),
|
||||
}
|
||||
GUIDE_LINES = [
|
||||
"This file reloads itself in Chrome every sixty seconds.",
|
||||
"Regenerate anytime with tools/watch_dashboard.sh or the python command.",
|
||||
# bottom health-check cheat-sheet: one column per subsection; each bullet is
|
||||
# a tuple of pre-wrapped text lines (first line gets the bullet marker)
|
||||
SIGNS_COLUMNS = [
|
||||
("Healthy patterns ✅", [
|
||||
("Both critic and actor losses trending down over time",),
|
||||
("Alpha decaying slowly from ~1.0,", "then plateauing — this is normal"),
|
||||
("Win rates appearing and increasing in the eval panel",),
|
||||
("Max scores rising in the max-score panel",),
|
||||
("Alpha plateauing is NOT a problem — it means",
|
||||
"exploration level is stable"),
|
||||
]),
|
||||
("Warning signs ⚠️", [
|
||||
("Losses exploding (suddenly jumping to", "millions or billions)"),
|
||||
("Win rates staying at 0% for a long time",
|
||||
"after the first ~20 eval cycles"),
|
||||
("Alpha reaching 0 — bot stops exploring entirely", "(gets stuck)"),
|
||||
("Max scores flatlining (no improvement",
|
||||
"over many eval cycles)"),
|
||||
("Any single loss value above 1e6",),
|
||||
]),
|
||||
("What each metric means (brief)", [
|
||||
("Critic loss: how wrong the bot's value",
|
||||
"estimates are — should go down"),
|
||||
("Actor loss: how well the bot's action policy",
|
||||
"is doing — should go down overall", "(some bumps are normal)"),
|
||||
("Alpha: exploration-exploitation tradeoff — starts",
|
||||
"high, settles at a positive value (NOT zero)"),
|
||||
("Max score: best score achieved per eval cycle —",
|
||||
"rising trend = learning"),
|
||||
]),
|
||||
]
|
||||
|
||||
|
||||
@@ -280,16 +307,23 @@ def map_fn(p0, p1, vmin, vmax, log=False):
|
||||
return f
|
||||
|
||||
|
||||
def guide_block(w, h, lines):
|
||||
"""Plain-English "How to read" band at the bottom of the canvas."""
|
||||
y = H - GUIDE_H
|
||||
s = f'<rect x="0" y="{y}" width="{w}" height="{GUIDE_H}" fill="#f2f2f2"/>\n'
|
||||
s += (f'<text x="16" y="{y + 21}" font-size="15" font-weight="bold">'
|
||||
f"How to read</text>\n"
|
||||
f'<text x="{w - 16}" y="{y + 20}" text-anchor="end" font-size="11" '
|
||||
f'fill="#666">Regenerate anytime: python3 tools/plot_progress.py</text>\n')
|
||||
for i, ln in enumerate(lines):
|
||||
s += f'<text x="16" y="{y + 43 + i * 17}" font-size="13">{esc(ln)}</text>\n'
|
||||
def signs_block():
|
||||
"""Health-check cheat-sheet band along the bottom of the canvas."""
|
||||
y0 = H - HEALTH_H
|
||||
s = f'<rect x="0" y="{y0}" width="{W}" height="{HEALTH_H}" fill="#f2f2f2"/>\n'
|
||||
s += (f'<text x="16" y="{y0 + 21}" font-size="15" font-weight="bold">'
|
||||
"Reading the signs</text>\n"
|
||||
f'<text x="{W - 16}" y="{y0 + 20}" text-anchor="end" font-size="11" '
|
||||
'fill="#666">Regenerate anytime: python3 tools/plot_progress.py</text>\n')
|
||||
for (head, bullets), x in zip(SIGNS_COLUMNS, (16, 500, 985)):
|
||||
s += (f'<text x="{x}" y="{y0 + 43}" font-size="13" font-weight="bold">'
|
||||
f"{esc(head)}</text>\n")
|
||||
y = y0 + 61
|
||||
for lines in bullets:
|
||||
for j, ln in enumerate(lines):
|
||||
s += (f'<text x="{x}" y="{y}" font-size="12">'
|
||||
f"{esc(('• ' if j == 0 else ' ') + ln)}</text>\n")
|
||||
y += 14
|
||||
return s
|
||||
|
||||
|
||||
@@ -496,7 +530,7 @@ def build_dashboard(campaign, metrics_f, out):
|
||||
s += panel_guide(geo[3], geo[0] + 33, guide)
|
||||
s += drawer() or "" # panels bare-return None on their no-data path
|
||||
|
||||
s += guide_block(W, H, GUIDE_LINES)
|
||||
s += signs_block()
|
||||
s += RELOAD_JS + "\n"
|
||||
s += "</svg>\n"
|
||||
return write_svg(out, s)
|
||||
@@ -552,8 +586,13 @@ def selftest():
|
||||
for t in PANEL_TITLES:
|
||||
assert esc(t) in text, f"panel title missing: {t}"
|
||||
assert text.count(PANEL_TITLES[0]) == 1
|
||||
assert "How to read" in text, "reading guide missing"
|
||||
assert 'width="1400"' in text and 'height="1720"' in text
|
||||
assert "Reading the signs" in text, "health-check section missing"
|
||||
for head, bullets in SIGNS_COLUMNS:
|
||||
assert esc(head) in text, f"health-check column missing: {head}"
|
||||
for lines in bullets:
|
||||
assert esc("• " + lines[0]) in text, f"bullet missing: {lines[0]}"
|
||||
assert text.count("• ") == sum(len(b) for _, b in SIGNS_COLUMNS)
|
||||
assert 'width="1400"' in text and 'height="1850"' in text
|
||||
# every panel carries its own What/Axes/Better how-to-read note
|
||||
assert text.count("What:") == len(PANEL_TITLES), text.count("What:")
|
||||
for g in GUIDES.values():
|
||||
|
||||
Reference in New Issue
Block a user