Commit Graph
1579 Commits
Author SHA1 Message Date
digital-garbage 4aad3d7a09 refactor: block-influence data lives in Settings, not the console
Research data belongs in Settings > Refinement & Taste — readable,
downloadable, clearable, with its own collection switch — not in a run
report that already carries more than anyone but us needs.

- Removed the sampler widget and its Editor knob entirely. Collection is
  driven by a global switch (env var live for this process + on-disk copy
  so a fresh rental comes back recording), the same two-layer mechanism
  trajectory_probe uses.
- Removed the per-rating console readout. Findings go to the panel;
  failures still speak through funpack_log.
- New section in Refinement & Taste: toggle, recorded count, Download,
  Clear, a plain-language flatness verdict, and the busiest blocks ranked
  with their liked-vs-disliked delta.
- Routes: GET/POST /api/block_influence, /export, /clear.

The switch gates whether the PROBE is installed and nothing else —
save_pending/commit stay unconditional, with a test pinning that, since a
toggle that quietly stops recording ratings is a mistake this project has
already made once.

Verified live: routes round-trip, the panel renders a seeded 6-run
profile, and a planted rating-correlated bump at block 31 surfaces as
+0.0107 in the UI. Seed data cleared afterwards.
2026-09-04 17:13:35 +03:00
digital-garbage d6981036d0 feat: per-block influence probe for H3 (measurement only)
Records ||f_i(x_i)|| / ||x_i|| on video rows for every block, averaged
over each run's steps, and pairs the profile with that run's rating.
Answers the question that gates rating-driven block weighting: is H3's
depth profile flat (nothing to aim at) or structured? Reports a
scale-invariant flatness number, and once a key has 2+ liked and 2+
disliked runs, which blocks run hotter on the liked ones.

Steers nothing. Installed BEFORE any steering hook so the delta it
records is the block's own, not one already containing an injection.
Bounded cost: two norms per block per step on ~512 strided rows, no
extra forward pass, results accumulated as device tensors and synced
once per run rather than 50x per step. Says so explicitly when it
records nothing, since an empty capture and a flat profile are
otherwise indistinguishable downstream.

Adjacent to per-block residual steering, removed in b7ed4f9 for
finding no rating signal above the 4th decimal -- that pass had no
per-step resolution, which its own removal note named as the gap.
This either reproduces that null definitively or it doesn't.
2026-09-04 17:01:21 +03:00
digital-garbage 8e31dcbff6 fix: report when DynaShift's positive pull is silently inactive
The status line at generation start only counted bank sizes, not
whether entries actually match this run's latent resolution -- so
"positive pull active (N liked)" could be true by that rough count
while the real per-resolution check inside the wrapper found nothing
usable, with no way to tell from the log. Negatives already had this
warning; positives didn't. Now both report a resolution mismatch.
2026-09-03 23:56:43 +03:00
digital-garbage b7f15a1a6b feat: re-enable DynaShift on H3, add a positive-pull bank alongside
the negative one

DynaShift was forced off for H3 in the 2026-09-03 disable pass on
theoretical grounds (LTXAV-calibrated, never actually tested on H3) --
re-enabled here to find out. Also gives it a second bank: negative_memory
now stores liked generations the same way it already stores disliked
ones (is_positive_profile, same sign-only convention h3_repr_steering
uses), and _build_dynashift_wrapper computes mean(liked) - mean(disliked)
over each bank's matching-resolution frames as a pull direction --
deliberately NOT nearest-neighbor matching toward one liked example,
which would risk reproducing that specific past generation. Needs
MIN_BANK_FOR_PULL (2) entries in each bank at the run's own latent
resolution before it contributes anything.

Reuses the existing dynashift/dynashift_strength/dynashift_threshold
controls for both directions -- no new Editor UI needed.
2026-09-03 23:22:35 +03:00
digital-garbage a239cdb1b8 fix: h3_repr_steering_block widget was inserted mid-list, breaking
positional reference-workflow mapping

