From 793682b82812d3e89adcc354dd8b844af094ce13 Mon Sep 17 00:00:00 2001
From: Ariver <shanghai3168@gmail.com>
Date: Fri, 05 Jun 2026 04:09:28 +0800
Subject: [PATCH] Record App Store clean rebuild

---
 02-P-NBL/freeze/20260605-mac-app-store-clean-rebuild.md                                  |   36 ++++++++++++
 02-P-NBL/freeze/20260605-mac-app-store-upload-preflight.md                               |    3 
 Docs/KM2.项目管理-非业务直接相关/QA工作-经验与教训.md                                                      |    8 ++
 Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/RELEASE_MANIFEST.md             |   79 ++++++++++++++++++++++++++
 Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/APP_STORE_CONNECT_SUBMISSION.md |   31 ++++++++++
 Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/SHA256SUMS.txt                  |    1 
 6 files changed, 157 insertions(+), 1 deletions(-)

diff --git a/02-P-NBL/freeze/20260605-mac-app-store-clean-rebuild.md b/02-P-NBL/freeze/20260605-mac-app-store-clean-rebuild.md
new file mode 100644
index 0000000..44ba2f0
--- /dev/null
+++ b/02-P-NBL/freeze/20260605-mac-app-store-clean-rebuild.md
@@ -0,0 +1,36 @@
+# 2026-06-05 Mac App Store clean rebuild
+
+## 背景
+
+Transporter/TestFlight 曾报 `91109`,原因是最终 `.pkg` 内的文件带 `com.apple.quarantine` 扩展属性。`20260605.0236` 修复了 quarantine,但后续本地检查发现 `productbuild` payload 会出现 `._*` AppleDouble 条目。进一步核对后确认,在当前 macOS 环境中这些条目来自 `com.apple.provenance` 元数据;本次真正需要阻断的是 `com.apple.quarantine`。
+
+## 新包
+
+```text
+/Users/ar/Desktop/PrivateVoice-26.0604上架/02-上传包/PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg
+/Users/ar/Projects/PrivateVoice/Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg
+/Users/ar/Projects/PrivateVoice/X-运营资料/PrivateVoice-26.0604上架/02-上传包/PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg
+```
+
+SHA256:
+
+```text
+2d0e4fa7b79b70cc771086bbb124329fd4bb923849061f441d03b7391074d4cc  PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg
+```
+
+## 验证
+
+- `bash -n privatevoice.src/scripts/build-macappstore-pkg-macos.sh`: PASS
+- `git diff --check`: PASS
+- `go test ./internal/startup ./internal/model ./internal/modelselection`: PASS
+- arm64 App Store build: PASS
+- x86_64 App Store build: PASS
+- universal app merge and re-sign: PASS
+- `codesign -vvv --deep --strict`: PASS
+- `pkgutil --check-signature`: PASS
+- 展开桌面最终 `.pkg` 后检查 `com.apple.quarantine`: PASS
+- Bundle ID / version / build / category / entitlements / universal 架构: PASS
+
+## 结论
+
+如果需要替换 App Store Connect 里的 build,使用 `20260605.0353`。不要继续上传或选择 `20260605.0236` 作为最终推荐包。
diff --git a/02-P-NBL/freeze/20260605-mac-app-store-upload-preflight.md b/02-P-NBL/freeze/20260605-mac-app-store-upload-preflight.md
index da17992..b0b8117 100644
--- a/02-P-NBL/freeze/20260605-mac-app-store-upload-preflight.md
+++ b/02-P-NBL/freeze/20260605-mac-app-store-upload-preflight.md
@@ -86,8 +86,9 @@
   - `com.apple.application-identifier`
   - `com.apple.developer.team-identifier`
   - `keychain-access-groups`
-- 当前可上传包是 `20260605.0216`,不要再上传 `20260604.0049` 或 `20260604.2353`。
+- 当前可上传包是 `20260605.0353`,不要再上传 `20260604.0049`、`20260604.2353`、`20260605.0216` 或 `20260605.0236`。
 - 如果遇到 `91109`,必须在组装 app 后、签名后、productbuild 前对 `.app` 执行 `xattr -cr`,并展开最终 `.pkg` 检查没有 `com.apple.quarantine`。
+- 在当前 macOS 环境里,`productbuild` payload 可能出现由 `com.apple.provenance` 编码来的 `._*` AppleDouble 条目。不要只因为看到 `._*` 就判定为 `91109`;硬性检查目标是展开最终 `.pkg` 后没有 `com.apple.quarantine`。
 
 ## 上传后还要检查
 
