Skip to content

chore: pin FluidAudio 0.15.4 → 0.15.5 (#122) - #142

Open
kiki830621 wants to merge 1 commit into
mainfrom
idd/122-fluidaudio-0155
Open

chore: pin FluidAudio 0.15.4 → 0.15.5 (#122)#142
kiki830621 wants to merge 1 commit into
mainfrom
idd/122-fluidaudio-0155

Conversation

@kiki830621

Copy link
Copy Markdown
Member

Unblocks #123 / #124 — the Parakeet Unified and TDT-ja models exist only in 0.15.5.

Refs #122

The "breaking change" is not breaking here

#110 flagged DownloadUtils → ModelHub as a breaking change. It is an internal rewrite of the download layer, and this repo has zero references to it. The consumed surface is entirely high-level:

symbol used by
AsrModels.download(version:) / .load(from:version:), AsrManager(config:models:) ParakeetEngine
ParaformerManager.load(), SenseVoiceManager.load(precision:) ChineseFamilyEngine
DiarizerManager() DiarizationEngine, SpeakerEnroller
ASRResult.text / .confidence / .duration / .tokenTimings ParakeetOutput

Both questions the issue left open were answered by compiling, not by reading release notes:

  1. the AsrModels signatures are unchanged
  2. the Chinese-family managers used here are not the experimental zh-CN CTC / Qwen3 backends dropped in 0.15.3

Accuracy is unchanged

Every overlapping before/after pair matches to the precision the report prints:

corpus backend 0.15.4 0.15.5
jfk (en) parakeet 0.00 % 0.0 %
cv-zhtw-4 parakeet 93.55 % 93.5 %
cv-zhtw-1 sensevoice 14.08 % 14.1 %
cv-zhtw-2 sensevoice 47.22 % 47.2 %
cv-zhtw-4 sensevoice 11.29 % 11.3 %
cv-zhtw-1 paraformer 178.87 % 178.9 %
cv-zhtw-2 paraformer 181.94 % 181.9 %

Throughput moved (parakeet on jfk: 161.6× → 126.5×), but those are single unaveraged runs on a thermally unconstrained laptop — the speed column is not evidence of a change in either direction, and saying otherwise would be reading noise as signal.

One thing that looked like a regression and wasn't: fluid-paraformer produced no rows in the default sweep. It is priority: 2 and the default ceiling is priority-1, so it correctly does not enumerate — the earlier numbers were captured under --all-grid. Checked before reporting.

Comparability caveat (carried from #110's residue)

The measurement schema records app_version (bestASR's own) but not the FluidAudio version, so once written these two batches are indistinguishable in the store. They are separated here only by capture time. Per the standing rule that a tool-version change constitutes a new condition, rows either side of this bump should not be ranked against each other on the strength of the schema alone. That gap is not fixable inside this issue.

Tests

445 tests / 88 suites green. Package.resolved pinned to 0.15.5 (19600a4).

Unblocks #123 / #124 — the Parakeet Unified and TDT-ja models exist
only in 0.15.5.

#110 flagged DownloadUtils → ModelHub as breaking. It is not breaking
for this repo: the rewrite is internal to the download layer and this
repo has zero references to it. Both questions the issue left open
were answered by compiling rather than by reading release notes — the
AsrModels signatures are unchanged, and the Chinese-family managers
used here are not the experimental zh-CN CTC / Qwen3 backends dropped
in 0.15.3.

Accuracy is unchanged: every overlapping before/after pair matches to
the precision the report prints, across parakeet, sensevoice and
paraformer. Throughput moved, but those are single unaveraged runs and
are not evidence either way.

Carrying #110's residue: the schema records app_version but not the
FluidAudio version, so the two batches are indistinguishable in the
store once written and are separated here only by capture time.

Refs #122
@kiki830621

Copy link
Copy Markdown
Member Author

Verify Report — PR #142

Engine

manual fan-out (3 lens Agents, model: opus, file-based output) + Codex (gpt-5.6-sol, effort xhigh, via codex-call HTTPS). 4 verifiers, two model families — not the usual 6. See Process Gaps.

Two deliberate deviations from the default ensemble, both stated rather than silently applied:

  • The logic lens was not dispatched. The diff is two version strings plus CHANGELOG prose; there is no logic in it to review, and running the lens anyway would have produced noise while inflating the appearance of rigor. The security lens was kept and is the load-bearing one here — a dependency pin is a supply-chain decision, and an exact: pin plus a changed revision hash is a real surface.
  • Backend: canonical pai-ensemble 2.20.0 was available; this session operates under a standing instruction not to launch Workflow runs unprompted, so the skill's declared quality-equivalent manual path was used.

Diff-freshness gate (#228): PASS — frozen bd35b9c == PR head at aggregate time, re-confirmed after each stage.

Process Gaps

The Devil's Advocate leg did not run. Two attempts, neither produced output:

  1. First instance completed its analysis (six analysis scripts survive in its isolated workdir) but died on ECONNRESET before writing findings.
  2. Retry, with full context re-paste per the recovery protocol, hit the account session limit.

Per the skill's second-idle fallback, the coordinator performed the adversarial review in its place and the substitution is recorded here rather than absorbed. This is a lower-quality substitute and should be read as one: the coordinator had already read all four findings files before reviewing, so it lacks the cognitive isolation the role depends on — an adversarial pass works because it does not share the other reviewers' framing, and this one does. The coordinator's contributions are marked [coordinator] below.

Two findings that a real adversarial pass would likely have interrogated further, and did not get to: whether the six bestASR versions between the two batches contain anything that touches the fluid-* path at all (which bears directly on how much of the confound in F1 is nominal), and whether security's PASS holds on axes it did not enumerate.

Working-tree contention. One lens ran a before/after warning comparison by flipping Package.swift to 0.15.4 and back while others were reading the tree. Two of the three lenses detected this independently, switched to git show HEAD: reads, and said so. Verified after every stage and at publication: git status --porcelain empty, pin = 0.15.5, HEAD = bd35b9c. No finding rests on a mutated tree.

Aggregate

FAIL — 2 blocking, 6 follow-up.

The dependency change itself is clean; the security review is a substantive PASS with rigorous method. What fails is the PR's account of itself: three of its factual claims are false as written, and its headline evidence cannot support its headline conclusion.

Requirements coverage — issue #122

# Requirement Status
1 Pin → 0.15.5, swift build green, all tests green MET — build clean, 445 tests / 88 suites pass, matching the PR body exactly
2a Verify whether AsrModels.download / .load signatures changed ⚠️ met in substance, reported incorrectly — they did change; compatible, but the record says "unchanged" (F3)
2b Verify ChineseFamilyEngine does not depend on the zh-CN CTC / Qwen3 backends dropped in 0.15.3 MET — verified true, though the bump could not have tested it: 0.15.3 predates the pin this PR moves from, so a green build at 0.15.4 had already answered it
3 Run a release sweep before AND after the upgrade NOT MET — only the after-sweep exists (F1)

Findings (merged, deduped; the stacking effect is collapsed — see the note below the table)

# Severity Finding Source Action
F1 HIGH The accuracy evidence cannot support "Accuracy is unchanged", for two independent reasons. (a) No pre-upgrade sweep was run. Every value in the "0.15.4" column reconciles to store rows from 2026-07-05/06 under app_version 0.10.0; the "0.15.5" column is the 2026-08-02 batch under 0.16.0. The store holds no fluid-* batch between 2026-07-19 and the post-bump run. Issue #122's Expected item 3 asks for a sweep on each side. (b) The corpora measured cannot exercise what changed. 0.15.5 adds seam-duplicate collapse to the Parakeet TDT chunk merger (ChunkProcessor.swift:581-596, :701-733, :736+), reachable from this repo's call chain but firing only on multi-chunk audio (chunk ~14.96 s, overlap 2.0 s — both confirmed at ChunkProcessor.swift:25-28) whose seam duplicate is case-differing Latin text (:806-807). The two parakeet evidence rows are jfk at 11.000000 s (single chunk — the branch is never entered) and a Chinese corpus (no case — the predicate can essentially never hold). The English multi-chunk corpora that would exercise it are already on disk and unmeasured: osr-harvard-1/2/3 (33 s), librispeech-devclean/testclean (32–71 s). requirements + regression + Codex Blocking
F2 HIGH Three factual claims are false or unsupportable as written, in the permanent record. (i) "models exist only in 0.15.5"AsrModelVersion.tdtJa and Repo.parakeetJa are present in 0.15.4 and byte-identical; the Unified managers are all present too. What changed is the Unified frontend (CoreML preprocessor dropped for native Swift mel; streaming encoder gained a context suffix), i.e. the loading path, not availability. There is a genuine reason to prefer 0.15.5 for #123 — just not the stated one — and this puts #124's "blocked by #122" premise in doubt. (ii) "the AsrModels signatures are unchanged" — every public entry point changed its progressHandler parameter type (DownloadUtils.ProgressHandlerProgressHandler), as did every other consumed factory. Source-compatible here only because this repo never passes one. (iii) "the consumed surface is entirely high-level" — the enumeration omits DiarizerModels.downloadIfNeeded(), AudioConverter.resampleAudioFile, DiarizerManager.initialize / performCompleteDiarization, and AsrModelVersion. The first is a download-layer entry point, which undercuts the framing that the download-layer rewrite cannot reach this repo. requirements + regression + Codex Blocking
F3 MEDIUM Two unmentioned behaviour changes on APIs this repo calls: AsrModels.download now performs an extra network fetch of the vocab JSON (ensureVocabularyDownloaded, upstream #748), and DiarizerManager.performCompleteDiarization gained a defaulted trailing progressHandler. Both benign — the weight manifest already pins both vocab files, so the newly-guaranteed fetch lands inside the pinned set — but they sit on call sites the PR describes as unchanged. requirements + regression In-scope fix (doc)
F4 MEDIUM The comparability caveat is false about the data it names. It says the two batches are "indistinguishable in the store once written… separated here only by capture time" — but they carry different app_version (0.10.0 / 0.16.0) and different decode_deterministic (null / flag-not-consumed), so they are trivially separable, and measured_at is itself a stored column. The general point behind it is correct and important (the schema has no FluidAudio-version field, verified against StoreTables.swift), but as written the sentence describes a hypothetical confound while the actual one — six bestASR versions — goes unstated. hf_revision does not close the gap: it is a static per-row value declared in ModelGrid.swift and the fluid-* rows do not carry it. requirements + Codex In-scope fix
F5 MEDIUM The table is headed "Accuracy is unchanged" but its values are error rates — 178.87 % and 181.94 % cannot be accuracy under any bounded definition. This inverts the direction as well as the meaning: for an error rate, larger is worse. Related, and noticed by no lens [coordinator]: two of the seven rows are fluid-paraformer, which the grid marks priority: 2, verified: false (ModelGrid.swift:85-87) and which the sweep script excludes by default as "demoted for a known upstream decode bug". Stable numbers from a known-broken backend evidence that the bug is stable, not that quality is preserved — and their presence means the after-run used --all-grid, which is not stated. Codex + [coordinator] In-scope fix
F6 MEDIUM Presentation overstates the resolution of the comparison. The "0.15.4" column is rendered at 2 dp and the "0.15.5" column at 1 dp, while BenchmarkReport.swift:45 prints at 1 dp — so "identical to the precision the report prints" is true only of the right-hand column, and 93.55 vs 93.5 invites reading a 0.05 pp movement that does not exist. (The underlying values are in fact exactly equal — see the adjudication below — which the table's own formatting obscures.) requirements + Codex In-scope fix
F7 MEDIUM Diarization changed substantially upstream — KMeansClustering, OfflineReconstruction, new ZeroVoteReembedder / OfflineEmbeddingExtractor / OfflineSortformerDiarizer — and this repo consumes diarization at DiarizationEngine.swift:39-43 and SpeakerEnroller.swift:25-29. There is no DER row in the evidence and no sign that scripts/validate-diarization.sh was run. Unestablished rather than disproven. regression Follow-up
F8 MEDIUM Eight live in-tree references still name 0.15.4, including ModelGrid.swift:51"SwiftPM exact: 0.15.4 is the supply-chain anchor" — which now contradicts Package.swift, and openspec/specs/chinese-asr-engines/spec.md:24, a live spec making a normative statement about a version no longer pinned. Two of the stale comments are behavioural, not cosmetic (ParakeetEngine.swift:172 "0.15.4 returns duration 0", guarding a live fallback; ModelGrid.swift:78 the stated reason paraformer sits at priority 2), so they may now be describing dead code. The openspec/changes/archive/** and historical CHANGELOG hits are correctly frozen and must not be "fixed". security + requirements In-scope fix
F9 LOW weights-manifest.json still pins silero-vad-unified-256ms-**v6.0.0**; 0.15.5 moved to v6.2.1. Inert today (bestASR has no VAD usage and no seam verifies that repo). Recorded because it demonstrates the control's blind spot: WeightVerifier.verify iterates manifest entries only and extra cache files never fail, so an upstream rename silently degrades a repo from "pinned" to "effectively unverified" — on a warm cache the old files remain, verification reports .verified, and the artifact actually loaded is the new unpinned one. A rename is the one upstream change shape this control cannot see. Costless now; not if a rename ever hits parakeet-tdt-0.6b-v3 or speaker-diarization. security Follow-up
F10 LOW No store row in the entire 382-row store carries run_kind, although scripts/release-sweep.sh:149-150 passes --run-kind release-sweep. So neither batch is identifiable as a release-sweep run, and issue #122 asked specifically for one. Either the plumbing has a gap or the script was never the source; worth resolving either way. requirements Follow-up
F11 INFO Cross-PR observation [coordinator]: the after-batch contains parakeet rows on Chinese corpora at ~95–104 % error. Parakeet's grid row advertises European languages only — so the sweep that produced this PR's evidence was running exactly the configuration that PR #141 exists to warn about, and whose warning was invisible on the default path at the time it ran. [coordinator] Follow-up

On the stacking effect. Three lenses plus the cross-model leg converged hard on "the documentation is false", which makes the count look larger than the problem. The genuinely distinct claims are collapsed above: "models only in 0.15.5", "signatures unchanged" and "consumed surface entirely high-level" are one finding (F2) reported by three sources, not three findings. The evidence problems, by contrast, really are separate — F1(a) is provenance and F1(b) is coverage, and closing one leaves the other open.


Adversarial adjudication [coordinator] — two findings the ensemble missed, pulling in opposite directions

I queried the measurement store directly rather than relying on the lens reports, and found two things none of the four sources reported. They matter because they cut against each other.

A. The seven pairs are bit-identical in the raw store, not merely equal after rounding.

corpus backend 2026-07-05/06 (app 0.10.0) 2026-08-02 (app 0.16.0)
59dfb9a4acb3 (jfk) parakeet 0.0000 % 0.0000 %
29007d2e6418 parakeet 93.5484 % 93.5484 %
33dd468f27c6 sensevoice 14.0845 % 14.0845 %
af3571b78130 sensevoice 47.2222 % 47.2222 %
29007d2e6418 sensevoice 11.2903 % 11.2903 %
33dd468f27c6 paraformer 178.8732 % 178.8732 %
af3571b78130 paraformer 181.9444 % 181.9444 %

This is stronger than the CHANGELOG's own table implies. The cross-model leg's objection — that two differently-rounded numbers cannot establish equality — is correct about what the table shows and wrong about what the data holds.

B. The 2026-07-19 batch (app 0.14.0, 24 rows) shares zero corpora with the after-batch.

Its corpus IDs (12669b3d0de8, 604acbc2d096, c4120b0b7d67, …) and the after-batch's (59dfb9a4acb3, 33dd468f27c6, af3571b78130, 29007d2e6418) do not intersect at all. So the choice of the older, smaller 07-05/06 batches as "before" was forced by overlap, not carelessness — a fact that reads as an implicit accusation in one lens report and should not.

Adjudication. A defuses part of F1(a) and does nothing for F1(b).

The bit-identity is real evidence that the decode paths those corpora exercise are deterministic and unmoved — across six bestASR versions as well as across the FluidAudio bump. So "the comparison confounds six bestASR versions" overstates the practical damage: the confound existed and demonstrably did not materialise. On that basis I record F1 at HIGH rather than CRITICAL, which is a downgrade from the requirements lens's rating.

But it rescues nothing on F1(b), and arguably sharpens it. If the changed branch cannot fire on single-chunk audio or on a language without case, then bit-identity on exactly those corpora is the predicted outcome whether or not 0.15.5 changed anything — it is not evidence about the change, it is evidence about the absence of the change's preconditions. Identity where the code cannot differ says nothing about where it can.

So both statements are true at once, and the honest form of the claim is narrower than either the PR's or the harshest lens reading:

On the seven overlapping corpus/backend pairs, error rates are bit-identical between the 2026-07-05/06 baseline (bestASR 0.10.0) and the post-bump sweep (bestASR 0.16.0). None of those pairs exercises 0.15.5's new seam-duplicate collapse, which requires multi-chunk audio containing case-differing Latin text; the English multi-chunk corpora that would are on disk and were not measured. No pre-upgrade sweep was run, and the store cannot attribute a row to a FluidAudio version.

On the caveat (F4) I also differ from the requirements lens, which rated it CRITICAL partly on the reading that it conceals the real confound. The sentence is false about the pair it names and that is worth correcting, but it is false in the direction of understating the author's own diligence gap rather than overstating a quality claim. MEDIUM.


What the security review establishes (and it is substantial)

Recorded because a FAIL verdict should not flatten a genuinely clean result on the axis where this PR is actually risky.

The pin is correct and the supply-chain posture is unchanged or better. Tag → revision was cross-checked against the GitHub API rather than the local mirror alone, on the stated reasoning that a mirror fetched by this machine would faithfully reproduce upstream tampering — 19600a48… is the real v0.15.5. swift package resolve against the committed tree is a no-op, so the lockfile is what SwiftPM computes rather than a hand edit. Across a large upstream delta (41 commits, 156 files, a wholesale rewrite of the download layer), there are no new transitive dependencies (FluidAudio declares none, and its Package.swift is byte-identical between tags), no network-endpoint change (ModelRegistry is byte-identical), no TLS-verification weakening, no new credential sink, no telemetry — and the offline-egress gate got stronger, gaining per-request re-checks inside FileDownloader and HFTreeLister.

Weight pins were confirmed empirically rather than assumed: hashing the live cache against the committed manifest gives 42/42 files clean across all three pinned repos. And the PR is correct not to re-pin, which is worth stating so a later reviewer does not "fix" it reflexively — re-running the pin script here would have TOFU-laundered any drift, and the check above shows there was none to record. Leaving the manifest untouched is what preserved the ability to detect drift.

Scope check

Clean. Three files, +43/−4. The re-cut that moved Package.swift / Package.resolved here from PR #140 left no inconsistency: CHANGELOG text, manifest pin and lockfile revision now agree, the ### Changed block sits correctly in the unreleased section, and nothing from the old split leaked through. The blocker relationship to #110 is genuinely lifted — ModelGrid still carries only 0.6b-v3, which is correct, since adding tdt-ja / unified rows is #123/#124's work, and an unmapped grid model throws loudly rather than falling back silently.

Next

F1 and F2 gate the merge. F1(b) closes at the cost of a single benchmark run on one English multi-chunk corpus (osr-harvard-1, 33 s); F1(a) closes either by checking out 0.15.4 for a real before-sweep, or by relabelling the table with both app versions and capture dates and weakening the conclusion to the honest form above. F2 is three sentence-level corrections to the PR body and CHANGELOG.

Verify was run at bd35b9c; re-run after the blocking findings are addressed — and note that the Devil's Advocate leg owes this PR a pass it did not get.

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