diff --git a/src/ace/sidecar/dashboard_render.py b/src/ace/sidecar/dashboard_render.py
index 54576a9..41c952e 100644
--- a/src/ace/sidecar/dashboard_render.py
+++ b/src/ace/sidecar/dashboard_render.py
@@ -1148,6 +1148,7 @@ def _refs(d: Dict[str, Any]) -> Dict[str, Any]:
.modebar button.on{background:#14301f;color:#4ade80}
.modebar button.on[data-mode=prod]{background:#3a2216;color:#f0a868}
.modebar button:hover:not(.on){color:#adbac7;background:#12161a}
+.lvh{font:9px/1.4 ui-monospace,monospace;color:#6e7681;letter-spacing:.08em;text-transform:uppercase;margin:9px 0 4px;padding-top:8px;border-top:1px solid #1c2126}
.modenote{font:10px/1.5 ui-monospace,monospace;color:#6e7681;margin-top:5px}
"""
@@ -1249,9 +1250,17 @@ def _mode_js() -> str:
""+shown+" ("+pct.toFixed(1)+"%) via "+(m.by||'')+"";
});
}
+ // Persisted, because the page reloads itself every REFRESH_SECONDS. Without this the
+ // control silently snapped back to OFF a few seconds after every click -- which reads as a
+ // broken toggle rather than as the page refreshing, and is exactly how it was reported.
+ // localStorage is the right store for it: a per-viewer display preference, not state
+ // anyone else needs, and it survives the reload that caused the problem.
+ var KEY='ace.skillmode';
+ function save(m){ try{ localStorage.setItem(KEY,m); }catch(e){} }
+ function load(){ try{ return localStorage.getItem(KEY)||'off'; }catch(e){ return 'off'; } }
document.querySelectorAll('#modebar button').forEach(function(b){
- b.addEventListener('click',function(){apply(b.dataset.mode);});});
- apply('off');
+ b.addEventListener('click',function(){ save(b.dataset.mode); apply(b.dataset.mode); });});
+ apply(load());
})();
"""
@@ -2422,14 +2431,21 @@ def _lever_rail(d: Dict[str, Any]) -> str:
if not rows:
# No sessions in scope. The published corpus figures would fit here and would be a
# lie about this machine, so the rows render with the number withheld.
+ # Installed levers are appended here too. Whether a package registered one has
+ # nothing to do with whether there are sessions to score it against, and an empty
+ # scope was silently hiding the only evidence that a lever package was present.
return "".join(
- f"
"
- f"{i + 1}{n}"
- f"—
"
- f"
"
- f"
not scoredPHASE 2
"
- for i, n in enumerate(_LEVER_NAMES)
+ [
+ f""
+ f"{i + 1}{n}"
+ f"—
"
+ f"
"
+ f"
not scoredPHASE 2
"
+ for i, n in enumerate(_LEVER_NAMES)
+ ]
+ + _measured_rows(d)
+ + _installed_rows(d)
)
top = max((r["usd"] for r in rows), default=0.0)
out = []
@@ -2457,9 +2473,59 @@ def _lever_rail(d: Dict[str, Any]) -> str:
f"{risk or '—'}"
)
out.extend(_measured_rows(d))
+ out.extend(_installed_rows(d))
return "".join(out)
+def _installed_rows(d: Dict[str, Any]) -> List[str]:
+ """Levers a package registered but which have not produced a number yet.
+
+ Without these an imported skill is INVISIBLE. Discovery finds it, the payload carries it,
+ every mode resolves it — and the rail renders only the simulated headroom rows and the
+ measured ones, so a developer who installs a lever package sees no evidence it worked.
+ That was the state until now: `installed` was in the payload and read by nothing.
+
+ They carry no figure on purpose. A registered lever that is `off` has produced neither a
+ measurement nor a simulation, and inventing a number for it here would put a third claim
+ on a rail that already has to keep two apart. What it shows instead is what a developer
+ actually needs: that the package is present, which levers came with it, their declared
+ risk, and the one word standing between the lever and doing something.
+ """
+ lv = d.get("levers") or {}
+ installed = lv.get("installed") or []
+ if not installed:
+ return []
+ modes = lv.get("modes") or {}
+ scored = {r.get("lever") for r in ((lv.get("measured") or {}).get("by_lever") or [])}
+
+ rows = ["Installed levers
"]
+ for item in sorted(installed, key=lambda i: i.get("id") or ""):
+ lid = item.get("id") or "?"
+ if lid in scored:
+ continue # already has a measured row above
+ mode = modes.get(lid, "off")
+ risk = escape((item.get("risk") or "").replace("*", ""))
+ needs = " · needs the proxy path" if item.get("requires_content") else ""
+ tip = (
+ f"Registered by {item.get('dist') or 'an installed package'} through the "
+ f"ace.sidecar.levers entry-point group. Mode is {mode.upper()}, read from "
+ f"~/.ace/config.json — installing a lever never enables it. "
+ f"Declared risk {risk or 'unstated'}."
+ + (" This lever needs the actual tool-result bytes, so it only runs on a proxied "
+ "turn, never on a transcript scan." if item.get("requires_content") else "")
+ )
+ cls = "on" if mode != "off" else "z"
+ rows.append(
+ f""
+ f"
●"
+ f"{escape(item.get('label') or lid)}"
+ f"{escape(mode.upper())}
"
+ f"
{escape(item.get('dist') or '')}{needs}"
+ f"{risk or '—'}
"
+ )
+ return rows if len(rows) > 1 else []
+
+
def _measured_rows(d: Dict[str, Any]) -> List[str]:
"""Rows for levers that actually ran, appended to the same rail.
diff --git a/tests/test_lever_shadow.py b/tests/test_lever_shadow.py
index e9ec1d8..463c61e 100644
--- a/tests/test_lever_shadow.py
+++ b/tests/test_lever_shadow.py
@@ -773,3 +773,63 @@ def blocked(name, *a, **k):
new_raw, info = runner.actuate(json.dumps(body).encode(), body)
assert new_raw is None, "no splice mechanics means the original bytes go out"
assert any("ace-skills is not installed" in r for r in info["refused"])
+
+
+# -- the rail must show a lever that was installed but has produced no number ----------------
+
+
+def test_an_installed_lever_is_visible_even_with_no_measurement(store):
+ """The bug this covers: discovery found the levers, the payload carried them, every mode
+ resolved them — and the rail rendered only simulated headroom and measured rows, so a
+ developer who installed a lever package saw no evidence of it anywhere on the page."""
+ from ace.sidecar.dashboard_render import _lever_rail
+
+ d = {
+ "scorecards": {"standalone": []},
+ "levers": {
+ "status": "all_off",
+ "installed": [
+ {"id": "tail_truncation", "label": "Cap oversized tool results",
+ "risk": "LOW", "dist": "ace-skills", "requires_content": False},
+ {"id": "image_stripping", "label": "Strip stale screenshots from history",
+ "risk": "MEDIUM", "dist": "ace-skills", "requires_content": True},
+ ],
+ "modes": {"tail_truncation": "off", "image_stripping": "shadow"},
+ "measured": {},
+ },
+ }
+ html = _lever_rail(d)
+ assert "Cap oversized tool results" in html
+ assert "Strip stale screenshots from history" in html
+ assert "ace-skills" in html, "the providing package must be named"
+ assert "OFF" in html and "SHADOW" in html, "the resolved mode is the actionable part"
+ assert "needs the proxy path" in html, "a content-requiring lever must say so"
+
+
+def test_a_measured_lever_is_not_listed_twice(store):
+ """It already has a row above with a real figure; repeating it as 'installed' would imply
+ two levers."""
+ from ace.sidecar.dashboard_render import _lever_rail
+
+ d = {
+ "scorecards": {"standalone": []},
+ "levers": {
+ "status": "measured",
+ "installed": [{"id": "tail_truncation", "label": "Cap oversized tool results",
+ "risk": "LOW", "dist": "ace-skills", "requires_content": False}],
+ "modes": {"tail_truncation": "shadow"},
+ "measured": {"by_lever": [
+ {"lever": "tail_truncation", "turns": 3, "removed_tokens": 900, "usd": 0.5,
+ "unpriced_turns": 0, "revisit_candidates": 0, "revisits": 0,
+ "revisits_paginated": 0}]},
+ },
+ }
+ html = _lever_rail(d)
+ assert html.count("Cap oversized tool results") == 1
+ assert "MEASURED" in html
+
+
+def test_nothing_installed_adds_nothing(store):
+ from ace.sidecar.dashboard_render import _lever_rail
+ html = _lever_rail({"scorecards": {"standalone": []}, "levers": {}})
+ assert "Installed levers" not in html