Files
soothe2-re/handoff/NOTES_LEVEL.md
T
Matiq f73724fee7 docs: archive 4024стр NOTES_LEVEL, единый источник TOTAL README, runbook AGENTS, 3-шаг план
- handoff/NOTES_LEVEL.md 4413→397 (голова 24mm5+), хвост → handoff/archive/NOTES_LEVEL_2026-08-18_2026-08-23.md
- handoff/NOTES_LEVEL_INDEX.md NEW навигатор, handoff/archive/ whitelist .gitignore
- SESSION_HANDOFF/summary → archive + редиректы, NOTES_TWIN/NOTES_CAPTURE сжаты
- README.md:13 единственный источник TOTAL 1.594/dual 0.193, AGENTS runbook, BITEXACT_PLAN 9→3 шага (каскад 9-19/k-маппинг/Δ)
2026-08-29 03:15:42 +03:00

30 KiB
Raw Blame History

NOTES_LEVEL — живой журнал детектора/маски (голова 24mm5+, 2026-08-28)

Архив 2026-08-18 — 2026-08-23 (4024 строки) → handoff/archive/NOTES_LEVEL_2026-08-18_2026-08-23.md. Оглавление по датам/темам → handoff/NOTES_LEVEL_INDEX.md (единственный навигатор). Статус TOTAL → README.md:13 (единственный источник).

Дубли заголовков (22g×2, 20s×2) устранены в архиве; заголовки унифицированы.