builder.py's extract_widgets maps a reference workflow's stored
widgets_values onto this node's CURRENT INPUT_TYPES order, positionally.
Inserting a new widget between h3_repr_steering_strength and
alg_guide_blur_strength shifted every widget declared after it by one
slot for any project that hadn't explicitly overridden that field in
sampler_inputs -- silently feeding it the previous field's stale value.
Moved to the end of the widget list (append-only, per the existing note
near debug_log) so nothing downstream is displaced.
2026-09-03 22:52:31 +03:00
digital-garbage 4e08348574 feat: extend REINS candidate/steerable blocks down to 1 and 5-15
CANDIDATE_BLOCKS now covers the whole depth range (1-45), and the
block-choice combo (node + Editor) offers 1/5/10/15 alongside the
existing 20-40 -- test-only, for probing the shallow end where the
anchor/reference rows haven't been attended to yet.
2026-09-03 22:37:59 +03:00
digital-garbage 978e762e90 feat: expose REINS block-choice in the Editor's Engine Settings
Added a dropdown next to Representation steering strength, not just on
the raw node -- same as every other sampler toggle this project has
shipped.
2026-09-03 22:25:55 +03:00
digital-garbage ad95c03f6e feat: pick which block REINS steers (test-only)
New h3_repr_steering_block combo (20/25/30/35/40, default 25) lets a run
inject the learned direction at a different candidate block instead of
always DEFAULT_BLOCK. Capture and block_sweep across all candidate blocks
are unaffected.
2026-09-03 22:22:57 +03:00
digital-garbage ad9a8f1c5e fix: block 25's captured descriptor was taken AFTER injection, not before
Confirmed by reading the hook directly: capture() ran on `out` after
the steering push was already added, and injection only ever happens
for block == DEFAULT_BLOCK -- so block 25's own logged descriptor
depended on whatever strength was dialed in at generation time, while
every other candidate block (never injected into) stayed clean. That
made block 25's block_sweep entry incomparable across different
strength settings and incomparable to the other 8 blocks, which is
exactly the inconsistency observed live (block 25 significant at
strength 0.1, not at 0.05, on data collected under each).

capture() now runs before the injection is added, so the logged
descriptor always reflects the network's natural behavior at that
block regardless of steering strength -- generation still receives
the injected push, only the log changed.
2026-09-03 21:30:38 +03:00
digital-garbage e079c01c09 revert: remove prompt_hash cross-prompt grouping from block_sweep
Never worked on this R2V-wired setup (prompt_hash always came back
None, silently disabling the guard on every sweep) and fixing it was
explicitly declined. Removed rather than left inert -- a guard that
never engages is worse than no guard, since it implies a protection
that was never actually there.
2026-09-03 21:21:35 +03:00
digital-garbage 4d92451b00 feat: add a rollback button for the last Update/Switch branch
Reads git's own reflog (HEAD@{1}) rather than a separate state file
-- pull()/checkout() already move HEAD, so git already remembers what
it was before, and there's nothing new to keep in sync. Refuses on a
dirty tree, same as pull()/checkout(). Does not reinstall
requirements for the target commit -- reversing a pip install
automatically risks breaking other already-installed packages, out of
scope here; surfaced as a warning in the confirm dialog instead.

Welcome screen / Settings maintenance row goes from 3 buttons to 4;
only enabled when there's actually something to undo.
2026-09-03 21:21:35 +03:00
digital-garbage 7d2a33f92b perf: vectorize separation_statistic/permutation_test's O(n^2) inner loop
Measured, not assumed: 9 blocks x 2000 trials at n=30 took 8.16s
before this (pure-Python nested loops, GIL-held throughout -- moving
it off the event loop via asyncio.to_thread does NOT mean it stops
costing real wall-clock time, it just stops blocking OTHER requests
while it costs that time). The O(n^2) between/within split is now a
single tensor broadcast per call, and the biggest remaining cost
(permutation_test recomputing the full _unit()+matmul on every one of
2000 trials, when only the shuffled labels change) is hoisted out of
the loop. Same 9x2000 sweep: 0.76s, 10.7x faster.

