Skip to content

Enable web-based LoRA/full-model training with live output - #1

Open
KhryptorGraphics wants to merge 72 commits into
mainfrom
svc-fork-integration
Open

Enable web-based LoRA/full-model training with live output#1
KhryptorGraphics wants to merge 72 commits into
mainfrom
svc-fork-integration

Conversation

@KhryptorGraphics

Copy link
Copy Markdown
Owner

Summary

  • Backend training API now accepts selectable training_mode (lora | full) and architecture (como | diffusion_mel | mel_gan | svc_fork).
  • Full-model training can be started before the 30-minute clean-vocal threshold via an explicit force: true override.
  • TrainingJobManager._save_trained_adapter() now returns/persists adapter_model / serving_model_path, and _update_profile_training_state() prefers the self-contained serving artifact over the deltas-only adapter file.
  • New GET /api/v1/training/jobs/<job_id>/logs?offset=N endpoint backed by TrainingJobManager.append_job_log() / get_job_logs().
  • Frontend: TrainingConfigPanel exposes LoRA vs Full-model mode and the CoMoSVC architecture; ConversionWorkflowPage sends force: true for early full-model starts and surfaces returned warnings; LiveTrainingMonitor polls the new logs endpoint and renders a live output panel.
  • Playwright mocks/smoke spec updated for LoRA/full mode, force, logs polling, and live monitor behavior.

Verification

  • python -m py_compile src/auto_voice/web/api_training.py src/auto_voice/training/job_manager.py src/auto_voice/cli.py — clean.
  • pytest -q tests/test_training_ui_routes.py — 9 passed (4 new: config-options architecture, unknown-QA warning path, force-override full training, job logs buffering).
  • cd frontend && npm run build — clean production build.
  • cd frontend && npm run test:e2e -- training-ui.smoke.spec.ts — 3 passed.
  • Manual API smoke against a live in-process server: POST /training/jobs (lora, force=true) -> 201; GET .../logs -> real buffered lines; POST .../cancel -> 200.
  • GitNexus change-impact check on the 10 changed files: risk score 0.00, 0 test gaps (native detect_changes timed out on this box; code-review-graph equivalent used as the scoped fallback).