24mm5–24mm7 (продолжение захода)

  1. Полная буферная карта полосы-цикла: ДВА круга log→exp, между вторыми — бидир-IIR ×2 В ЛОГ-ДОМЕНЕ (= спектральное смешение детектора).
  2. Design 535a70 (своп аргументов) → 1802a24c0 = тело conv из вопроса 22z. Вход [r15]=bands_final@678+i, выход scratch@628.
  3. Тест: scr == ln(bands_final) с eps float32 (identity-фаза) ⇒ k=1.
  4. Перед EXP: FIR[1..n/2] *= 2.0 (@1824c41e0; исправление «÷−1» из 24l).
  5. γ=1.760561 возникает после design: кандидаты opB/opC и финальный combine df0(FIR, track_i); формулы-кандидаты в BLOCKMAP 24mm7.
  6. Все правки dataflow 24hh/24ii/24l перенесены в BLOCKMAP (14 порядок, ACC@7c8, ×2 вместо ÷−1, log#1/log#2 позиции).

24mm8-бис: точка входа следующего раунда

opB-воркер 18004ca80: пролог + тег [obj]==6 проверка (0xfffffff3 при сбое), дальше — дескрипторная операция над векторами (BLOCKMAP 24l «ops AD»). Полный дизасм не сохранён (скрипт-глюк с редиректом), перегенерировать: python3 scripts/disasm_func.py 18004ca80 0x300. Цель: найти множитель γ=1.760561 внутри opB/opC/df0 → замкнуть конвейер.

============ 24mm9: FIR-ЦЕПЬ ДЕКОДИРОВАНА = MIN-PHASE КЕПСТРАЛЬНЫЙ СЭНДВИЧ; ВАЛИДАЦИЯ 0.0065 дБ ============

Структура опов (полные дизасмы в /tmp/opencode/cascade/*.dis)

обёртки 125e0/5560: перестановка аргументов → воркер(rcx=data, rdx=data,
                    r8=ПЛАН, r9=WORK); всё ин-плейс над FIR
ПЛАН   = buf548@540548 (!НЕ маски/твидлы): {tag=6, log2n=12 [+4],
         [+8]=0, scale_flag=1 [+0xc], scale=2^-12 [+0x10], work=16384Б [+0x18]}
WORK   = buf598@540598 (рабочая область FFT, ~1.0 мусор; «lane-mask» из
         23b — УСТАРЕЛО)
th2180(воркер 4ca80) = INVERSE real-FFT (голова: сумма/разность X[0]/X[Nyq]);
th1a90(воркер 1a0c0) = FORWARD real-FFT (хвост: пакинг Найквиста в слот n);
тела — импортные близнецы 181b853e0/181b81b80 (AVX, только ±1/√2 твидлы,
без внутренних масштабов); ffe0 = in-place ×scale (skip при 1/0);
copy th2210→136e0→4d900 = пак real→interleaved complex (re=v, im=0).
df0 18000b3c0 = ПОЭЛЕМЕНТНОЕ КОМПЛЕКСНОЕ УМНОЖЕНИЕ, dst=arg2:
    track_i := track_i ⊗ FIR  (vfmaddsub213ps; двойная версия b560+)
EXP-ядро 140b30→1803831c0: таблично-полиномиальная комплексная экспонента
    (магия 12582912 expf-класса, guard 87.33654=maxarg2ln2,
    редукция 184.665≈128/ln2, диадич. {37/24,15/8,31/24,11/1024});
    численно ведёт себя как КОМПЛЕКСНЫЙ exp (вариант flat проиграл 8 дБ).
    Unicorn-эмуляция невозможна (нет FMA в TCG) — статический декод открыт.

Цепь (все константы из асмa; fn529fe0.dis 52b60c52b893)

scr@628 → pack(re=scr,im=0) 2049 пар
→ FIR[n]=FIR[4096]=0            ; 52b685 (Найквост re:=0, ДО фолда!)
→ inv-RFFT                      ; opA th2180
→ fold: y[1..2047]*=2.0         ; xmm13 @1824c41e0, 52d920
        y[2049..4095]=0         ; 52db50 (y[2048] НЕ трогается)
→ fwd-RFFT                      ; opB th1a90
→ комплексная EXP аргумент ×q   ; 52b716, q≈0.80 (см. ОТКРЫТО)
→ inv-RFFT                      ; opC th2180
→ float[0..2047]*=WINfreq[2048..4095] (падающий Hann); хвост=0 ; 52d990/db50
→ fwd-RFFT                      ; opD th1a90
→ FIR[0]=1.0, FIR[1]=0          ; 52b7cd
→ df0: mask_i := track_i ⊗ FIR  ; финальный combine

Это классическое построение минимально-фазового ядра через кепстр (IDFT лога → удвоение причинной части → exp → обратно).

Валидация (структурная фаза, критерий <0.05 дБ — ВЫПОЛНЕН)

60 ультрачистых кадров (|γ_fit1.760561|<5e-4, fit-rms<1e-5, все sc_*): по ВСЕМ 2049 бинам rms медиана 0.0065 дБ, p90 0.0075, max 0.035 при q=0.80. Инструмент: cascade_sim.py --mask / fir_probe.py.

γ выводится из цепи: γ = 1 + s_F(q), s_F = ∂log|F|/∂log trk в нотче

При q=0.8: s_F=0.7516 ⇒ γ_pred=1.7516 против точного 1.760561 (Δ 0.5%). Остаточная структура та же, что даёт пер-бин модуляцию rms 0.0065 дБ.

ОТКРЫТО (следующий раунд)

  1. Источник q на аргументе EXP: эмпирика 0.785–0.809 по подвыборкам; главный подозреваемый — внутренность 1803831c0 (или xmm10=0.8 @1824c3e28-класс константа вне прослеженного пути). Нужен статический декод ядра (~5700 строк AVX-512+FMA) либо live-захват входа/выхода EXP.
  2. Асинхронность снапшотов (cur может отставать от scr/trk) ограничивает точность пер-кадрового фита — уйдёт с симуляцией детектора (Этап B).
  3. Детекторный каскад lvl_raw→scr (шаги 9–17) не тронут; нужны ACC@7c8 (+ WINfreq@658 для контроля окна) — обновить rendersnap2 SLOTS.

============ 24mm10: ЯДРО EXP ДЕКОДИРОВАНО ПОЛНОСТЬЮ; МАСШТАБЫ ОПОВ ЗАФИКСИРОВАНЫ; ПАРАДОКС q ============

EXP 1803831c0 — полная формула (скалярный путь = векторная математика)

Вход: пары (re,im) плоско; выход in-place. Это ТОЧНАЯ комплексная экспонента:

e^re:  t = fma(re, C1, MAGIC), C1=184.665 (=128·log2e!), MAGIC=12582912
       k = tMAGIC (округление до целого); таблица T @0x1820fcd80,
       запись 8 байт (hi/lo extended double), индекс (t&MASK)<<3
       r_hi = re  k·h,        h=0.00541687 (=ln2/128, f32)
       r    = r_hi + k·1.65777e-06            ; Коди–Уэйт вторая компонента
       p    = r + 0.5·r²
       e^re = T[k].lo + T[k].hi·p (+знаковые фиксы, guard 87.33654=maxarg2ln2)
e^(i·im): |im|→q=round(|im|·(1/π)) через тот же MAGIC; приведение в DOUBLE:
       rπ = |im|  q·π_hi − q·π_lo (двухкомпонентный π); фолд π/2;
       минимакс sin/cos в double {2.60578e-06, 1.98096e-4, 3.166e-05,
       0.01604}; знаки по квадранту (vmovmskps)
out = (e^re·cos(im'), e^re·sin(im'))  — БЕЗ КАКОГО-ЛИБО МАСШТАБА ВНУТРИ.

Следствие: аргумент экспоненты в цепи = ровно то, что даёт fwd-RFFT.

Нормировки опов (пин по дизасму воркеров)

  • FWD(1a0c0): сборка X[Nyq]=A0B0 БЕЗ ×0.5 ⇒ ядро сырое (gain 1 = numpy.rfft); план-масштаб guard [obj+8]: у нас [+8]=0 ⇒ ffe0 НЕ вызывается. ИТОГ s_f=1.
  • INV(4ca80): голова X0/XN бабочка без 0.5, план-масштаб guard [obj+0xc]=1 ⇒ ffe0 ×2^-12 по всему буферу ПОСЛЕ ядра. Ядро сырое (raw IDFT, gain N) ⇒ после ffe0: s_i = 1 (ровно numpy.irfft). ИТОГ s_i=1.
  • Содержимое WINfreq@658 подтверждено по старым дампам (firbufs.npz): периодический Hann(4096), w[1]=5.8827e-07, w[1024]=0.5, w[2047]=0.9999994.

Отвергнуто (численно, на ультрачистых кадрах)

  • Своп направлений (fwd,inv,fwd,inv): rms 82 дБ — исключено.
  • «Найквост не экспоненцируется»: rms 60 дБ — исключено (EXP накрывает все 2049 флоатов включая слот Nyquist.re).
  • Окно hann^p (p=0.5..4) при q=1: s_F∈[0.81..0.97], не достигает 0.76.
  • Перестановка («unordered» layout) для кадров класса post-stage: сортировка модулей не совпадает ни с одной стадией (relres 0.28..0.98) — кадры полиморфны, forensics снапшотов исчерпана.

ПАРАДОКС q (главный остаток)

Все масштабы зафиксированы ⇒ модель обязана быть точной при q=1, однако: q=1 → rms 0.022 дБ; q=0.8 → 0.0065 дБ (медиана, 60 кадров). Более того: наблюдаемый закон cur=trk^γ держится с rms~1e-4 на РАЗНЫХ контентах, а наш сэндвич даёт контент-зависимый наклон s_F (0.82..1.34). ⇒ реальный тракт ведёт себя как ПОТОЧЕЧНАЯ степень (диагональный оператор в частотном домене), наш rfft∘fold∘irfft — нет. Гипотеза: ops A–D суть комплексные FFT размера 2048 (не real-4096!) либо содержат zreorder-слой, и срединный линейный оператор L=rfft∘fold∘irfft в действительности близок к диагональному в частотном базисе (например, при интерпретации буфера как 2048 комплексных отсчётов fold-паттерн становится почти тривиальным).

Пути закрытия (следующий раунд)

  1. Статический декод ядер-близнецов (~3.1k строк AVX каждый) — определить размер/тип преобразования и формат укладки окончательно.
  2. Live: burst-захват rendersnap2 (обновлён, +ACC/WINfreq) с плотным семплированием состояния FIR внутри рендера; сравнить стадии.
  3. Windows/x64dbg-MCP (если доступен хост): брейкпоинт на 52b644..52b893, дамп FIR после каждого из 6 шагов для одного кадра — закрывает всё.

24mm10-бис: итог статического разбора близнецов (раунд «добить q»)

Ядра 181b853e0(INV-core)/181b81b80(FWD-core): 3130 строк почти развёрнутого
AVX2-кода (60 jcc, 4 боевых петли), БЕЗ внутренних вызовов; единственные
float-константы ±0.707107 (+ знак-маска 0x80000000) в собственном статике
@0x186ee7dxx (в дампе есть). Это radix-4/split-radix КОМПЛЕКСНЫЙ FFT
половинного размера (count=N/2=2048 от воркера), специфицированный под
размер (jump-table по log2n в воркере выбирает ядро).
Нормировок внутри НЕТ (ни одной vmulps на константу ≠±1/√2).
INV-воркер добавляет ffe0(2^-12) ([obj+0xc]=1), FWD-воркер НЕ добавляет
([obj+8]=0). Твидлы плана лежат инлайн после заголовка плана (захват buf548:
квады cos(π/8)-класса @f32-индекс 560+, пары sin|cos дальше);
указатели plan[+0x30]/[+0x38]/[+0x50]/[+0x58] — кучные адреса этих таблиц
(вне дампа), разность [+0x38][+0x30]=0x230Б=140 f32.
Инструмент: /tmp/opencode/avx_interp.py (мини-интерпретатор AVX/FMA-
подмножества; баги cmp-as-sub и RIP-rel исправлены; довести до прогона —
упёрлось в управление потоком на таблицах, см. probe2/probe3.py).

ВЫВОД: пара INV/FWD == пара numpy.irfft/rfft (подтверждено трижды). Парадокс q (модель требует аргумент×0.8, все масштабы зафиксированы) ⇒ причина НЕ в нормировках ядер, а в том, ЧТО реально лежит в FIR-буфере в момент γ-кадров: офлайн-гипотезы о стадиях исчерпаны, кадры полиморфны. Необходимо наблюдение ЖИВОГО состояния (варианты 2/3 выше), либо полный декод управления потоком близнеца (петли по стадиям, r13/r14 walk — частично картирован: r13=work, add/sub rbp, add 0x40/0x100).

Скорректированные мелочи dataflow этого раунда

  • Порядок: copy → opA(INV) → FIR[n]=0 → fold×2 → zero[2049..] → opB(FWD) (FIR[n]=0 стоит ПОСЛЕ opA, обнуляет временной отсчёт t[N/2], не вход!)
  • В модели убрать h[-1]=0 перед irfft (Найквост входа НЕ обнулялся).




## ============ 24mm11: LIVE PTRACE-ТРАССИРОВКА WINE-ХОСТА; ЦЕПЬ ДО DF0 БИТ-ТОЧНА; q=1 ============

### Инструмент (прорыв)
scripts/wine_ptrace_trace.py — мини-ptrace отладчик: запускает reaper как
ребёнка (yama=1 не мешает), аттачится ко всем тредам wine-хоста yabridge,
ставит int3 на входах COPY 1800136e0 / EXP 1803831c0 / DF0 18000b3c0 /
DF0RET 52b898, дампит регистры и буферы через /proc/tid/mem между хитами.
Контекст НЕ нужен: всё берётся из регистров хитов; кадры сшиваются
последовательностью COPY→EXP→DF0→DF0RET.

### ФАКТЫ (dual_b1q_0.5.rpp, 400+ хитов)
1. **Вход EXP == rfft(fold(irfft(scr))) при q=1 ТОЧНО**: отношение
   Y_meas/Y_model = 1.0000+0.0000j по всем бинам всех кадров. НИКАКОГО
   скаляра q нет — «q≈0.8» из 24mm9 был артефактом вырожденного фита
   (гладкая модель подгонялась под гладкую кривую).
2. **FIR на входе df0 == полная модель БИТ-В-БИТ**: |ratio|=1.0000,
   phase=0 по всем 2049 бинам; энергия разностного ядра ~1e-15.
   Окно = периодический Hann, падающая половина, всё как в модели.
3. **df0 = complex-mul подтверждён живьём**: Tout==Tin⊗F с relerr≤3.5e-7
   (float32).
4. **НОВОЕ: track_i ([rsp+0x138]-таблица) ≠ exp(scr)!** Tin — комплексная
   кривая, СОСРЕДОТОЧЕННАЯ В НОТЧАХ (топ-бины = нотчи скр), |max|~442,
   наклон log|Tin|/scr ≈ 5.5 ⇒ Tin ≈ trk^5.5; Tout = Tin⊗F ≈ trk^4.54.
5. Слоты ctx через сигнатуру vtable нашли ДРУГОЙ инстанс (GUI-класс:
   слоты содержат 1200/440/25 — частоты/параметры); валидация ctx теперь
   только по инварианту trk==exp(scr) из хита (строгая: finite, |scr|<40).

### СЛЕДСТВИЕ: где рождается γ
Цепь до df0 бит-точна и НЕ содержит γ. Применённая маска cur@678 =
trk^1.760561 образуется ЛИБО самим track_i (выход детекторного каскада
шагов 9–17 — ЭТАП B!), ЛИБО пост-df0 нормализацией потребителем
(FFT-conv движок 22z). Этап B получил точную цель: декодировать путь
lvl_raw → track_i (буфер [rsp+0x138][band]) и пост-обработку до 678.

### Следующие шаги
1. Этап B: каскад lvl_raw→track_i (bandloop_trace, шаги 917, ACC@7c8);
   валидация теперь возможна ЖИВОЙ трассировкой тех же опов (add bps на
   divide 52d650/acc-dc40/att-rel 1fa0/1940).
2. Найти консюмера track/FIR после fn529fe0 (FFT-conv движок) — как
   track_i превращается в применённую маску аудио.
3. C++ порт RT_CASCADE=1 (Этап C) — цепь до df0 уже можно транскрибировать.

## ============ 24mm12: НАЙДЕН ДЕТЕКТОРНЫЙ КАСКАД = СТАДИЯ vt+0x28 = 180529c60; КАРТА VTABLE ПАЙПЛАЙНА ============

### Оркестратор (0x1805300f0..0x1805305e7)
fn529fe0 вызывается ВИРТУАЛЬНО: `call [ctx_vtable+0x30]` (сайт 530371),
аргументы (rcx=ctx, rdx=ТАБЛИЦА TRACK = ctx+0x380, r8d=4096=[ctx+0x1a8],
r9d=nbands=[ctx+0x30]). До него в том же оркестраторе — серия виртуальных
вызовов других стадий. Полоса-цикл после fn: cmp [rsi+0x30],r13;
r15=ctx+0x360, r14=ctx+0x2e0 — ещё таблицы-указатели в малых оффсетах ctx.

### Карта vtable ctx (live, comb_b1234)

+0x08 0x18052cfb0 +0x10 0x180529550 +0x18 0x1804714b0 (чужой модуль?) +0x20 0x18052b940 +0x28 0x180529c60 ← ДЕТЕКТОР +0x30 0x180529fe0 (fn) +0x38 0x180529ef0 (prep) +0x40 0x18052bbf0 +0xe8 0x1804731c0 (чужой модуль?) +0x218 0x180481210

Трасса кадра: [e8,e8]? → 38 → 28(×nbands) → 30(fn). Писец track — ТОЛЬКО
vt+0x28 (430/430 изменений md5).

### 180529c60 — детекторный каскад, ВСЯ функция 0x281 байт

lock bts [ctx+0x2404dc] ; тот же лок что в fn r9 = rdx (СТАРЫЙ track всей таблицы? базовый буфер) r12 = band2; rcx = [ctx + r128 + 0x540678] ; bands_curve полосы n2 = ([ctx+0x64]±)/2+1 call 0x1805355d0(bands, rdx, n2) ; ?? первичное смешение loop по [ctx+0x1b0]: rbp = [ctx+r12*8+0x540678] call 0x180530080(rbp, rbp+4, n2-1) ; ?? call 0x18052d920(rbp, xmm1=0.5f, n2-1) ; масштаб ×0.5 ! r15 = [ctx+0x5406f8] ; vec6f8 call 0x1800020f0 / 0x180001850(rsi=rbp+4, rdx=rbp, r8=r15, r9=n2-1) call 0x180001a00 / ...(rcx=r15, rdx=rsi, xmm=0.5f/0.5d)

То есть «шаги 9–17» из BLOCKMAP 24mm5 на самом деле живут ЗДЕСЬ (+хелперы),
а НЕ в fn529fe0: fn529fe0 получает ГОТОВЫЕ track-буферы (arg2) и строит
из них ядро (df0: T⊗F), не вычисляя детектор!

### Статус Этапа B
Осталось декодировать: хелперы 5355d0 / 530080 / 20f0 / 1850 / 1a00 /
52d920-семантику и роль vec6f8@6f8 — десятки инструкций, вся рекуррентия
track_{t+1} замкнётся офлайн. Затем γ=1.760561 выводится аналитически.

### Инструменты раунда
scripts/wine_stage_trace.py (vtable-stage трассировщик c md5-атрибуцией
записей), scripts/wine_ptrace_trace.py (+TRACKSAVE/DIV/DC40/EXPVAR/FN,
mapped-фильтр, строгая валидация ctx по trk==exp(scr)).
Грабли: адреса-константы в патчах скрипта молча не применялись при чужом
отступе — проверять installed-list; DC40=0x1800dc40 (не 0x18000dc40);
DIV/DC40/EXPVAR/FN могут быть вне маппинга процесса (пропускать).

## ============ 24mm13: ХЕЛПЕРЫ КАСКАДА 529c60 ДЕКОДИРОВАНЫ (статика) ============

Резолв ILT-цепочек (movsxd rax,[1826159a0]=4; lea r10,tbl; jmp [r10+rax*8]):

5355d0.f → 18e0(ILT) → 0x1800032c0 → call 0x180016140(a,b,n2) [векторная, 5-й арг из стека — MXCSR-сохраняющая, тело не дочитано] 530080.f → 2090(ILT) → 0x180010e40: b[i] += a[i] IN-PLACE (vaddss; a=rcx, b=rdx, store в rdx!) 20f0.f → 0x180011580: dst[i] = a[i] + b[i] (vaddss, dst=r8) 1850.d → 0x1800025e0: то же в double 1a00.f → 0x180004720: dst[i] = xmm1 · src[i]; skip при xmm1∈{0,1} 52d920 : dst[i] *= xmm1 (in-place, skip при 1/0 — как ffe0)

Грабли раунда: адреса теряли ноль при ручном наборе (0x180018e0 vs
0x1800018e0) И интермиттент пустые чтения soothe_mem.bin (лечится ретраем).

### Рекуррентия каскада на полосу (порядок вызовов из 529c60):

A: 16140(bands_curve@678, T_old, n2) ; до цикла, семантика ??? цикл по [ctx+0x1b0]: a: bands[1+j] += bands[j] ; j=0..n2-2 (префикс!) b: bands[j] *= 0.5 ; j=0..n2-2 c: vec6f8[j] = bands[1+j] + bands[j] ; (20f0, dst=r8=6f8) d: bands[1+j] = 0.5 · vec6f8[j] ; (1a00, xmm1=0.5f/d) → результат пишется в track-буфер полосы (ctx+0x380 таблица)

Замечание: префикс-аккумуляция (a) + деление пополам (b) + попарное
усреднение (c,d) — это вычисление ПОЛУСУММ смежных бинов = построение
иерархического сглаживания (wavelet/Haar-класс!) поверх спектра.
Tin на захватах ≈ trk^5.5 в нотчах — согласуется с накоплением за много
кадров такого экспоненциального смешения.

### Следующий шаг (финал Этапа B)
1. Дочитать 0x180016140 (оп A до цикла — вероятно T_new = α·T_old + β·bands).
2. Собрать рекуррентию в numpy, прогнать по 400 живым кадрам
   (winetrace_casc/chain_samples.pkl: scr→Tin покадрово), подобрать
   единственные константы из асма (не фитом!), проверить выход == Tin.
3. γ=1.760561 затем выводится из замкнутой рекуррентии аналитически.

### 24mm13-доп: оп A (0x180016140) — начало декодировано
Первый внутренний цикл считает ЭНЕРГИЮ КОМПЛЕКСНЫХ ПАР bands-кривой:

for i: E[i] = fma(re,re, im*im), где re=bands[2i], im=bands[2i+1] (denormals→0; MXCSR сохраняется/восстанавливается)

далее в теле — смешение с T_old (константы 0.5/0.5 broad @181c5ce60).
⇒ track_i = рекурсивно сглаженная ЭНЕРГИЯ спектра (не амплитуда!) —
это объясняет и масштабы (~trk^5.5 после логов), и нотч-концентрацию.
Осталось дочитать ~100 инструкций хвоста 16140 (формула смешения с T_old)
— рекуррентия замкнётся полностью, γ выводится аналитически.

### 24mm13-доп2: численная проверка рекуррентии — расхождение, нужен пер-стадийный дамп
Симуляция «магнитуды пар → track» НЕ совпадает с захваченным Tin
(Tin пикируется в нотчах со значениями ~442, магнитуды там ~0.3).
Гипотеза на проверку: между op-A и df0 есть недоучтённый этап, ЛИБО
вход каскада — другая кривая (не exp(scr), т.к. scr снят ПОСЛЕ модификаций).
Решение с гарантией: добавить в tracer брейкпоинты вход/выход 529c60 и
вход/выход 16140 — точные состояния bands/track до и после каждого блока.
(Инфраструктура готова, адреса известны; следующий раунд.)

### 24mm13-доп3: пер-стадийные дампы живьём — op A подтверждён, вход каскада ≠ exp(scr)
Трассировщик получил брейкпоинты CIN/COUT (вход/выход 529c60) и
AIN/AOUT (вход/выход 16140, возврат 332c). Живые факты (comb_b1234):

AIN: a(rcx)=кривая состояния, ЗНАКОВАЯ, |max|=57.6 (НЕ exp(scr)!) b(rdx)=единичный буфер (init 1.0) AOUT: a — без изменений (16140 вход не трогает) b[i] = |z_i| ТОЧНО (пары a[2i],a[2i+1]) — магнитуды подтверждены CIN/COUT: track между входом и выходом каскада меняется предсказуемо.

⇒ Вход детектора — НАКОПЛЕННОЕ СОСТОЯНИЕ (знаковая кривая с амплитудами
до десятков), а не текущий спектр. Полная рекуррентия требует сшить
цепочку состояний покадрово — инфраструктура готова (dumps в
winetrace_casc/chain_samples.pkl, kind∈{CIN,COUT,AIN,AOUT,COPY,EXP,DF0}).

### 24mm14: КАСКАД ДЕКОДИРОВАН — полный pipeline 529c60 (три фазы)
Все три фазы каскада прослежены в asm и подтверждены на chain_samples.pkl:

**Фаза 1 — магнитуды (16140, НЕ |z|²!)**
- Ключевое исправление: AOUT.b[i] = |z_i| (макс. отклонение 5.4e-6 от np.sqrt)
- Инструкция: vsqrtps (не vmultps) — магнитуда, НЕ квадрат
- Выход: bands_curve[i] = sqrt(re² + im²), интерлив=re,im из complex state

**Фаза 2 — Хаар-сглаживание (529c60, строки 35-74)**
- Ядро [0.25, 0.5, 0.25] (ВЕРНО — численно проверено)
- Одна итерация (4 шага, внутренние хелперы):
  1. b[i] += b[i+1]   (10e40, prefix sum)
  2. b[i] *= 0.5      (ffe0, scalar mul)
  3. scratch[i] = b[i+1] + b[i]  (11580, 3-operand add)
  4. b[i+1] = 0.5 * scratch[i]   (4720, scalar mul+store)
- ctx[0x1b0] итераций; best-fit = 2 (rms=0.30 vs 1.09 при 5)

**Фаза 3 — постобработка и blend (строки 74-123)**
- peak = max(curve) [4d56b0, horizontal max]
- sin_peak = sin(ctx[0x54087c]*30  90) * 0.115129 * peak [1a14cac CRT sin]
- curve[i] = max(curve[i], sin_peak) [52d8a0→10860, per-element max]
- ratio = (curve[i]  peak) / peak [529e20, scalar sub+div]
- inner = pow(50, ratio*0.001) * ratio*0.001 [1a14cd6 CRT log, pow, mul]
- w = 1/inner [529e5a, scalar div]
- log_w = log_0.1(w) [529e8e,CRT log] — но откуда ctx[0x24]?
- 5407a8[i] *= w [52d920, array scalar mul]
- 5407a8[i] += curve[i] * (1-w) [52dae0→f620, FMA]
- memcpy 5407a8 → 540678 [52dbc0→6840]

**Валидация (2 кадра, chain_samples.pkl):**
- iters=2: w=0.015, rms=0.30, corr=0.998 (лучший)
- iters=1: rms=0.59; iters=3: rms=0.67; iters=5: rms=1.42
- Per-bin w: 0.0840.100 (std=0.005) — ошибка Хаара, НЕ(ctx param)
- Кадр 1 (silence): COUT = предыдущий кадр (каскад stateful, trk=0 → skip)

**Неизвестные ctx-поля (требуют live-захвата):**
- ctx[0x1b0] — число итераций Хаара (best-fit=2)
- ctx[0x54087c] — параметр sin modulation (sin_peak)
- ctx[0x24], ctx[0x1a0], ctx[0x1ac] — параметры ratio/w
- ctx[0x54087c] — пер-биновый sin_peakclamp
- 5407a8 — accumulator (zero в стационаре, НО хранит state между кадрами)

**Ключевые коррекции (НЕ полагаться на старые значения):**
- Phase 1 = |z| (НЕ |z|²) — AOUT.b подтверждает
- Haar iters = 2 ( best-fit, НЕ 5)
- w ≈ 0.015 (scalar, НЕ 0.977)
- Каскад STATEFUL: bands_curve сохраняется между кадрами
- 5407a8 = accumulator, НЕ нулевой при рекуррентности