Summary
The macOS slice of the vendored TranscribeCpp.xcframework (transcribe-cpp-swift 0.1.2) has a malformed framework bundle layout: the top-level entries are real files/directories instead of symlinks into Versions/A. Because the bundle then contains two divergent copies of the binary, code signing seals it invalid, and a from-source build of FluidVoice produces an app that fails codesign --verify.
This does not affect the official signed release (presumably repaired or signed differently in your pipeline), but it does mean contributors building from source get an app macOS can refuse to launch.
Affected
- Dependency:
altic-dev/transcribe-cpp-swift, version 0.1.2, revision a16df2905f9c715344374fd2d8dd97c2712a6d96
- Declared in
Fluid.xcodeproj/project.pbxproj (XCRemoteSwiftPackageReference "transcribe-cpp-swift"); used via import TranscribeCpp in Sources/Fluid/Services/WhisperProvider.swift
- Introduced in
a7876b1 ("feat(asr): migrate Whisper to TranscribeCpp", 2026-07-09)
- Reproduced on v1.6.4 and v1.6.5; macOS 27.0, Apple Silicon (M3 Max), Xcode 27.0
What's wrong
In TranscribeCpp.xcframework/macos-arm64_x86_64/CTranscribe.framework, as downloaded by SwiftPM:
-rwxr-xr-x CTranscribe ← should be a symlink → Versions/Current/CTranscribe
drwxr-xr-x Resources ← should be a symlink → Versions/Current/Resources
drwxr-xr-x Versions
drwxr-xr-x Versions/Current ← should be a symlink → A
A macOS framework is a versioned bundle: the top-level CTranscribe and Resources must be symlinks into Versions/Current, and Versions/Current must be a symlink to Versions/A. Here they're all real, so Versions/A/CTranscribe and Versions/Current/CTranscribe are two separate 7.1 MB files with different SHA-256 hashes.
(The ios-* slices are flat, which is correct — iOS frameworks are flat bundles. Only the macOS slice is affected.)
Repro
git clone https://github.com/altic-dev/FluidVoice && cd FluidVoice
git checkout v1.6.5
xcodebuild build -project Fluid.xcodeproj -scheme Fluid -configuration Release \
-derivedDataPath /tmp/dd \
CODE_SIGN_IDENTITY="-" CODE_SIGN_STYLE=Manual DEVELOPMENT_TEAM="" \
PROVISIONING_PROFILE_SPECIFIER="" CODE_SIGNING_REQUIRED=NO CODE_SIGNING_ALLOWED=YES
codesign --verify --deep --strict /tmp/dd/Build/Products/Release/FluidVoice.app; echo "exit=$?"
Expected: exit=0
Actual: exit=1
FluidVoice.app: a sealed resource is missing or invalid
In subcomponent: .../Contents/Frameworks/CTranscribe.framework
Worth noting the build itself reports ** BUILD SUCCEEDED ** — the failure only shows up on verification, so it's easy to miss and ship an unlaunchable app.
Fix
Ideally in transcribe-cpp-swift: build/package the macOS slice with the standard versioned layout, e.g.
cd CTranscribe.framework
ln -s A Versions/Current
ln -s Versions/Current/CTranscribe CTranscribe
ln -s Versions/Current/Resources Resources
ditto and xcodebuild -create-xcframework preserve symlinks; a cp -R or a zip round-trip without symlink support will flatten them, which is the likely origin.
Workaround for anyone building from source — after building, before signing: remove the duplicated top-level CTranscribe, Resources and the real Versions/Current, recreate them as symlinks, then re-sign the framework and the app (frameworks first, app second, not --deep). That takes verification back to exit=0.
Happy to open a PR against transcribe-cpp-swift if that's the right place for it.
Summary
The macOS slice of the vendored
TranscribeCpp.xcframework(transcribe-cpp-swift0.1.2) has a malformed framework bundle layout: the top-level entries are real files/directories instead of symlinks intoVersions/A. Because the bundle then contains two divergent copies of the binary, code signing seals it invalid, and a from-source build of FluidVoice produces an app that failscodesign --verify.This does not affect the official signed release (presumably repaired or signed differently in your pipeline), but it does mean contributors building from source get an app macOS can refuse to launch.
Affected
altic-dev/transcribe-cpp-swift, version 0.1.2, revisiona16df2905f9c715344374fd2d8dd97c2712a6d96Fluid.xcodeproj/project.pbxproj(XCRemoteSwiftPackageReference "transcribe-cpp-swift"); used viaimport TranscribeCppinSources/Fluid/Services/WhisperProvider.swifta7876b1("feat(asr): migrate Whisper to TranscribeCpp", 2026-07-09)What's wrong
In
TranscribeCpp.xcframework/macos-arm64_x86_64/CTranscribe.framework, as downloaded by SwiftPM:A macOS framework is a versioned bundle: the top-level
CTranscribeandResourcesmust be symlinks intoVersions/Current, andVersions/Currentmust be a symlink toVersions/A. Here they're all real, soVersions/A/CTranscribeandVersions/Current/CTranscribeare two separate 7.1 MB files with different SHA-256 hashes.(The
ios-*slices are flat, which is correct — iOS frameworks are flat bundles. Only the macOS slice is affected.)Repro
Expected:
exit=0Actual:
exit=1Worth noting the build itself reports
** BUILD SUCCEEDED **— the failure only shows up on verification, so it's easy to miss and ship an unlaunchable app.Fix
Ideally in
transcribe-cpp-swift: build/package the macOS slice with the standard versioned layout, e.g.cd CTranscribe.framework ln -s A Versions/Current ln -s Versions/Current/CTranscribe CTranscribe ln -s Versions/Current/Resources Resourcesdittoandxcodebuild -create-xcframeworkpreserve symlinks; acp -Ror a zip round-trip without symlink support will flatten them, which is the likely origin.Workaround for anyone building from source — after building, before signing: remove the duplicated top-level
CTranscribe,Resourcesand the realVersions/Current, recreate them as symlinks, then re-sign the framework and the app (frameworks first, app second, not--deep). That takes verification back toexit=0.Happy to open a PR against
transcribe-cpp-swiftif that's the right place for it.