From 9c0dac7076a1160a29b01b145bdbbb0cd52411b5 Mon Sep 17 00:00:00 2001 From: digital-garbage <133010426+digital-garbage@users.noreply.github.com> Date: Thu, 3 Sep 2026 20:17:31 +0300 Subject: [PATCH] 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. --- conditioning.py | 5 ++- h3_repr_steering.py | 45 ++++-------------------- movie_editor/frontend/api.js | 1 - movie_editor/frontend/settings_window.js | 33 ++--------------- movie_editor/server.py | 9 ----- tests/test_h3_repr_steering.py | 36 ------------------- 6 files changed, 11 insertions(+), 118 deletions(-) diff --git a/conditioning.py b/conditioning.py index 5cf8fbc3..404cc186 100644 --- a/conditioning.py +++ b/conditioning.py @@ -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 " diff --git a/h3_repr_steering.py b/h3_repr_steering.py index 2cd63335..3b84fadb 100644 --- a/h3_repr_steering.py +++ b/h3_repr_steering.py @@ -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: diff --git a/movie_editor/frontend/api.js b/movie_editor/frontend/api.js index 87038a3d..544a28a0 100644 --- a/movie_editor/frontend/api.js +++ b/movie_editor/frontend/api.js @@ -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"; diff --git a/movie_editor/frontend/settings_window.js b/movie_editor/frontend/settings_window.js index d88856f4..a72cb0c3 100644 --- a/movie_editor/frontend/settings_window.js +++ b/movie_editor/frontend/settings_window.js @@ -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) " diff --git a/movie_editor/server.py b/movie_editor/server.py index 8fc37591..c6c15890 100644 --- a/movie_editor/server.py +++ b/movie_editor/server.py @@ -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() diff --git a/tests/test_h3_repr_steering.py b/tests/test_h3_repr_steering.py index 05c62630..079320df 100644 --- a/tests/test_h3_repr_steering.py +++ b/tests/test_h3_repr_steering.py @@ -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)