All 48 existing trajectory_probe tests pass unchanged -- same exact
p-values, same edge cases -- confirming this is a pure speed fix, not
a behavior change. Benefits both trajectory_probe's own "Read" button
and h3_repr_steering's block_sweep, which share this code.
2026-09-03 20:53:29 +03:00
digital-garbage fdc75d1aed fix: block sweep was running on every Settings panel open, stalling the server
block_sweep() is a 9-block permutation test (2000 trials each by
default) -- heavy enough on CPU that running it synchronously inside
the status route (which fires on every panel mount) blocked the same
event loop ComfyUI's own server runs on. Confirmed live: opening
Settings > Refinement & Taste froze an in-progress generation.

Split the same way trajectory_probe already is: status stays cheap
(no sweep), the sweep moves to its own POST route, run off the event
loop via asyncio.to_thread, triggered only by an explicit "Read"
button instead of automatically on mount.
2026-09-03 20:41:41 +03:00
digital-garbage 9c0dac7076 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.
2026-09-03 20:17:31 +03:00
digital-garbage a2da292f52 fix: commit() reports whether a row was actually recorded, not just the reward
"Committing weight +X" printed unconditionally, before checking
whether there was a pending capture to attach it to -- so a correctly
computed reward with nothing to pair it with (capture was off, or the
sampler's h3_repr_steering toggle was off, on the run being rated)
looked identical in the log to a real commit. That's the gap that
made "0 liked / 0 disliked" on a cleared key impossible to diagnose
from the console alone: the weight line looked right every time.

commit() now returns "recorded" | "no_pending" | "disabled" | "no_key"
and the caller prints which one actually happened.
2026-09-03 20:11:34 +03:00
digital-garbage 19ce43bfb8 feat: H3 picker goes binary (Liked/Disliked); REINS gets its own capture pause
Picker: h3_repr_steering only ever reads the reward's SIGN now (see
the binary-direction commit), so a 1-10 scale was granularity nothing
downstream uses. Down to two buttons -- reuses the scale's own "10"
and "1" endpoints, zero backend change.

REINS capture toggle: independent of the sampler's h3_repr_steering
widget, which controls whether the learned direction gets APPLIED --
this new per-key flag controls whether it keeps RECORDING at all, so
data collection can be paused without touching the steering setting
or discarding what's already captured. Settings > Refinement & Taste
gets the toggle; save_pending() is the single gate.
2026-09-03 20:00:01 +03:00
digital-garbage cbc0c322a9 fix: REINS direction reverts to binary (sign only), not weighted by magnitude
Weighting by rating magnitude (a 9/10 pulling harder than a 6/10) is
the better estimator in the limit, but needs enough data for a
weakly-rated row's noise to average out. At the handful of ratings a
key actually accumulates, a mediocre "6" just gets a vote and dilutes
the direction with an ambiguous case instead of being excluded by it.
Binary spends what little data exists on the clearest examples only.

block_sweep(), multi-block capture, and prompt-hash grouping are
unaffected -- only direction()'s own math changed.
2026-09-03 19:54:49 +03:00
digital-garbage 329e2ec057 fix: stop printing the block-sweep ranking to console every rating
Duplicated what Settings > Refinement & Taste already computes and
shows as a table on demand. Console still gets the compact one-line
commit confirmation; the full per-block permutation-test ranking now
lives only in the panel.
2026-09-03 19:30:55 +03:00
digital-garbage 4af9875d15 feat: H3 block-depth sweep + Settings export/clear UI for REINS
Captures every candidate block (5,10,...,45, plus DEFAULT_BLOCK=25)
read-only alongside the one that actually steers, so block_sweep()
can answer "which block really separates liked from disliked" from
data already being collected -- reusing trajectory_probe's own
permutation test (proven correct on this project's real data) instead
of trusting REINS' 50%-depth heuristic (their own paper picks the
best layer per model by sweep, not by applying one universal
percentage) or porting a diagnostic built for a different question
(LTXAV's identity-block search measured cross-scene consistency, not
liked-vs-disliked separation).