diff --git "a/Docs/KM2.\351\241\271\347\233\256\347\256\241\347\220\206-\351\235\236\344\270\232\345\212\241\347\233\264\346\216\245\347\233\270\345\205\263/QA\345\267\245\344\275\234-\347\273\217\351\252\214\344\270\216\346\225\231\350\256\255.md" "b/Docs/KM2.\351\241\271\347\233\256\347\256\241\347\220\206-\351\235\236\344\270\232\345\212\241\347\233\264\346\216\245\347\233\270\345\205\263/QA\345\267\245\344\275\234-\347\273\217\351\252\214\344\270\216\346\225\231\350\256\255.md"
index 8d7307b..8363091 100644
--- "a/Docs/KM2.\351\241\271\347\233\256\347\256\241\347\220\206-\351\235\236\344\270\232\345\212\241\347\233\264\346\216\245\347\233\270\345\205\263/QA\345\267\245\344\275\234-\347\273\217\351\252\214\344\270\216\346\225\231\350\256\255.md"
+++ "b/Docs/KM2.\351\241\271\347\233\256\347\256\241\347\220\206-\351\235\236\344\270\232\345\212\241\347\233\264\346\216\245\347\233\270\345\205\263/QA\345\267\245\344\275\234-\347\273\217\351\252\214\344\270\216\346\225\231\350\256\255.md"
@@ -5,3 +5,11 @@
 - 原因:发布前 QA 门禁没有覆盖 Apple Transporter 的关键校验项,也没有形成固定预检清单。
 - 改进:以后 Mac App Store 上传包交付前,必须展开最终 `.pkg`,检查 Bundle ID、版本/build、`LSApplicationCategoryType`、profile App ID、signed `com.apple.application-identifier`、Team ID、sandbox entitlements、universal 架构、pkg 签名和包内无 `com.apple.quarantine` 扩展属性全部通过后,才交给用户上传。
 - 关联:`privatevoice.src/scripts/build-macappstore-pkg-macos.sh`、`02-P-NBL/freeze/20260605-mac-app-store-upload-preflight.md`。
