Problem
renderLayeredF0() remains a large imperative renderer in src/track-assembler.ts. Some constants have been moved to config, but the primary F0 rendering algorithm still mixes signal-processing loops and FE orchestration in TypeScript.
Evidence
src/track-assembler.ts exports renderLayeredF0().
- The same file still contains layered-F0 filtering, impulse/profile rendering, and event interpolation logic.
src/track-assembler.ts still has fallback defaults such as LAYERED_F0_MIN_HZ_DEFAULT = 50 and uses modelConfig.output_clamp?.min_hz ?? LAYERED_F0_MIN_HZ_DEFAULT.
Acceptance criteria
- Decide and implement the owned target boundary: either move the DSP renderer into a proper runtime primitive/WASM-backed module, or split the policy/config and imperative DSP so track assembly only orchestrates declarative commands.
- No unconfigured F0 clamp defaults remain in
track-assembler.ts; defaults come from speaker/profile/model config and are validated.
- Add tests covering the chosen boundary and preserving current rendered contour behavior.
npm.cmd run typecheck:core passes.
Problem
renderLayeredF0()remains a large imperative renderer insrc/track-assembler.ts. Some constants have been moved to config, but the primary F0 rendering algorithm still mixes signal-processing loops and FE orchestration in TypeScript.Evidence
src/track-assembler.tsexportsrenderLayeredF0().src/track-assembler.tsstill has fallback defaults such asLAYERED_F0_MIN_HZ_DEFAULT = 50and usesmodelConfig.output_clamp?.min_hz ?? LAYERED_F0_MIN_HZ_DEFAULT.Acceptance criteria
track-assembler.ts; defaults come from speaker/profile/model config and are validated.npm.cmd run typecheck:corepasses.