Grouped by prompt_hash (trajectory_probe's own, reused) so cross-
prompt content differences can't masquerade as a rating signal -- the
same confound that inverted the first cross-prompt read of this
project's output value function.

Settings > Learning > Refinement & Taste gets a per-key REINS panel
(status, block-sweep table, export/clear) mirroring the trajectory
probe UI, plus matching /api/h3_repr_steering routes -- so data can
be pulled off a rental and handed over directly instead of relayed
through pasted console logs.
2026-09-03 19:26:30 +03:00
digital-garbage eb0c76ef9a feat: lower REINS' activation floor from 3+3 to 2+2 rated generations 2026-09-03 19:06:04 +03:00
digital-garbage 3e5c07249a fix: close a gap in the H3 disable pass — output_guidance snapshot and DynaShift capture
Both were captured "regardless of the toggle" by original design (so
turning guidance on later works immediately), which meant they kept
running on H3 even after output_guidance/dynashift were forced off —
exactly the kind of function the "disable everything unrelated to
REINS" pass was supposed to catch, missed because the capture point
predates any toggle check.

Confirmed live: the user's own log showed "DynaShift negative bank
updated — 1 entry" after the rest of the disable pass had already
landed.
2026-09-03 18:59:47 +03:00
digital-garbage 85add9ed84 fix: H3 scale ratings were silently discarded and replaced with the default
Root cause of "every rating counts as liked": the 'rating' node
input is a COMBO widget the graph builder validates against
V2_RATING_LABELS (builder.py's _live_value) -- the same guard that
falls back to a node's default when a saved LoRA/model choice isn't
installed on this machine. The H3 scale sends bare digit strings,
which were never added to that list, so EVERY H3 rating since the
scale shipped was silently rejected as "not a valid choice" and
replaced with the node's declared default, "Missing action" (+0.05)
-- explaining the diagnostic log exactly: legacy_score=None (never
reached the digit-parsing path at all) and reward +0.050 (the
literal default, not a mapped value).

Confirmed with the log line the user captured: the fix earlier this
session to normalize_refiner_v2_rating's digit math was correct and
irrelevant -- the real rating value never reached that function.

Fix: add "1".."10" to V2_RATING_LABELS so they pass validation
unchanged, same list both rating widget declarations already read.
2026-09-03 18:56:28 +03:00
digital-garbage 90250e9f6a debug: log the weight REINS actually commits, and which rating produced it 2026-09-03 18:52:24 +03:00
digital-garbage 6a942ae3a9 feat: disable every rating-driven mechanism on H3 except phrase emphasis and REINS
H3's only validated (or being-validated) rating consumers are
h3_phrase_emphasis and h3_repr_steering. Everything else --
value_guidance/absolute taste steering, output_guidance,
trajectory_guidance, dynashift, embed_guidance, score_slider,
taste_nearest_prompt, and the path planner -- was built and
calibrated for LTXAV or for a value function nothing on H3 reads.
None of it helps REINS; it only trains value functions that are
never consumed and prints status lines for mechanisms that can
never fire, which is what actually produced the "80% of the log is
useless" bug report this responds to.

Forced off at two chokepoints (top of sample() in samplers.py once
self._is_h3 is known; top of refine_v2 in conditioning.py once the
clip's family is known), not just hidden in Engine Settings, so a
project saved before this still behaves correctly. Value-function
and Absolute-taste TRAINING (not just application) is skipped too --
per-scene, per-key, and the main path -- since nothing on H3 will
ever read what they'd produce.
2026-09-03 18:46:30 +03:00
digital-garbage c8993891c6 fix: H3 scale's reward sign was backwards for 5 and 6 out of 10
normalize_refiner_v2_rating's legacy digit path snapped a bare number
to the nearest existing category label and used THAT label's reward
verbatim. Missing action's +0.05 was calibrated for its own meaning
("the frame was fine, just no motion") -- not "a mediocre score" --
but 5 and 6 both landed in that bucket, so rating something a 5/10
produced a POSITIVE reward. Every h3_repr_steering weight built from
those ratings was backwards.

Reward is now a straight linear map across the full 1-10 range
(1 = -0.9, 10 = 1.0), so the sign matches what the scale promises.
Level/missing_axes/skip flags still come from the nearest label --
harmless, since nothing needs them exact for a legacy score.
2026-09-03 18:42:59 +03:00
digital-garbage 3ba114708b feat: h3_repr_steering learns a weighted direction, not a hard liked/disliked split
Every rated run now pulls proportionally to its own reward instead of
being bucketed into two equal-weight groups -- a 9/10 counts for more
than a 6/10, instead of both counting as one full vote. Centring the
WEIGHTS (not the descriptors) before the weighted sum is what makes
shared content cancel exactly even when the weights are unbalanced;
see the module docstring for the identity. This is what actually
justifies the scale existing at all, rather than just picking one of
two buckets with extra steps.

Also: the H3 scale's heart/loved button did nothing --
normalize_refiner_v2_rating only applies the loved boost inside the
branch that matches an existing category label, and a bare number
never reaches it (confirmed: '7' and '7|loved' produced the identical
reward). Removed it from the scale rather than wire a boost with no
established meaning on a 1-10 input.
2026-09-03 18:30:17 +03:00
digital-garbage 33038ae700 feat: H3 rating picker becomes a 1-10 scale; REINS learns from rating identity, not reward sign
The category grid assumes axis-specific effects (phrase emphasis,
dynashift...) this project has not proven land differently on H3.
Replaces it with a single scale for H3 pipelines only -- the backend
already turns a bare number into the nearest existing rating profile
(normalize_refiner_v2_rating's legacy-score path), so every consumer
(value functions, phrase emphasis, dynashift, path planner) keeps
working unchanged; only what the picker sends changes.

Also fixes h3_repr_steering: it was splitting liked/disliked by the
sign of the blended scalar reward, which counts near-misses like
Missing action (+0.05) as "liked" even though that reward exists for
the value functions' quality-landscape ascent, not as a liked/disliked
verdict. Now filters by rating KEY (LIKED_KEYS/DISLIKED_KEYS) and
excludes everything ambiguous instead of guessing a side for it.
2026-09-03 18:22:11 +03:00
digital-garbage 6e28f56c92 feat: REINS-style representation steering for H3 (experimental)
Reaches inside the forward pass instead of around it: captures the
video rows of one block's hidden state per generation, and once a
refinement key has 3+ liked and 3+ disliked runs, adds their mean
difference back into that block's output on every later run. No
gradient, no MLP -- a mean-difference of vectors is the whole model.

Masked to video rows only via the block's own mod_segments tags,
never audio or text -- the one documented failure of this class of
intervention (project_self_consistency_failed.md) happened on a
different model (LTXAV) via joint audio-video attention.

Off by default, H3-only, unvalidated.
2026-09-03 17:50:37 +03:00
digital-garbage c86e8894f6 feat: variability dial on H3 phrase emphasis
0 = only cemented phrases get extra attention. 1 = that bias
collapses to nothing, letting untrained content compete evenly.
Same attention-bias channel as the existing toggle, scaled down.
2026-09-03 16:58:34 +03:00
digital-garbageandClaude Opus 5 3a62759be9 feat: a way to throw the learned state away and start clean
Settings ▸ Learning ▸ "Start a fresh measurement". Deleting the refinement key
was not enough: the probe log lives outside the <key>.* sidecar convention on
purpose, so it survives a key clear, and the per-bucket heads are REBUILT from
it on every rating — the next rating restored them from runs still on disk.

So the clear takes both, and leaves the switch alone: "throw away what was
measured" and "stop measuring" are different requests.

Verified against a running ComfyUI: 12 runs and the heads file removed, count
back to 0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 14:47:26 +03:00
digital-garbageandClaude Opus 5 787e379ffc fix: trajectory guidance never trained — the heads were empty every run
ComfyUI executes a node under torch.inference_mode(), so a descriptor read out of
the probe log becomes an inference tensor and autograd refuses it:

  Trajectory probe intake failed: Inference tensors do not track version counter.

Every head stayed empty and the run reported "nothing learned yet" on every
generation — so the feature was OFF while looking merely untrained, which is the
one failure invisible from the outside: "not steering" is also what correct
behaviour looks like before enough ratings. Seen on a live rental with 73 runs
logged and zero of them trained.

The output value function's trainer already carries this guard; this one did not.

Also: the bucket-isolation test was measuring TRAINING accuracy, where a
few-hundred-parameter MLP fits 20 noise vectors perfectly and every bucket scores
1.0. It now holds rows back, which is the only version that can tell a head that
learned from one that memorised.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 14:41:00 +03:00
digital-garbageandClaude Opus 5 d392578832 feat: steering that reaches the first half of a generation
Every rating-driven mechanism shares one gate that opens only over the last half
of the schedule — after motion and layout are decided — so a rating about
movement has never had a window to act in.

This learns one value function per schedule quarter, each trained on that
quarter's own predicted output, each steering inside its own window, with no
shared late ramp. It reads the probe's log, so it starts trained on whatever has
already been rated.

Basis: 51 rated runs across two independent sessions, different prompts and
balances. The early window measured 88% and 89% of the late window's effect,
direction unanimous across all 8 bucket-by-session results, sessions combining
to p 0.043. Cross-validated on the clean session the heads rank held-out runs at
AUC 0.73-0.82.

Beside output_guidance, not replacing it, and off by default: the honest test is
the same seed with it off and on. A window with under 10 samples is byte
identical to the feature being off, so "nothing changed" stays readable, and the
run says which windows can steer rather than only that it is on.

Not included: axis routing (quality late, action early). It is the next step and
it would muddy this A/B.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 14:29:17 +03:00
digital-garbageandClaude Opus 5 ff2e1bf046 fix: compare what differs between runs, not what they share
Runs of one prompt share most of their content: on a real 21-run session, 86% of
each descriptor was the part every run had. Comparing raw vectors measured that
shared part, so every distance came out near zero and near equal — mean cosine
0.97, and no separation at ANY bucket including the late ones where steering
demonstrably works.

Centring first flips the same data from -0.002 (backwards) to +0.03 and p 0.83
to 0.11, consistent across all four buckets. Not significant at 5 good / 16 bad,
but pointing the right way and now limited by sample size rather than by the
statistic.

The descriptor was not at fault. adaptive_avg_pool1d over the flat latent keeps
512 REGIONAL means, not one global mean, and it distinguishes clips fine.

Also: the prompt id is quantised before hashing. Raw bytes answered "are these
bit-identical", so any value crossing a rounding boundary changed the id — one
prompt produced 20 distinct ids across 21 runs. Stable now for jitter of the
size a GPU produces; no exact hash of floats can do better.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 13:44:48 +03:00
digital-garbageandClaude Opus 5 349cf75859 feat: carry the trajectory measurement between machines
Settings ▸ Learning gains Download and Load. A rental is replaced whenever
something breaks, refinements/ is not in git, and the reading needs ~16 rated
runs — so without a way off the box the count restarts on every instance and
the answer is never reached. 16 runs is ~85 KB.

Importing the same export twice adds nothing: the permutation test reads n
directly, so duplicated runs would report a separation as far more significant
than the evidence supports.

An uploaded .pt is a pickle, so the restore parses it with weights_only — every
field in a run is a tensor or a primitive, and anything else is refused rather
than executed. Nothing but numbers, a rating key, a timestamp and a one-way
prompt hash is stored; no prompt text has ever been written to these files.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 13:06:33 +03:00
digital-garbageandClaude Opus 5 818ed26c49 feat: trajectory probe lives in Settings, not the terminal
Settings ▸ Learning ▸ Trajectory probe: a switch to record, the run count,
and a Read button that gives the answer in plain language. The switch is the
same environment variable the sampler reads and the editor sets it in the
running process, so it takes effect on the next generation with no restart —
and it is written to disk, so a restarted box comes back recording instead of
having quietly stopped.

tools/trajectory_separation.py stays as the terminal door for a headless box.

Verified against a running ComfyUI: toggle both ways, persistence across a
real restart, and the reading recovering a planted early signal.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 15:55:37 +03:00
digital-garbageandClaude Opus 5 39d0f312de feat: trajectory probe — does a rating show up before the halfway point?
Every rating-driven mechanism shares one gate (_make_steer_ramp) that opens
only over the last half of the schedule, so a "Missing action" rating has no
window in which it could act. Banking x0_hat per schedule position would give
it one — if the early half carries any signal. This measures that.

Off unless FUNPACK_TRAJECTORY_PROBE=1. Records, never steers. Built for H3:
buckets clamp to few-step runs, batched predictions are refused rather than
averaged with their unconditional row, and each pass binds its own schedule.
Read the result with tools/trajectory_separation.py.

fix: reference numbering counts within its own kind

A reference slot resolves per kind, so marking an image then a video labelled
the video R2 while the only slot reaching it was "Reference video 1" — there
was no way to have an R1 video and an R1 image at once.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-31 15:35:41 +03:00
digital-garbage deeb4c0b74 docs: announce FunPack v5 "Cunning Cranberry" 2026-08-27 16:26:00 +03:00
digital-garbage e35bae00a5 Merge v4 into main - Release 4.0.0 "Blinding Blackout" 2026-08-27 14:48:14 +03:00
digital-garbageandClaude Opus 5 3b7f21bf30 Merge main into v4
main carried two commits v4 branched before, including the README cleanup.
README resolved to v4's, which is main's own text with the "v4 in progress"
section replaced by What's new. Nothing else differed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:47:22 +03:00
digital-garbageandClaude Opus 5 807c1b9999 docs: drop the mid-scene guide from the sampler reference
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:44:23 +03:00
digital-garbageandClaude Opus 5 8763475f91 docs: prepare 4.0.0
CHANGELOG: stamp [4.0.0] "Blinding Blackout" and record what this release
removes.

README: rebased on main's, which is the maintained one — the copy on this
branch was an older, longer version. Only the "v4 in progress" section is
replaced, by a short What's new block. The migration notice stays as written.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:43:21 +03:00
digital-garbageandClaude Opus 5 b16d48b2db maint: finish prompt repair, and label bounded attention untested
Prompt repair lost most of itself in an earlier stage; what was left was a
fallback that appended missing phrases back onto the prompt, reachable only
through a list nothing fills any more. Gone. The axes stay — active_repair_axes
is the "what's missing" signal the advisor reads, and it never edits a prompt
by itself.

prompt_repair and prefer_wired_conditioning are read by nothing at all and only
survive in old saved settings, so the card stops printing them.

Bounded attention is built and has never been run, and its left/right split is
fixed. Both labels now say so.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:41:10 +03:00
digital-garbageandClaude Opus 5 0158cd0eb9 maint: take segmented detailing out of the Editor, keep the code
Never validated on a real run, so 4.0.0 does not offer it. The widgets stay
for a raw ComfyUI graph and the module is marked FOR FUTURE REFERENCE — the
CLIPSeg tube, the upsampler pass and the feathered paste-back are the hard
parts and are worth having if it is picked up again.

The card still hides its settings when it is off, so a graph that does tick it
still reads correctly.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:38:56 +03:00
digital-garbageandClaude Opus 5 987beef9d9 maint: remove the H3 audio clock
Did not work. The widget, the per-step correction, the denoiser proxy for
samplers whose loop we do not own, the sampler-suitability tables, and its
test file.

The step helper was identity without a clock, so every call site in the
distilled-flow and hybrid loops becomes the value it was passing through.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:36:03 +03:00
digital-garbageandClaude Opus 5 7537ec0bef maint: remove the mid-scene guide
Not used on H3, not used on LTX any more. Two widgets, the append method, the
Editor's continuity controls for it, and the auto-enable that turned it on for
every multi-scene carry chain.

JoyAI memory and carried i2v guides keep the guide-attention machinery they
share with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:32:20 +03:00
digital-garbageandClaude Opus 5 aebc286042 maint: remove the H3 render gains
Six widgets (three write gains, prompt loudness, taste push, learned/manual
mode) and the whole rating loop behind them. Never proved out on the rental:
picture gain past +-0.1 adds distortion and latent noise, the rest changed
nothing legible, and the audio gain was never worth testing.

The final-layer picture detail SURVIVES and now reads its own widget — it was
the only one of the set that showed a real effect. Relabelled experimental.

Two things fall out with them. The refinement key no longer holds any sampler
value, so key scoping has nothing left to scope and goes too. And the card's
ownership table now reads dependsVals as well as dependsValue: the Studio rows
use the plural form, so absolute_strength was printing under steer_mode
"relative", where it does nothing.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:30:19 +03:00
digital-garbageandClaude Opus 5 8374838e46 maint: remove the reference-weight dial (h3_prompt_time)
Seven rental runs across its whole range: below 0.5 the picture breaks up,
above 0.5 it reproduces the reference outright, and nothing in between is
worth having. It never did the job it was built for either.

Kept: the final-layer video scale it shipped alongside, which does work.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:23:57 +03:00
digital-garbageandClaude Opus 5 511713593c maint: remove the plateau step-cache
Measured on the rental and it never worked as intended. Two widgets, the
wrapper, the context-windows exclusion it needed, and its two tests.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 14:21:58 +03:00
digital-garbageandClaude Opus 5 663eae2c3a feat(card): drop dead keys and defaults from the Studio block too
On the card from the rental: Chain Sampler 35 rows -> 4, Studio 13 -> 6,
Studio inputs 2 -> 0.

Three additions. A key the node does not DECLARE is now dropped rather than
kept: ComfyUI builds a node's arguments from its own INPUT_TYPES, so
`block_steer` (removed from this pack entirely) and a `steps` key the Chain
Sampler has never had reached nothing, while printing beside live settings as
if they had. An empty value decided nothing either. And the studio_settings
refiner block is filtered against the Editor's own defaults — it has no node
to ask, so an unrecognised key there is still kept: unjudgeable is not inert.

identity_projector was printing a model filename under a disabled feature. It
is rendered by hand in the Editor so it carries no dependsOn, hence
_OWNED_EXTRA, kept apart so the generated half stays generated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 04:41:38 +03:00
digital-garbageandClaude Opus 5 138e13d901 feat(card): print what produced the video, not every widget that exists
Two rules: skip a value equal to the widget's own default, and skip a value
whose feature is switched off. A region-sharpening prompt printed under a
disabled sharpener read as if it had run, and enough of that buries the few
values that did decide the render. On a realistic project this cuts the Chain
Sampler section from 8 rows to 4.

Defaults are read off the node's own INPUT_TYPES rather than copied here.
Ownership mirrors the Editor's dependsOn wiring, and a test regenerates the
table from engine_settings.js so the two cannot drift. Owner chains are walked
to the end — v2a_grad_scale belongs to joyai_audio_memory, which belongs to
joyai_memory. A section left with nothing to say is dropped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 04:34:22 +03:00