+
+## 2026-06-05|不要把 provenance 的 AppleDouble 误判成 quarantine
+
+- 触发:用户追问 `20260605.0236` 是否因为 payload 里存在 `._*` AppleDouble 条目就已经是“脏包”。
+- 失误:AI 初步把 `._*` 当成需要马上阻断的发布质量问题,没有先区分它是 `com.apple.provenance` 编码还是 App Store 明确拒绝的 `com.apple.quarantine`。
+- 原因:QA 判断混淆了 macOS packaging 元数据表现形式和 Transporter `91109` 的实际拒绝条件。
+- 改进:以后检查 Mac App Store `.pkg` 时,必须展开包并检查具体 xattr 名称;`91109` 的硬拦截项是 `com.apple.quarantine`,不能仅凭 `pkgutil --payload-files` 里出现 `._*` 下结论。
+- 关联:`02-P-NBL/freeze/20260605-mac-app-store-clean-rebuild.md`、`02-P-NBL/freeze/20260605-mac-app-store-upload-preflight.md`。
diff --git a/Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/APP_STORE_CONNECT_SUBMISSION.md b/Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/APP_STORE_CONNECT_SUBMISSION.md
new file mode 100644
index 0000000..c8a58a1
--- /dev/null
+++ b/Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/APP_STORE_CONNECT_SUBMISSION.md
@@ -0,0 +1,31 @@
+# App Store Connect Submission
+
+Upload this package:
+
+```text
+/Users/ar/Desktop/PrivateVoice-26.0604上架/02-上传包/PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg
+```
+
+Use build `20260605.0353` for version `2.1.28`.
+
+Do not use older upload packages:
+
+- `20260605.0236`
+- `20260605.0216`
+- `20260604.2353`
+- `20260604.0049`
+
+SHA256:
+
+```text
+2d0e4fa7b79b70cc771086bbb124329fd4bb923849061f441d03b7391074d4cc  PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg
+```
+
+Verified:
+
+- Package signature is valid.
+- Bundle ID is `com.shanghai3168.privatevoicedictation`.
+- `LSApplicationCategoryType` is `public.app-category.productivity`.
+- Signed entitlements include `CR3J54M8BQ.com.shanghai3168.privatevoicedictation`.
+- The app executable and bundled ASR dylibs are universal `x86_64 + arm64`.
+- Expanded package has no `com.apple.quarantine`.
diff --git a/Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/RELEASE_MANIFEST.md b/Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/RELEASE_MANIFEST.md
new file mode 100644
index 0000000..6489004
--- /dev/null
+++ b/Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/RELEASE_MANIFEST.md
@@ -0,0 +1,79 @@
+# PrivateVoice Dictation 2.1.28 build 20260605.0353
+
+- Type: Mac App Store signed universal upload package
+- Platform: macOS universal, `arm64` + `x86_64`
+- Source commit: `82ce4aa571dfa74032d4697984cc932257cfa35b`
+- Source tag: `v2.1.28-build20260605.0353-appstore-upload`
+- Branch: `codex/privatevoice-freeze-2.1.25`
+- Created: 2026-06-05 04:07 HKT
+
+## Purpose
+
+This build replaces `20260605.0236` after local package inspection showed macOS provenance metadata being encoded into AppleDouble payload entries and after the App Store/TestFlight `91109` quarantine failure. The hard App Store blocker is `com.apple.quarantine`; this build verifies the final expanded package has no quarantine extended attribute.
+
+## Build Inputs
+
+- Bundle ID: `com.shanghai3168.privatevoicedictation`
+- Version: `2.1.28`
+- Build: `20260605.0353`
+- Category: `public.app-category.productivity`
+- Team ID: `CR3J54M8BQ`
+- App signing identity: `0D7D5484FDE4EC1CA2C9225F1E71E65A256A1E7C`
+- Installer signing identity: `3rd Party Mac Developer Installer: Hainan Wanxing Technology Co., Ltd. (CR3J54M8BQ)`
+- Provisioning profile: `X-运营资料/PrivateVoice-26.0604上架/01-证书/PrivateVoice_Dictation_Mac_App_Store.provisionprofile`
+
+## Commands
+
+```bash
+bash -n privatevoice.src/scripts/build-macappstore-pkg-macos.sh
+git diff --check -- privatevoice.src/scripts/build-macappstore-pkg-macos.sh privatevoice.src/app.go privatevoice.src/build/darwin/Info.plist
+go test ./internal/startup ./internal/model ./internal/modelselection
+
+PRIVATEVOICE_MACAPPSTORE_BUILD_ROOT=/Users/ar/Projects/PrivateVoice/privatevoice.src/build/macappstore-final-20260605.0353 \
+  ./privatevoice.src/scripts/build-macappstore-pkg-macos.sh arm64
+
+PRIVATEVOICE_MACAPPSTORE_BUILD_ROOT=/Users/ar/Projects/PrivateVoice/privatevoice.src/build/macappstore-final-20260605.0353 \
+  ./privatevoice.src/scripts/build-macappstore-pkg-macos.sh x86_64
+```
+
+The final universal app was assembled from the signed arm64 and x86_64 app bundles with `lipo`, then re-signed with the App Store entitlements and packaged with `productbuild`.
+
+## Verification
+
+- `bash -n privatevoice.src/scripts/build-macappstore-pkg-macos.sh`: PASS
+- `git diff --check`: PASS
+- `go test ./internal/startup ./internal/model ./internal/modelselection`: PASS
+- arm64 App Store package build: PASS
+- x86_64 App Store package build: PASS
+- universal app merge and re-sign: PASS
+- `codesign -vvv --deep --strict` universal app: PASS
+- `pkgutil --check-signature` universal pkg: PASS
+- Final expanded desktop pkg has no `com.apple.quarantine`: PASS
+- Bundle ID: `com.shanghai3168.privatevoicedictation`
+- `CFBundleShortVersionString`: `2.1.28`
+- `CFBundleVersion`: `20260605.0353`
+- `LSApplicationCategoryType`: `public.app-category.productivity`
+- signed `com.apple.application-identifier`: `CR3J54M8BQ.com.shanghai3168.privatevoicedictation`
+- signed `com.apple.developer.team-identifier`: `CR3J54M8BQ`
+- app executable: universal `x86_64 + arm64`
+- `libsherpa-onnx-c-api.dylib`: universal `x86_64 + arm64`
+- `libonnxruntime.1.24.4.dylib`: universal `x86_64 + arm64`
+
+## Artifacts
+
+```text
+Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg
+/Users/ar/Desktop/PrivateVoice-26.0604上架/02-上传包/PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg
+/Users/ar/Projects/PrivateVoice/X-运营资料/PrivateVoice-26.0604上架/02-上传包/PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg
+```
+
+## SHA256
+
+```text
+2d0e4fa7b79b70cc771086bbb124329fd4bb923849061f441d03b7391074d4cc  PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg
+```
+
+## Notes
+
+- Do not upload `20260605.0236` if this replacement build is available.
+- macOS `com.apple.provenance` may appear as AppleDouble `._*` entries in `pkgutil --payload-files`; do not treat that alone as the `91109` failure. The required rejection check is that the expanded final pkg contains no `com.apple.quarantine`.
diff --git a/Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/SHA256SUMS.txt b/Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/SHA256SUMS.txt
new file mode 100644
index 0000000..2ebd251
--- /dev/null
+++ b/Release/PrivateVoice-Dictation-2.1.28-build20260605.0353/SHA256SUMS.txt
@@ -0,0 +1 @@
+2d0e4fa7b79b70cc771086bbb124329fd4bb923849061f441d03b7391074d4cc  PrivateVoice-Dictation-2.1.28-build20260605.0353-universal-macappstore.pkg

--
Gitblit v1.9.3