revert: remove the REINS capture-pause toggle entirely

Misread "disable that .pt tracking" as "stop recording ratings" --
the actual ask was about console noise, already handled by removing
the block-sweep print. This toggle instead silently stopped every
rating from being recorded while it was on, confirmed live: a real
key sat at "0 liked / 0 disliked" through multiple ratings with no
visible error, and the "committing weight" log line looked correct
the whole time (fixed separately, but the toggle itself should never
have existed).

Removed cleanly rather than patched: capture_enabled/set_capture_enabled,
the enabled gate in save_pending/commit, the /enabled route, the API
client method, and the Settings toggle row. save_pending and commit
now behave exactly as they did before this was ever added -- every
rating is recorded, unconditionally.
This commit is contained in:
digital-garbage
2026-09-03 20:17:31 +03:00
parent a2da292f52
commit 9c0dac7076
6 changed files with 11 additions and 118 deletions
+2 -3
View File
@@ -10218,9 +10218,8 @@ class FunPackVideoRefinerV2(FunPackVideoRefiner):
_rs_note = {
"recorded": "recorded",
"no_pending": "NOT recorded — no captured generation was waiting "
"(capture may have been off, or the sampler's "
"h3_repr_steering toggle was off, when that run sampled)",
"disabled": "NOT recorded — capture is paused for this key",
"(the sampler's h3_repr_steering toggle was likely off "
"when that run sampled)",
"no_key": "NOT recorded — no refinement key",
}.get(_rs_outcome, _rs_outcome)
print(f"[FunPackRefiner] H3 representation steering: weight "
+7 -38
View File
@@ -116,43 +116,18 @@ def capture(hidden_state, video_mask):
def _load(refinement_key):
path = state_path(refinement_key)
if not os.path.exists(path):
return {"rows": [], "pending": None, "enabled": True}
return {"rows": [], "pending": None}
try:
data = torch.load(path, map_location="cpu", weights_only=True)
except Exception: # noqa: BLE001
return {"rows": [], "pending": None, "enabled": True}
return {"rows": [], "pending": None}
if not isinstance(data, dict):
return {"rows": [], "pending": None, "enabled": True}
return {"rows": [], "pending": None}
data.setdefault("rows", [])
data.setdefault("pending", None)
data.setdefault("enabled", True)
return data
def capture_enabled(refinement_key):
"""Whether this key is recording at all -- independent of the sampler's own
h3_repr_steering toggle, which also controls whether the learned direction gets APPLIED.
A user who wants to pause data collection (to test something else without polluting the
log, or because a sweep came back null and they want to think before adding more rows)
still needs the widget on for `block_sweep`/status to mean anything, so the pause lives
here instead of overloading that widget."""
if not refinement_key:
return True
return bool(_load(refinement_key).get("enabled", True))
def set_capture_enabled(refinement_key, enabled):
if not refinement_key:
return
data = _load(refinement_key)
data["enabled"] = bool(enabled)
try:
_save(refinement_key, data)
except OSError as e:
_log().failed("H3 representation steering", "set capture enabled", e,
"the pause/resume did not persist")
def _save(refinement_key, data):
path = state_path(refinement_key)
os.makedirs(os.path.dirname(path), exist_ok=True)
@@ -171,8 +146,6 @@ def save_pending(refinement_key, descriptors):
if not refinement_key or not descriptors:
return
data = _load(refinement_key)
if not data.get("enabled", True):
return
data["pending"] = {int(b): d.detach().float().cpu() for b, d in descriptors.items()}
try:
_save(refinement_key, data)
@@ -187,17 +160,13 @@ def commit(refinement_key, reward, prompt_hash=None):
already-resolved, already-admissibility-filtered reward -- this function trusts it rather
than re-deriving a verdict, same as the value functions do with the same number.
-> "recorded" | "no_pending" (nothing generated since the last rating -- or capture was
off when that generation ran, so nothing was ever saved to pair this rating with) |
"disabled" (capture is paused for this key right now) | "no_key". The caller prints this,
not just the reward it computed -- a reward can be correct and still never reach a row if
there was nothing to pair it with, and a log line that only ever reports the reward it
is ABOUT to commit cannot tell that apart from a real commit."""
-> "recorded" | "no_pending" (nothing generated since the last rating) | "no_key". The
caller prints this, not just the reward it computed -- a reward can be correct and still
never reach a row if there was nothing to pair it with, and a log line that only ever
reports the reward it is ABOUT to commit cannot tell that apart from a real commit."""
if not refinement_key:
return "no_key"
data = _load(refinement_key)
if not data.get("enabled", True):
return "disabled"
pending = data.get("pending")
data["pending"] = None
if pending is None:
-1
View File
@@ -200,7 +200,6 @@
// H3 representation steering (Settings ▸ Learning) — per-KEY, unlike the probe above.
reinsStatus: (key) => j("GET", API("/h3_repr_steering") + `?key=${encodeURIComponent(key || "default")}`),
reinsSetEnabled: (key, enabled) => j("POST", API("/h3_repr_steering/enabled"), { key: key || "default", enabled: !!enabled }),
reinsClear: (key) => j("POST", API("/h3_repr_steering/clear"), { key: key || "default" }),
async reinsExport(key) {
const k = key || "default";
+2 -31
View File
@@ -408,26 +408,6 @@
return tbl;
}
function reinsToggleRow(enabled, onChange) {
const row = el("div", "sw-row");
const main = el("div", "sw-row-main");
main.append(el("div", "sw-row-title", "Record ratings for this key"));
main.append(el("div", "sw-row-hint",
"On by default. Independent of the sampler's own toggle — that one controls whether "
+ "the learned direction gets APPLIED; this one controls whether it keeps learning at "
+ "all. Turn off to pause the log without losing what's captured, or while testing "
+ "something else you don't want mixed in."));
row.append(main);
const lbl = el("label", "chk es-toggle");
const cb = el("input");
cb.type = "checkbox";
cb.checked = !!enabled;
cb.onchange = () => onChange(cb.checked);
lbl.append(cb, el("span", null, ""));
row.append(lbl);
return row;
}
function reinsRows(key) {
const box = el("div", "sw-stack");
const paint = () => {
@@ -436,21 +416,12 @@
const nLiked = reinsState ? reinsState.n_liked : 0;
const nDisliked = reinsState ? reinsState.n_disliked : 0;
const ready = !!(reinsState && reinsState.ready);
const enabled = !reinsState || reinsState.enabled !== false;
rows.append(reinsToggleRow(enabled, async (on) => {
reinsError = "";
try { reinsState = await window.MovieEditorAPI.reinsSetEnabled(key, on); }
catch (e) { reinsError = String(e.message || e); }
paint();
}));
rows.append(infoRow("Rated generations (this key)",
`${nLiked} liked / ${nDisliked} disliked`, reinsState ? ready : null));
if (reinsState && !ready) {
rows.append(el("div", "sw-hint",
enabled
? `Needs ${reinsState.min_per_group}+ of each before it steers anything — still `
+ "capturing every generation either way."
: "Recording is off — nothing new is being captured for this key."));
`Needs ${reinsState.min_per_group}+ of each before it steers anything — still `
+ "capturing every generation either way."));
}
rows.append(actionRow("Save this key's REINS data",
"Downloads every captured run (all candidate blocks, not just the one that steers) "
-9
View File
@@ -2110,7 +2110,6 @@ if web is not None and PromptServer is not None:
"min_per_group": rs.MIN_PER_GROUP,
"default_block": rs.DEFAULT_BLOCK,
"sweep": {str(b): r for b, r in sweep.items()},
"enabled": rs.capture_enabled(key),
}
@routes.get(UI_PREFIX + "/api/h3_repr_steering")
@@ -2140,14 +2139,6 @@ if web is not None and PromptServer is not None:
body=body, content_type="application/octet-stream",
headers={"Content-Disposition": f'attachment; filename="{key}.repr_steer.pt"'})
@routes.post(UI_PREFIX + "/api/h3_repr_steering/enabled")
async def _repr_steer_set_enabled(req):
body = await req.json()
key = str(body.get("key") or "default").strip() or "default"
_repr_steer_module().set_capture_enabled(key, bool(body.get("enabled")))
_rs, state = _repr_steer_state(key)
return web.json_response(state)
@routes.post(UI_PREFIX + "/api/h3_repr_steering/clear")
async def _repr_steer_clear(req):
body = await req.json()
-36
View File
@@ -147,12 +147,6 @@ def test_commit_reports_no_pending_with_nothing_to_pair():
assert rs.commit("k", 1.0) == "no_pending"
def test_commit_reports_disabled_when_capture_is_paused():
rs.save_pending("k", _pend(torch.tensor([1.0, 0.0])))
rs.set_capture_enabled("k", False)
assert rs.commit("k", 1.0) == "disabled"
def test_commit_reports_no_key_for_an_empty_key():
assert rs.commit("", 1.0) == "no_key"
@@ -166,36 +160,6 @@ def test_pending_overwrites_not_accumulates():
assert torch.allclose(data["rows"][0]["desc"][rs.DEFAULT_BLOCK], torch.tensor([2.0, 0.0]))
def test_capture_enabled_defaults_true():
assert rs.capture_enabled("k") is True # no file yet -- still True, not False
def test_disabling_capture_stops_save_pending():
rs.set_capture_enabled("k", False)
rs.save_pending("k", _pend(torch.tensor([1.0, 0.0])))
rs.commit("k", 1.0)
direction, n_pos, n_neg = rs.direction("k")
assert n_pos == 0 and n_neg == 0 # nothing was ever captured to commit
def test_re_enabling_capture_resumes_it():
rs.set_capture_enabled("k", False)
rs.set_capture_enabled("k", True)
assert rs.capture_enabled("k") is True
rs.save_pending("k", _pend(torch.tensor([1.0, 0.0])))
rs.commit("k", 1.0)
data = rs._load("k")
assert len(data["rows"]) == 1
def test_disabling_capture_does_not_discard_existing_rows():
rs.save_pending("k", _pend(torch.tensor([1.0, 0.0])))
rs.commit("k", 1.0)
rs.set_capture_enabled("k", False)
data = rs._load("k")
assert len(data["rows"]) == 1
def test_clear_all_removes_the_state_file():
rs.save_pending("k", _pend(torch.tensor([1.0, 0.0])))
rs.commit("k", 1.0)