Commits

  • 3564457c Enable web training mode selection
  • 331b1027 Refresh agent helper metadata (unrelated .claude/helpers/* + agentdb.rvf* refresh, split out per session notes)

kp added 4 commits July 6, 2026 11:04
… local artifacts

- analyze_spectrum(.py/2.py): spectral comparison diagnostics used to chase
  the fast-note-change 'autotune' artifact and detection-percentage tuning
- create_svcfork_checkpoint.py: build svc-fork checkpoint metadata
- update_connor_profile.py: profile json updater for the Conor voice
- .gitignore: keep local debug launchers (inline flask secret), ruvector.db,
  .codegraph/, playwright live reports, and .claude/settings.local.json out
  of the repo
54 agent definitions, command templates, and hook helpers referenced by
CLAUDE.md so the tooling setup is reproducible across checkouts.
Machine-local settings (.claude/settings.local.json) stay untracked.
@cr-gpt

cr-gpt Bot commented Jul 12, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

@greptile-apps

greptile-apps Bot commented Jul 12, 2026

Copy link
Copy Markdown

Too many files changed for review. (320 files found, 100 file limit)

Bypass the limit by tagging @greptile-apps to review.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, we are unable to review this pull request

The GitHub API does not allow us to fetch diffs exceeding 20000 lines

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

kp added 2 commits July 12, 2026 18:23
…c device; add local-audio ingestion + V100 launchers

- trainer: DataLoader uses spawn context (16 workers) to avoid fork+CUDA
  deadlock after GPU ContentVec precompute; warmup scales from immutable
  scheduler base_lrs (was get_last_lr(), which compounds ExponentialLR and
  collapsed lr to ~0 on small datasets)
- encoder: ContentVecEncoder.encode aligns the HF model to the input device
  (latent CPU/CUDA mismatch surfaced by multi-sample on-the-fly extraction)
- scripts/ingest_local_audio_profile.py: reusable video/audio -> profile
  ingestion via pretrained htdemucs_ft, optional --slice-seconds clipping
- scripts/serve_local_threading.py: threading-mode server (no eventlet)
- scripts/start_v100.sh: V100 launcher, UUID GPU pin + sm70 assertion
@cr-gpt

cr-gpt Bot commented Jul 12, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

- serialize concurrent log fetches (in-flight guard) so the immediate
  poll + interval + React StrictMode double-invoke can't all fetch at
  offset 0 and append the first lines twice
- discard a log response whose jobId switched mid-flight (cancel -> start
  new run) so the old job's lines don't append into the new job's log
@cr-gpt

cr-gpt Bot commented Jul 12, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…f16 gate

- voice_profiles.list_training_samples re-anchors stored absolute sample
  paths to the store's actual location, so profiles survive data-dir
  relocation / cross-machine sync (AV-ksek)
- VocalSeparator.separate clamps a too-large segment to the model's max
  (min across sub-models for htdemucs_ft), preventing the >7.8s htdemucs
  reshape crash for every caller; api_profiles no longer passes 10.0 (AV-e4p7)
- trainer.resolve_precision downgrades bf16 -> fp16 on pre-Ampere GPUs
  (capability < sm80, e.g. V100 sm70), fail-safe on unknown capability (AV-ua0w)
- add tests/test_bugfix_paths_segment_precision.py
@cr-gpt

cr-gpt Bot commented Jul 12, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

ConversionHistoryPage crashed with 'Cannot read properties of null (reading toFixed)'
when a conversion record had rtf/processing_time_seconds === null (the !== undefined
guard let null through). Guard with typeof === 'number' so the history page renders
records missing those metrics.
@cr-gpt

cr-gpt Bot commented Jul 13, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

@cr-gpt

cr-gpt Bot commented Jul 13, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…training UI

Fixes crash 'Cannot read properties of undefined (reading toFixed)' on
checkpoint.final_loss (LoRA-only checkpoints omit web metrics). Swept the same
class on the training/profile/history path: TrainingJobQueue (null-passing
!== undefined guard), GPUMonitor, VoiceProfilePage/ConversionWorkflowPage sample
durations, and QualityMetricsPanel gauges. QualityMetrics leaves the async
metrics path (get_job_metrics -> _calculate_metrics) omits — mean_error_cents,
embedding_distance, spectral_distortion — marked optional; GaugeProps.value
widened + NaN bar-width clamped.
@cr-gpt

cr-gpt Bot commented Jul 13, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…); file 3 follow-ups (api.ts split, ConversionHistoryPage guard, fp32 mem watch)
@cr-gpt

cr-gpt Bot commented Jul 13, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…al-decoder <-> svc-fork-integration divergence)
@cr-gpt

cr-gpt Bot commented Jul 13, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…d, fp32 mem); record AV-owvr divergence assessment
@cr-gpt

cr-gpt Bot commented Jul 14, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…n unique commits cherry-picked into hq-lora-universal-decoder)
@cr-gpt

cr-gpt Bot commented Jul 14, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

autovoice.gigaghost.com (single 'a') is a different, uncontrolled domain
parked on GoDaddy's aftermarket nameservers (ns1/ns2.namefind.com), which
is why every path there serves GoDaddy's generic /lander sales page. The
real, working, correctly-configured production hostnames are
autovoice.giggahost.com and autovoice.giggadev.com (double 'g'), already
served by the enabled Apache vhost with a working SPA fallback and API
proxy. No code or server config change was needed; this note documents
the root cause to prevent recurrence.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…cipe, not the data

Ran the control that the six new-data runs all missed: continue training from v3 ep135
on EXACTLY the corpus v3 ep135 was already trained on (corpus_v3, 79 files, verified
zero new material), same recipe, 5000 steps. It degraded on its own - 6-8k -13.2 to
-15.5, fmax 17.9k to 14.6k (a LARGER bandwidth loss than st4's), identity 0.929 to
0.921.

So ~half of st4's 6-8k deficit is reproduced with no new data at all, and the seed's
bandwidth isn't even preserved by training on its own data. The dominant cause is
continuing to train from this converged seed at this recipe, not the new material -
which was the previous conclusion's attribution and was wrong. New data is a real but
secondary penalty (st4 -17.7 vs ctl -15.5).

Also explains why more steps never helped (st2/st2b): more steps = more damage.

Records two mechanism candidates: LR too high for fine-tuning a converged checkpoint
(and notes warmup_epochs/init_lr_ratio are vestigial - this fork's train.py never
reads them, so a lower flat LR is the implementable test), and c_mel=45 dominating a
loss whose mel scale barely resolves 6-8k, leaving that band to the discriminator.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…e buzz metric

Single-variable rerun of the control corpus at LR 2e-5 instead of 1e-4. Verified the
arm took effect by reading the runtime optimizer state out of the checkpoint
(param_groups[0].lr = 1.9967e-05, i.e. 2e-5 decayed by ExponentialLR over 490 steps),
not just the config value.

Results vs the LR 1e-4 control: 6-8k -15.5 to -14.0 (regains 1.5 of the 2.3 dB lost),
8-12k -34.8 to -32.4 (back to the seed's -32.2), and both aperiodicity bands fully
recovered - 2-6k at 0.675 actually exceeds the seed's 0.664. Aperiodicity is the buzz
metric this line of work started from, so the buzz was substantially self-inflicted by
the fine-tuning LR.

fmax (15.0k vs seed 17.9k) and identity (0.922 vs 0.929) do NOT recover with LR alone -
a separate mechanism, with the mel-loss HF-blindness candidate still untested.

Consequence: all six new-data runs were handicapped by a recipe that damaged the model
independent of data, so their ~2.2 dB 'data penalty' is not a valid estimate. The new
material needs re-testing at 2e-5 before being written off.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…ubles

Ran st4's corpus at LR 2e-5 (same 5000-step/100-epoch horizon as st4, so LR is the only
difference from st4 and data the only difference from the no-data run):

  data penalty at 1e-4: -15.5 -> -17.7 = 2.2 dB
  data penalty at 2e-5: -14.0 -> -18.2 = 4.2 dB

The penalty nearly doubles once the recipe is fixed - the broken LR was masking part of
it. st4lr's 6-12k aperiodicity (0.753) is the worst value in the table. So the earlier
'this material hurts' conclusion was right in direction and understated in magnitude;
this re-test closes that question rather than reopening it, and corrects the prior
commit's 'deserves re-testing' framing.

The one thing new data buys and LR cannot: fmax 17.9k, matching the seed, where both
no-data runs top out at 14.6-15.0k. LR governs brightness/aperiodicity, added full-band
data governs the bandwidth ceiling - different axes, which is why no single-lever run
beats the seed on everything at once.

Best overall is still the seed (v3 ep135). Closest challenger is lowlr (LR 2e-5, no new
data). AV-6sxy updated with both findings and ranked next levers.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

… on different axes

Replaces the three sections that the 2x2 contradicted (in place, not by append, so no
stale conclusion sits above its correction):

- 'LR was the cause - confirmed' retitled and scoped: the LR effect is real but exists
  ONLY in the zero-fresh-data condition. With new data present, 6-8k is data-driven and
  LR-insensitive (st4 -17.7 @1e-4 vs st4lr -18.2 @2e-5; 8-12k identical both ways).
  A future session must not fine-tune new material at 2e-5 expecting brightness to hold.
- 'recipe is the dominant cause, data secondary' corrected to co-equal: 2.3 dB recipe
  vs 2.2 dB data is a dead heat for the best run, and data dominates outright for the
  rest (deltas from ctl: 1.7/1.8/3.0/6.0/7.8 dB). Also: the effects do NOT decompose -
  an additive model predicts st4lr at -16.2, it measured -18.2.
- 'mel-loss HF blindness / MRD is the fmax suspect' REFUTED by measurement: c_mel=45
  and the discriminator are identical in all four cells, so neither can produce a
  corpus-conditional split. Also refuted: corpus bandwidth (corpus_v3 measured directly
  is full-band - speech median 22.1 kHz over 69 files - yet yields the LOWEST ceiling,
  14.6k) and added-file bandwidth (st6's full-band file gave 14.9k while st4's five
  band-limited files gave 17.9k - anti-correlated). What fmax tracks is fresh-data
  VOLUME, monotonically: 0 new -> 14.6-15.0k, 1 file -> 14.9k, 6 files x1 -> 17.9k,
  6 files x3 -> 22.1k, with steps substituting for volume within a fixed corpus.
- 'more steps means more damage' corrected: the 6-8k loss is incurred early and then
  plateaus (st2->st2b at 5x steps left it flat).

Also added: the noise-floor/clip-dependence/selection-regression caveats (everything
is n=1 on one 20s clip), the local-only warning for the gitignored candidate dir,
the G+D pair requirement (train.py silently random-inits from a G-only dir), and the
full corrected table. AV-6sxy updated to match, with revised next levers - the prior
lever list proposed a b4_6-only run that had already been run as st6 and failed.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…r Brandy 2x2 follow-up

- A1: all 11 ctl intermediates scored on hero20 — oscillation (-13.3..-16.8), no early
  shock, no drift; adjacent-epoch swing up to 3.2 dB (mean 1.4)
- A2: 8 lowlr intermediates — same oscillation 3x tighter (<=1.1 dB, mean 0.7)
- Noise floor: deltas <~1.5 dB between single checkpoints are noise at either LR;
  the 2x2's 1.5 dB LR delta is endpoint luck (trajectory means 0.4 dB apart)
- A3: 15 renders, 5 arms x 3 fresh clips — ctl<lowlr<seed direction holds everywhere
  but all deltas inside noise; fresh-data cost is clip-dependent (0 to 7 dB);
  fmax does not replicate as checkpoint property across clips (clip-controlled)
- warmup lever closed: trigger failed (no front-loaded loss to absorb)
- AV-6sxy updated with measured noise floor and replication outcome
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…veraging results

- Phase C (st2f): 79 originals + 2 sing_b4 files, LR 2e-5, 5000 steps — hero20 fmax
  14.6k lands in the no-data cluster; 2 files do NOT hold the ceiling; boundary is
  between 2 and 6 files. Dilute fresh signal also costs MORE brightness (-19.8 vs
  st4lr's -18.2)
- Phase D: ctl_avg3/avg5 within 0.1-0.9 dB of plain G_143 on all 4 clips — averaging
  is a no-op; oscillation is not noise around a good solution
- Candidate dirs updated: st2f_2file/, render-only ctl_avg{3,5}
- AV-6sxy closed: all four follow-up levers (noise floor, warmup, replication,
  boundary, averaging) resolved
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

… high-register training gap

First perceptual check of any render reported two defects on the best Brandy conversion
of Hero. Both reproduced and measured; they have different causes.

Defect 1 (quiet edges cut off) - FIXED. -db is an absolute-dBFS split threshold; at -40,
breath tails and note decays at -54..-64 dBFS (just above the stem floor, p2 = -59) were
written as EXACT ZEROS: 26 frames on hero20, 21 on the high-register clip. The audible
defect is the hard discontinuity, not the level. -db -60 gives 0 zeroed frames with only
4.5 dB more silence bleed (-49.8 vs -54.3 dBFS); -db -200 also zeroes nothing but bleeds
model noise into silences, so it was rejected. Applied to the serving config with a
.pre_dbthresh60_20260905 rollback snapshot. Checkpoint untouched (trained_epochs 235).

Defect 2 (high-register dropout) - NOT fixable in the recipe, filed as AV-41e4. Brandy's
training corpus has 0.00% of voiced frames above 700 Hz (max 844); Hero reaches 1031 Hz.
Render ducks monotonically -4.6/-4.7/-5.0 dB at 500-600/600-800/800-1036 Hz, starting
exactly where corpus coverage ends. Ruled out by measurement: crepe UV threshold (UV 0.1
and UV-off gave no improvement), the hardcoded f0_max=1100 (her top note is under it), and
checkpoint choice (all ten arms are 3.9-5.9 dB down at 500-600 Hz; st3's largest fresh
corpus is among the worst up top).

A/B renders registered in GUI History tagged edge-fix.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…e), no serving change

Correction to 275f903, which claimed db_thresh -40 -> -60 fixed cut-off voice edges.
That was measured on the wrong path and is retracted; the live entry is byte-identical
to its pre-session state (db_thresh -40, trained_epochs 235).

What was wrong:
- The diagnostic renders used G_135 + SVCFORK_UV_CONTRACT=1 +
  SVCFORK_CREPE_UV_THRESHOLD=0.3 on 20s clips. The served entry sets NEITHER env key
  and serves ..._svcfork/G.pth, and a 20s clip is a single chunk that never exercises
  the silence split at all.
- -db is dB below the clip PEAK, not absolute dBFS (core.py:251,254,
  ref=1 if absolute_thresh else np.max; absolute_thresh defaults False, absent here).
  So -60 lands at -72.5 dBFS, below the stem floor = no gating whatsoever - i.e. the
  'gate off' case the same commit rejected for bleeding noise into silences.
- The earlier scoring averaged dB-domain values including 20*log10(1e-12), and derived
  its floor from a percentile that landed on the song's digital silence, not the stem
  noise floor.

Measured on the served path instead (pipeline #7 isolated lead stem vs source vocal,
full 258s, phrase spans from librosa.effects.split(top_db=30), linear-RMS means):
  in-phrase +0.2 dB | phrase tails +4.4 dB | 0 tail frames zeroed | 0 frames >20 dB down
  by source F0: +1.2 dB at 300-400, -4.5 at 500-600, -4.8 at 600-800, -7.8 at 800-1600
Swept -40..-80 relative and -75/-85 absolute: 0 tail frames zeroed at every value.

So there is one defect, not two: nothing gates her edges; her level collapses 5-8 dB as
she climbs, and her sustained top notes sit at phrase ends, which under a full mix reads
as the voice cutting out at phrase edges. Cause is corpus pitch coverage (p99 496 Hz,
max 844) vs a source reaching 1031 Hz - tracked in AV-41e4. Ruled out by measurement:
db_thresh, crepe UV threshold (not even active in serving), f0_max=1100 (never fires),
and checkpoint choice (all ten arms 3.9-5.9 dB down at 500-600 Hz).

Replaces scripts/register_edge_ab.py (hardcoded dead /tmp paths, title-keyed dedup) with
scripts/register_render.py: argparse, DATA_DIR-aware, uuid5-keyed so re-runs are
idempotent. GUI now carries a source-vs-converted high-register pair instead of the
retracted BEFORE/AFTER 'FIX' records.

detect_changes: no indexed symbols affected.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…ract gate and decay mechanisms

Third and final revision of the 2026-09-05 late entry. Measured on the SERVED weights this
time (pipeline #5 = ep235 isolated lead stem vs source stem, full 258s, alignment verified
0 samples / 0 ms). Earlier revisions used pipeline #7 (MRD ep41) or bare svc infer with
candidate checkpoints and UV env vars serving never sets.

Two independent losses, both at the top of her voice:
- Loss 1, spectral air/presence: 3-6k -3.9 dB, 8-12k -8.6, 12-16k -13.6, fmax 17.9k vs
  source 20.0k (6-8k is +3.2, brighter). Band levels referenced to each file's own
  300-1000 Hz, so global gain cannot produce it. This is what 'edges around her voice'
  means - the air halo at 8-16 kHz.
- Loss 2, level collapse with pitch: +1.7 dB at 300-400 Hz, -5.6 at 500-600, -5.5 at
  600-800, -10.9 at 800-1600. Worse on served ep235 than any candidate (MRD ep41 -7.8).
  Cause is corpus coverage: p99 496 Hz, max 844 vs a source reaching 1031 Hz.

The two are independent: phrase-final 300 ms frames are 0.8% >=500 Hz vs 4.3% in-phrase,
so the high-F0 collapse cannot be what cuts the edges. The user's 'it's both' was right.

Retracted (each was published, each removed by measurement):
- 'db_thresh -40 -> -60 fixes the edges' (275f903). Swept -40..-80 relative and -75/-85
  absolute on the full vocal through the served command: 0 tail frames zeroed at every
  value including live -40; tail-minus-body within-file is -10.1 source vs -9.9 ep235.
  Also -db is dB below clip PEAK, not absolute dBFS, so -60 gates nothing.
- 'one mechanism, not two' - refuted by the phrase-final F0 test.
- 'ep235 truncates decays 30% faster' - artifact of per-file span detection (116 vs 134
  phrases). Matched source-derived windows reverse it: source 330 ms vs ep235 360 ms,
  faster on 49% of offsets.

Live config unchanged and verified byte-identical to its pre-session snapshot
(db_thresh -40, trained_epochs 235). GUI listening set retagged 'highreg': source vs
served ep235 vs MRD ep41 over 168-188s, vocals only. register_render.py now preserves
isFavorite/notes/tags on re-run.

detect_changes: no indexed symbols affected.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…ttribution

The served lead is 1 channel - pipeline #5's own note records 'mono centred vocal
(stereo width 0.0 like every approved OLT render)'. Mariah's vocal stem is 2 channels
with side content at -15.7 dB relative to centre; at mix level the delivered render is
-13.7 dB side/mid against the original's -11.9. So everything spatially AROUND her voice
is discarded before any of this session's metrics run - every one of them sums to mono
first, which is why none could see it, and it is present in every approved render by
construction (fits 'the best conversion still has it').

Two candidates now fit 'edges cut off around her converted voice' equally well on paper:
presence/air (8-12k -8.6 dB, 12-16k -13.6, fmax 17.9k vs 20.0k) and the stereo halo.
Attributing either without a listen would repeat the retractions already in this entry,
so the doc now states it as unestablished and registers the instrument that settles it:
five 40-60s full mixes tagged edges-ab (original / served / +air / +stereo halo / +both),
each the delivered mix plus a measured delta. +air moves 8-12k to -23.1 and 12-16k to
-25.9 (original -22.2/-25.4); +halo reaches the original's -11.9 dB side/mid. Both are
offline pipeline post-stages - no retraining, no model or registry change.

Also: validated the air band is real vocal content, not separator bleed (12-16k is
+20.4 dB in-phrase vs between-phrase, correlation +0.82 with her envelope). And dropped
the implied checkpoint ranking - ep235 -10.9 dB vs MRD ep41 -7.8 dB at 800-1600 Hz is
3.1 dB between single renders, inside this session's ~3 dB checkpoint noise floor.

Live registry still byte-identical to its pre-session snapshot (db_thresh -40, ep235).
detect_changes: no indexed symbols affected.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

….35 render already exists

fork_hq_stereo_width is explicitly 0.0 in data/app_state/app_settings.json and is a
documented runtime setting accepting 0.0-1.0 (runtime_contract.py:86, api_runtime.py:482),
so Loss 1b is configuration, not a model limit. The pipeline's widening is real model
decorrelation - L and R converted separately, difference becomes side, scaled by
stereo_width (singing_conversion_pipeline.py:1648-1676) - not a pseudo-stereo trick.

A render of these exact ep235 weights at width 0.35 already exists in History
(herofix-d9e90fc4, 'ep235 + FIXES (edges kept, stereo 0.35)'), and its own note says it was
built 'for your complaints' and asks for a comparison against the serving render. Measured
side/mid: original -11.9, served -13.7, width-0.35 -10.9. That render also used db -35 and a
different instrumental, so width is not its only difference - noted in the doc and the
record title.

Also exonerates fork_hq_match_source_bandwidth: it defaults on and low-passes the converted
vocal to the source's measured wall, but _detect_bandwidth_hz returns 20000 Hz here, above
the render's own rolloff, so it is inert on this material. The 17.9-18k ceiling is the
decoder.

Listening set is now six entries: the offline air/halo variants are labelled as
approximations to isolate the variable, and the shippable spatial variant is the real
pipeline width 0.35. Nothing changed in the registry or app settings.

detect_changes: no indexed symbols affected.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…x, not the stem

The exoneration of fork_hq_match_source_bandwidth was measured on the separated stem, which
is precisely the signal the pipeline does NOT use: singing_conversion_pipeline.py:1689-1694
measures the original mix and warns that a stem reads as full-band because the separator
invents energy above the source's wall.

Re-measured correctly on the original mix: 20000 Hz, identical at 48k native and resampled
to 44.1k. So the filter DOES fire (20000 < the 20947 Hz threshold) and applies a 20 kHz
low-pass - but 20 kHz sits above the decoder's own 17.9-18k rolloff, so it still cannot be
what creates the fmax gap. Conclusion unchanged, provenance now correct; the stem happens to
return the same number on this song, which is a coincidence and not a basis to reason from.

detect_changes: no indexed symbols affected.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

…ue is 0.16, not 0.35

singing_conversion_pipeline.py:1666-1668 scales side by stereo_width * mid_rms / side_rms,
so the vocal's side/mid ratio equals stereo_width exactly. That makes the value arithmetic:
0.35 = -9.1 dB, which is 6.6 dB WIDER than Mariah's own stem (-15.7 dB); the matched value
is 0.164. If the halo is the missing thing, ship 0.16, not the 0.35 that happens to exist.
Higher width also means more of the chorus/decorrelation artefact the pipeline's comments
warn about, since side is the difference of two stochastic conversions.

Resolved the comparator question empirically: the htdemucs and BS-RoFormer remixes of the
same width-0.35 render both measure -10.9 dB side/mid, so the instrumental is not a confound
on this axis. Its TONE still cannot be judged as width-only (also used db -35; 1.9 dB darker
at 8-12k, 4.6 at 12-16k, walls 4.1 kHz lower).

Noted that fork_hq_stereo_width is a global app setting and 0.0 is the documented recipe
behind every approved OLT render - user-approved state, so only a listening verdict moves it.
Also noted both fix renders predate the complaint (09-04 vs 09-05): if that render was
already heard and the complaint stands, the spatial hypothesis is largely dead.

Listening set now seven entries with distinct stated roles: 4of7 isolates width alone
(spectrum bit-identical to served), 6of7 proves the pipeline's own knob reaches the target.

detect_changes: no indexed symbols affected.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

… 0.0 was a later choice

Measured the two width-0.35 remixes on vocal-silent frames (instrumental alone):
  served #5        8-12k -20.9  12-16k -21.6  fmax 22.1k
  d9e90fc4 htdemucs      -30.1        -34.7       17.9k
  c5e8decd RoFormer      -20.8        -21.5       19.6k
So the darkness and the 18k wall in d9e90fc4 are its instrumental, not the vocal and not the
width - which reverses my earlier 'the instrumental is not a confound' note: it is moot for
side/mid (-10.9 both) but decisive for tone. c5e8decd is therefore the only one of the two
comparable to serving on tone, and the confounded htdemucs clip is dropped from the listening
set (now six entries, relabelled).

Corrected the ordering claim: the 0.35 renders came FIRST (09-04 11:19, 13:22) and the served
width-0.0 recipe was built later at 18:03, so width 0.0 was a subsequent choice, not an
accidental regression - the doc records it as the recipe behind every approved OLT render.

Whether those renders were ever auditioned cannot be inferred from the store: isFavorite,
notes and user tags are unset on both, and exactly one record in 236 has isFavorite set at
all (an unrelated 09-02 render). Recorded as a question that must be asked.

register_render.py: skip the copy when src resolves to the destination, so re-registering an
already-registered clip to fix its title no longer raises SameFileError.

detect_changes: no indexed symbols affected.
@cr-gpt

cr-gpt Bot commented Sep 5, 2026

Copy link
Copy Markdown

Seems you are using me but didn't get OPENAI_API_KEY seted in Variables/Secrets for this repo. you could follow readme for more information

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant