Files
Matiq 627c35dd53 AGENTS.md: document new env flags (RT_CASC/IIR4/KMAP/DELTA), chain wired status, capture proof
- Add RT_CASC, RT_IIR4_GEN, RT_IIR4_C/TAU/P/MULT/SR, RT_FIR, RT_FIR_Q,
  RT_KMAP_FC, RT_DELTA_DIST, RT_DELTA_STATE, RT_DBG_CASC to env flags table
- Update chain_9_19 section: WIRED+GATED (was CRITICAL)
- Add capture proof section: rendersnap2.py + /tmp/opencode/ datasets
- Remove outdated PTRACE live-dump hazards (superseded by /proc/pid/mem capture)
2026-09-03 14:11:19 +03:00

134 lines
9.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AGENTS.md — runbook for AI agents working in this repo
> **Статус → `README.md:13` (единственный источник TOTAL).** Этот файл — только runbook: сборка, метрика, env-флаги, tooling hazard.
> Полный журнал — `handoff/NOTES_LEVEL_INDEX.md` → `handoff/NOTES_LEVEL.md` (живая голова) + `handoff/archive/`.
> Карта метода — `handoff/BLOCKMAP_529fe0.md`. ЭТОТ ФАЙЛ ЧИТАЙ ПЕРВЫМ.
## Золотое правило (обязательно)
1. **Цель — bit-exact реверс кода**, НЕ эмпирическая подгонка кривых. Каждый параметр
должен иметь источник (decomp адрес / live-таблица), а не быть подогнанным числом.
Если берёшь эмпирику — явно пометь и занеси в «осталось».
2. Источник истины — **декомпиляция** (`decomp_funs.txt`, `decomp_funs2.txt`,
`handoff/nls_dasm/*.dis`) и **live-снимки** (`/tmp/snap_rt.bin`). Обновлять заметки
при любом новом декоде.
3. Команды через `rtk` (токен-фильтр), включая цепочки `&&`.
## Сборка и тесты (канон)
```bash
# собрать библиотеку + framed_test (bridge, 44.1k) + render48k (структурная цепь, 48k/4096)
cmake -S dsp -B dsp/build
cmake --build dsp/build --target framed_test render48k
# bridge-рендер (N=2048, hop=512, SR 44100, sqrt-Hann OLA)
# формат полосы: fc,q,sens,level_scale (одна полоса в comma-форме)
./dsp/build/framed_test /home/m/soothe-bt/tone1kq.wav /tmp/o.wav 678.7611083984375,0.99999785,12,600
# многополосный: через отдельные аргументы fc q sens scale (см. framed_test.cpp)
# структурный рендер (внутренняя сетка 48000/4096: resample -> FUN_180529fe0 chain -> resample)
./dsp/build/render48k /home/m/soothe-bt/tone1kq.wav /tmp/o48.wav 1000,0.99999785,12
# корпусные прогонки (62 случая, честная 24-bit метрика)
python3 scripts/corpus.py # bridge + guard --compare
python3 scripts/corpus_structural.py # структурная цепь
python3 scripts/corpus_structural.py --vs-bridge scripts/baseline_bridge.json
# отдельные модули (bit-exact черные проверки)
cmake --build dsp/build --target twin_check tables_check fftconv_check vlog_check leveltrack_check levelpath_check fn529fe0_check exp2_check vlaw_check
./dsp/build/twin_check # float-parity twin-резонатора
```
> **TOOLING HAZARD**: cmake пропускает пересборку при изменении исходника в ту же секунду —
> параметрические свипы молча гоняют STALE бинарь. Протокол: `touch` исходника перед сборкой +
> проверять свежесть mtime бинаря (пример: /tmp/sweep_fresh.py паттерн в NOTES_LEVEL:21a).
### Метрика (tone-cmp, Goertzel stead-state)
Сравнивать **тримкнутый** выход (длина = длина входа) с референсом `*_ref.wav` / `t1kq_b1f_*`:
```python
# ref: t1kq_b1f_678.7611083984375.wav (или t1kq_b1f_1000.wav и т.д. по fc полосы)
# вход: tone1kq.wav (тон 1000 Гц)
import wave, numpy as np
def load(p):
w=wave.open(p,'rb'); n=w.getnframes(); d=w.readframes(n)
return np.frombuffer(d,dtype=np.int16).astype(np.float64).reshape(-1,w.getnchannels()).mean(1)/32768
def ta(x,f,sr=44100):
x=x[-int(0.75*sr):]; t=np.arange(len(x))/sr; w=2*np.pi*f
return np.hypot(2*np.sum(x*np.cos(w*t))/len(x), 2*np.sum(x*np.sin(w*t))/len(x))
def db(a): return 20*np.log10(max(a,1e-9))
inp=load('/home/m/soothe-bt/tone1kq.wav')
out=load('/tmp/o.wav')
ref=load('/home/m/soothe-bt/t1kq_b1f_678.7611083984375.wav') # fc полосы = 678.76
err = db(ta(out,1000)/ta(ref,1000)) # err в dB, цель <0.1
```
Тестовый корпус (`/home/m/soothe-bt/`, вне git): `tone1kq.wav`(вход),
`t1kq_b1f_<fc>.wav` (рефы), `comb.wav`/`comb_ref.wav` (мультиполосный).
## Структура ключевых файлов
- `dsp/framed_model.{cpp,hpp}` — C++ порт mask-apply цепи (ГЛАВНЫЙ файл).
- `dsp/render48k.cpp` — пайплайн 48000/4096 (resample → chain → resample).
- `dsp/twin.{cpp,hpp}` — twin FUN_180535880 (float-parity).
- `scripts/corpus.py` / `corpus_structural.py` — харнессы + guard `--compare`.
- `handoff/NOTES_LEVEL.md` — живой журнал (голова 24mm5+, хвост → `archive/`).
- `handoff/NOTES_LEVEL_INDEX.md` — оглавление журнала.
- `handoff/BLOCKMAP_529fe0.md` — блок-карта FUN_180529fe0.
- `handoff/nls_dasm/` — 134 дизассембла.
## Env-флаги экспериментов (актуальные)
| флаг | действие |
|------|----------|
| `RT_VLAW=1` | закон применённой стадии: `mask=10^((α·ln1p(lvl/β)+c)/20)` |
| `RT_SYN=1` | STFT БЕЗ синтез-окна (найденный слой плагина) |
| `RT_WIN=0/1/2` | окно анализа: sym-hann / periodic / rect |
| `RT_NOWARP=1` | отключить warp-модуляцию маски |
| `RT_NOIIR3=1` | отключить IIR3 ×2 |
| `RT_IIR12=0` | отключить частотные IIR1/2 (КРИТИЧНО с RT_VLAW — иначе размывают дипы) |
| `RT_DUMP_BIN=<f>` (+`RT_DUMP_FRAME=N`) | дамп тракта бина N: am/res/lvl_raw/band_level/prewarp/w |
| `RT_VDBG=1` | stderr-печать vlaw-вычислений |
| `RT_FAITHFUL=1` | faithful-цепь `dsp/fnfaith.cpp` (детекторный каскад) |
| `RT_FIRCONV=1/3` | FIR-применение (1=complex-mul, 3=`1.019·mask^1.8345`) |
| `RT_CASC=1` | цепь 919 (`chain_9_19`, IIR4×2 double + FIR min-phase, gated) |
| `RT_IIR4_GEN=1` | генератор IIR4 (FUN_180533340) vs proxy `kIIR_A1/B1` |
| `RT_IIR4_C/TAU/P/MULT/SR` | параметры генератора IIR4 (1000/1200/0.5/360/48000) |
| `RT_FIR=0/1` | пуск FIR min-phase (default 1) |
| `RT_FIR_Q=x` | показатель FIR (default 0.8002203702926636, live `.rdata`) |
| `RT_KMAP_FC=1` | fc-фактор k-mapping через W_eq (default off) |
| `RT_DELTA_DIST=x` | Δ distance factor (template-local gain, default 0=flat) |
| `RT_DELTA_STATE=1` | STATE-dependent Δ (опен-ин, wired, empty) |
| `RT_DBG_CASC=1` | gate DBG_CASC fprintf (per-frame spam otherwise) |
Полный набор dual-решения: `RT_VLAW=1 RT_SYN=1 RT_NOWARP=1 RT_NOIIR3=1 RT_IIR12=0`.
## Инструменты
| скрипт | назначение |
|--------|-----------|
| `scripts/rendersnap2.py <rpp> [cap] [outdir]` | мягкий STOP-снаппер (RENDER_FILE из rpp!) |
| `scripts/campaign.py <base> <fc> <q> <sens> <in> <drives> <out>` | ячейка параметризации (~8 мин) |
| `scripts/disasm_func.py <VA> [len]` | capstone-дизасм с RIP-константами |
| `scripts/iat_name.py` | рантайм-резолв импортов (SIGSTOP!) |
| `scripts/probe_states.py` / `probe_mem.py` / `dump_dispatch.py` | live state/память/таблицы |
| `scripts/hunt2.py` | перебор ctx-инстансов |
| `scripts/scan_pairs.py`, `scan_lutsub.py` | диагностика памяти |
Датасеты: `/tmp/opencode/sc_{q,sens,qmap,k,f,d}*` + `tract_*` + `*.pkl/.npz` (см. `NOTES_LEVEL_INDEX.md`).
Открытые пробелы → `BITEXACT_PLAN.md`.
## Архитектурная проблема chain_9_19 (WIRED, GATED)
`chain_9_19` из `dsp/fn52fe0.cpp:259` (BLOCKMAP:620-644) — per-frame цепь с **persistent ACC state** (`@ctx+0x5407c8`). Интегрирована в `framed_model.cpp:process_band_structural` через `RT_CASC=1`. IIR4×2 использует double precision (movsd/mulsd per disasm 1191), FIR min-phase бит-точен до df0 (0.0065 dB). Генератор IIR4 (`generate_iir4_coefs`, FUN_180533340) env-gated `RT_IIR4_GEN`.
**Статус:** chain wired и gated (`RT_CASC=0` default = canon untouched). Все unit checks PASS, corpus gate d=+0.000. Калибровка I/O format требует `ph*.npz` capture (rendersnap2.py) — capture proof получен (2026-09-02).
**Live-dump chain (ptrace):** chain вызывается в рантайме (DIV#0-7 на `0x1803a06a0`):
- Input: `a` = bands_curve (VLAW output, min=0, max=17.6, mean=0.048)
- `b` = tmp6f8 (step 9b accumulation, min=0, max=0.8, mean=0.8)
- 8 DIV hits на одном кадре (dual-band: 2 bands × 4 iterations?)
**Capture proof (2026-09-02):** `rendersnap2.py` снимает `ph*.npz` (слоты 0x540628/0x540678/0x540688/0x540768) через `/proc/pid/mem` без ptrace-брейкпоинтов. Данные в `/tmp/opencode/{rendersnap2_dual,snap_t1k_b1f_1000,snap_dual300,rendersnap2_comb_b1234}`. Маск-цепь работает в рендер-окне (BLOCKMAP:285 устарел).
---
## Чистая работа
- Не коммитить: `*.bin`, `*.wav/rpp`, `*.log`, `dsp/build/`, `ghidra-proj/`, `dl/lib/bin/include/`, `regions*/`. См. `.gitignore`.
- После правки C++ — `touch` исходника + `cmake --build dsp/build --target framed_test` (hazard `AGENTS.md:66`) + `python3 scripts/corpus.py --compare scripts/baseline_bridge.json --tol 0.25`.