Validation and release qualification
September 13, 2026 ยท View on GitHub
This document describes the repeatable build, installation, and device-validation procedure for a supported target. It is a procedure, not a record of a previous run. Record the result and provenance for each run in the release or pull-request record.
Run manual end-to-end validation on a throwaway account where an account is required. A re-signed build with a VPN/proxy on a real account may create account risk; see lessons learned. Use the version and package metadata defined by the target compatibility constants.
Build validation
Run the repository tests and build the Android bundle:
./gradlew :patches:test buildAndroid --no-daemon
python3 -m unittest discover -s scripts/tests -v
Shell, shfmt, and workflow lint are covered by the pre-commit gate in Verify;
do not rerun shellcheck or actionlint separately here.
The bundle is written to patches/build/libs/patches-*.mpp. Successful Check
runs retain a patches-<sha>-<attempt> artifact for seven days. Record the
run/commit and downloaded bundle hash. CI artifacts are test builds, not releases.
Optional local target validation against the original pinned APK's extracted
base.apk is analysis-only. Use the target-specific test command and environment
variable documented by that target. Tests must not commit or download proprietary
APKs.
Re-patch and install
Patch and install the selected input APK explicitly:
MPP="patches/build/libs/patches-<version>.mpp" \
python3 scripts/repatch.py /path/to/input.apkm /tmp/patched.apk
adb install -r /tmp/patched.apk
Only update an existing installation when its signing certificate matches.
For startup isolation, repatch.py accepts a strict comma-separated patch
allow-list. Start with a minimal control, then enable the target's patches
incrementally; install and cold-start each control before enabling the next patch:
PATCHES='' python3 scripts/repatch.py /path/to/input.apkm /tmp/control-0.apk
PATCHES='<first patch>' python3 scripts/repatch.py /path/to/input.apkm /tmp/control-1.apk
PATCHES='<first patch>,<second patch>' python3 scripts/repatch.py /path/to/input.apkm /tmp/control-2.apk
PATCHES disables every bundle patch not named and rejects unknown names, so a
control cannot silently include default-on patches.
Release qualification includes one SDK-verified re-patch. Compilation alone only proves that the toolchain ran because the patcher verifier defaults to existence checks:
MPP="patches/build/libs/patches-<version>.mpp" VERIFY_SDK=1 \
python3 scripts/repatch.py /path/to/input.apkm /tmp/verified.apk
VERIFY_SDK=1 uses $ANDROID_HOME, then $ANDROID_SDK_ROOT, then the OS-default
SDK location. Set VERIFY_SDK=/path/to/sdk to pin a specific SDK. Record the
verification result with the bundle and input hashes.
If every available toolchain reproduces an internal D8 error that is not a patch error, the owner may waive verification after device validation. Record the waiver, toolchain versions, and device evidence in lessons learned, and revisit it when Morphe fixes the verifier. Do not block a release indefinitely on a broken verifier.
Device validation scope
Validate the following areas and record each as PASS, FAIL, or BLOCKED with concise evidence:
- Manifest and package metadata match the intended target, including removal of permissions targeted by a patch.
- Splash launch, cold start, background/kill/resume, and lifecycle behavior.
- Existing-session and fresh-login behavior separately; preserve existing data unless the test plan explicitly authorizes a reset.
- Every enabled patch has a positive behavior check and a negative/control check.
- Inputs, navigation, network-dependent screens, notifications, media, and relevant background work remain functional.
- Messaging and calling, including one-to-one chats, group messaging, and VoIP.
- Notification delivery while the app is in the background.
- Target ad surfaces remain patched without crashes.
- Launch-time missing-provider guidance allows cancellation without blocking use.
- Provider-backed authentication: account selection, transport, token issuance, and feature access are assessed separately. Record upstream OAuth attestation failures as BLOCKED, not as patch failures.
- Provider-backed restore, including initial media restore and a complete backup / restore cycle where supported.
- Optional renamed-package/coexistence behavior when supported by the target and its signing/OAuth configuration.
If a provider is absent, the app should provide installation guidance without blocking normal use. Keep request logs bounded and redact credentials and tokens. Do not promote a stable release while required validation remains blocked.
Record input APK version/code and hash, bundle path/hash, enabled patches, package ID, device/Android version, and signing certificate fingerprint. Never record passwords. Keep screenshots, UI dumps, and logs outside Git; retain sanitized notes in the release or PR record.
Provider boundaries
Treat provider transport, account selection, token issuance, and upstream authorization as separate gates. A successful picker or IPC request does not prove that the provider accepts the patched package and signing certificate. Record upstream attestation failures as BLOCKED, not as patch failures, and keep credentials and tokens out of logs.
Version update qualification
For every newly supported version:
- Confirm fingerprints resolve uniquely and the target ABI remains compatible.
- Confirm each patch target still has the intended semantics; a matching signature alone does not prove behavior.
- Repeat build validation through device/regression validation before updating target version metadata.