Imported from mrc-labs/PlayStoreAppAudit (
AGENTS.md). Install upstream withnpx skills add mrc-labs/PlayStoreAppAudit. Copyright stays with the author.
AGENTS.md
Project
Play Store App Audit is a Python desktop application that audits Android package IDs against public Google Play listings and, optionally, enriches results from an Android device through ADB.
The production UI is Qt 6 / PySide6 Qt Widgets. The former CustomTkinter implementation is retired and preserved only as the historical Git tag legacy-customtkinter-v9.3.
Durable engineering decisions live in docs/PROJECT_DECISIONS.md. Current shipped/development state lives in docs/PROJECT_STATUS.md. Forward-looking release/feature planning lives in docs/ROADMAP.md. The detailed release procedures live in docs/BUILDING.md. Permanent release-closure and local VS Code synchronization requirements live in docs/RELEASE_CLOSURE.md. Mandatory twice-per-release latest-stable component verification lives in docs/RELEASE_COMPONENT_FRESHNESS.md. GitHub Actions retention and post-release housekeeping live in docs/CI_MAINTENANCE.md. The canonical GitHub Release body structure and historical normalized release-note wording live in docs/RELEASE_NOTES.md.
When old version-specific scheduling language in an operational document conflicts with the current roadmap, preserve the operational procedure but follow PROJECT_DECISIONS.md and ROADMAP.md for the current milestone assignment. Historical release wording in CHANGELOG.md and RELEASE_NOTES.md is not rewritten to match later roadmap changes.
Architecture
All production application code belongs under playstore_app_audit/:
playstore_app_audit/app.py: application entry point only.playstore_app_audit/domain/: typed domain models and pure business concepts.playstore_app_audit/services/: Play Store, audit, cache/history/report service boundaries.playstore_app_audit/devices/: ADB/device integration.playstore_app_audit/platform/: Windows/macOS/Linux abstraction.playstore_app_audit/ui/: Qt Widgets UI only.
The version-suffixed top-level Qt and feature modules have been removed. Internal Qt layers use descriptive package module names such as base_window, audit_window, device_window, preferences_window and results_window, with main_window.py as the public UI entry point.
Do not reintroduce cross-module runtime monkey-patching for audit selection, classification, cache bypass or ADB metadata enrichment. Keep extension points explicit and local.
The UI still uses a layered inheritance structure for proven behaviour. Reduce it incrementally only where composition or smaller focused widgets/controllers clearly improve maintainability. Do not combine a large behavioural rewrite with a structural migration.
UI code must not implement Google Play parsing, cache persistence, ADB discovery/download logic or OS detection directly.
Runtime and dependencies
- Current development Python/Quality baseline: rolling stable Python 3.14 with
check-latest: trueand fail-closed stable major/minor checks. Immutable v2.2 release Python is exact 3.14.8. Immediately before every future release SHA freeze, pin and verify one audited full patch again; seedocs/RELEASE_COMPONENT_FRESHNESS.mdand the historicaldocs/V2_2_FINAL_PRE_RELEASE_FRESHNESS.md. - Current PySide6 baseline:
PySide6-Essentials==6.11.2. - Current release compiler pin:
Nuitka==4.2.2. - Runtime, development and build dependency pins must reflect the latest stable compatible versions verified by the mandatory release freshness gate and its explicit ownership/compatibility categories.
- Python pre-releases, including Python 3.15 release candidates, are not stable release baselines unless a deliberate engineering decision changes the policy.
- UI technology: Qt Widgets, not QML unless a demonstrated UX, maintainability or performance reason justifies migration.
- Keep
google-play-scraperbehind a service boundary because it is unofficial and replaceable. - HTTP fallback uses
requests+ BeautifulSoup with Python's built-inhtml.parser; do not re-addlxmlwithout a measured need.
Avoid adding libraries for functionality available cleanly in the Python standard library or Qt Essentials.
Correctness rules
- Never use Google Play
datePublishedas the latest update date. Only update-specific fields such asdateModified, explicitupdated, or visibleUpdated ontext are valid. - A package unavailable in one Store country is not automatically globally removed. Preserve multi-country fallback logic and uncertainty states.
- Maintenance Score is the user-facing name for the maintenance heuristic; the compatibility-sensitive internal identifier remains
health_score. It is not a malware/security score. - A different installed/store version is not automatically outdated; device-specific or staged rollouts are possible.
- ADB operations remain read-only with respect to installed Android applications unless a future change is explicitly approved.
UX rules
- The Basic view must remain compact and understandable to non-expert users.
- Advanced settings remain behind the Tools menu and should warn users before changing technical behaviour.
- Presentation-only actions, including changing View presets, must not overwrite the more relevant audit/progress/status message.
- Avoid adding vertical UI sections when an existing row, menu or dialog can contain the feature cleanly.
- Status chips above the table support multi-selection.
- Production startup uses Qt's platform/default QStyle. Do not globally force Fusion or add a theme dependency without new cross-platform evidence.
Cross-platform rules
All feature code should work on Windows, macOS and Linux unless the feature is inherently platform-specific.
Put platform-specific behaviour behind playstore_app_audit.platform or playstore_app_audit.devices, including:
- Platform-Tools download URL and executable name
- app-data directories
- Store-country detection
- subprocess console hiding
- icon/bundle handling
- packaging/signing
Do not hard-code adb.exe, %LOCALAPPDATA%, Windows-only SDK paths or Windows-only console flags in shared UI/service code.
v2.2.0 published baseline and closure
v2.2.0 was published 2026-10-02 and is immutable at 21b6646571b7e93044b76fe4d18a04eeec092f18; annotated tag object 95a402b25f65bf22db58f831076bca747e2c9103, GitHub Release ID 401714084. Its three shipped pillars are source-aware independent Custom layouts, the persistent privacy-safe Personal Device profile library and CLI/headless audit mode; Sponsors is integrated. The exact release toolchain is Python 3.14.8, PySide/Shiboken/Qt 6.11.2 and Nuitka 4.2.2. Linux uses Ubuntu 24.04 build hosts on both architectures, with x64 Ubuntu 22.04 packaged GUI/CLI backward smoke passed; macOS uses macOS 26/Xcode 26.6. Windows/Linux are unsigned; macOS is engineering ad-hoc signed only, without Developer ID signing or notarization.
Canonical Quality 36987000922, Windows 36988301118, Linux 36988304138, macOS 36988307201 and assembly 36993205418 all passed on attempt 1 at the exact release SHA. Exactly eight assets were independently re-downloaded and verified by names, sizes, SHA-256 and byte identity. Do not rebuild, retag or replace them. Current source version remains 2.2.0; PR #222 restored rolling stable Python 3.14 development tracking at post-release baseline fec702dace16efc96d4d0c072acd97bd0f13a90f, with Quality #641 / 37019239185 SUCCESS. Public repository/About/README reconciliation and local Docker hygiene are complete. Issue #212 is closed as completed after final local synchronization and closure confirmation. Active v2.3 planning is tracked by #225 with #188 for Play Store Category plus installer_category cleanup, #147 for a maximum of 3 Named Custom Views per source family, and #224 for conservative Duplicate APK management. #154 and #209 remain deferred outside v2.3. See docs/V2_2_POST_RELEASE_CLOSURE.md, docs/PROJECT_STATUS.md and docs/ROADMAP.md.
Proactively migrate concretely announced deprecations when a stable supported successor preserves all six targets and intended compatibility floors and can be validated in the active release cycle. Preview successors and implicit floor increases are excluded; classify blockers, required migrations, watches and upstream observations explicitly.
Release invariants
These are hard constraints unless deliberately changed through a dedicated engineering decision:
mainis the only permanent branch. Use short-lived branches and normal PR merge commits.- Published release source commits, annotated tag targets and binary/source/checksum assets are immutable. GitHub Release descriptive prose may be corrected, clarified or condensed when historical facts and release semantics remain unchanged; editorial maintenance never authorizes rebuilding, retagging or replacing assets.
- Every release must run the complete component freshness gate twice: once at release-phase entry and again immediately before the final exact-SHA freeze. Audit the complete maintained release toolchain using the ownership categories in
docs/RELEASE_COMPONENT_FRESHNESS.md: latest stable compatible directly controlled components, supported parent bundles, current supported vendor integrations, and supported OS/compiler baselines preserving all six targets and binary compatibility floors. Record embedded versions and evidenced upstream observations; applicable security/support issues remain blockers. - If either freshness gate finds a newer stable compatible component under repository control, update it and repeat every affected source, package, legal, signing and platform validation before release work continues. Compatibility exceptions require concrete target-matrix evidence, not preference or validation cost. Before final SHA freeze, use and fail-closed verify one exact audited Python patch across release-producing workflows and final Quality; development
3.14/check-latesttracking is not a frozen toolchain contract. - A release profile freezes one exact full
mainSHA after Quality CI passes. - Build workflows must reject mismatches between expected SHA, dispatch SHA and checked-out SHA.
- Do not create public RC tags.
- Release-tag pushes must not rebuild binaries. Publish the already validated artifacts.
- If source or release tooling changes after the SHA is frozen, discard and rebuild every candidate required by the selected release profile from the new exact SHA. Never mix artifacts from different SHAs.
- Do not weaken legal/source validation to make a build pass.
- Do not delete files under
.github/scripts/merely because there are several. Verify workflow references, imports and tests before removal. - GitHub Actions retention follows the generational policy in
docs/CI_MAINTENANCE.md; failed/cancelled runs never replace successful generations. - Every public GitHub Release body follows
docs/RELEASE_NOTES.md: the four mandatory sections areWhat's New / Highlights,Compatibility and distribution,Release assets, andVerification, in that exact order.Added,Changed, andFixedare the standard optional subheadings insideWhat's New / Highlightsand empty subheadings are omitted. - When normalizing an already published release, the body actually published on GitHub is the primary historical source. Changelog/docs may supplement only clearly supported missing details and must not silently replace or strengthen the historical claims.
- Obvious editorial mistakes in historical prose may be corrected during normalization only when the release/tag identity is unambiguous and the substantive meaning is unchanged.
- Release-note prose is editorially maintainable after publication, but this never authorizes changing an immutable published tag, source commit, binary/source asset, checksum file, distribution state or verification claim.
- Every release must finish the permanent closure procedure in
docs/RELEASE_CLOSURE.md. Publishing alone is not release completion: post-release context Markdown must be reviewed/updated, the local VS Code checkout must be synchronized safely to canonicalmain, the local tree/SHA must be verified, and any new handoff must be generated only from that clean synchronized state.
Permanent release closure and VS Code sync
For every current and future release:
- review and update all maintained project-context Markdown whose facts changed, including the current version-specific handoff;
- verify the live GitHub repository/About description, homepage, topics and rendered README; file reconciliation alone is insufficient;
- review local Docker resources read-only, separately from intentional CI Ubuntu 22.04 compatibility containers; delete no ambiguous/shared resources;
- keep release history and the newer post-release
maincontext clearly distinguished; - before any local pull run
git status --short; if dirty, stop and never reset/stash/discard automatically; - on a clean local VS Code checkout use
git fetch --prune origin, switch tomain, and usegit pull --ff-only origin main; - verify the clean local
HEADequals the expected canonical post-release/documentation SHA; - generate
REPOSITORY_SNAPSHOT.mdand chat/continuation handoffs only after that synchronization; - do not call the release cycle closed until remote repository state, local VS Code state and context documentation agree.
The full checklist and rationale are canonical in docs/RELEASE_CLOSURE.md and apply to v1.7, v1.8, v1.9, v1.99, v2.0 and every later release line.
v1.4 Windows x64 Engineering Test Build (ETB) profile
v1.4 is intentionally a public Windows x64 Engineering Test Build (ETB).
- Build Windows x64 only from the frozen SHA.
- Use
.github/workflows/build-windows-exe.ymlwithtarget=x64. - Do not invoke
.github/workflows/sign-windows.ymlfor v1.4. - Do not build Windows ARM64, Linux or macOS release candidates for v1.4.
- Assemble with
.github/workflows/assemble-windows-engineering-release.yml. - The engineering assembler must accept only the successful unsigned Windows x64
Build Windows - Qt6run from the same repository and exact SHA and must reject ARM64 input. - The public asset set is exactly three files: Windows x64 ZIP, one consolidated third-party source
tar.xz, and oneSHA256SUMS.txt. - Engineering GitHub Releases use title suffix
(ETB Win x64); the release-body heading identifiesEngineering Test Build - Windows x64 Only; the package must be clearly described as unsigned.
v1.5 Windows x64 Engineering Test Build (ETB) profile
v1.5.0 remains an unsigned Windows x64 Engineering Test Build (ETB).
- Build Windows x64 only from the frozen SHA.
- Use
.github/workflows/build-windows-exe.ymlwithtarget=x64. - Do not invoke
.github/workflows/sign-windows.ymlfor v1.5. - Do not build Windows ARM64, Linux or macOS release candidates for v1.5.
- Assemble with
.github/workflows/assemble-windows-engineering-release.yml. - The public asset set is exactly three files:
PlayStoreAppAudit-v1.5.0-windows-x64.zip,PlayStoreAppAudit-v1.5.0-third-party-sources.tar.xz, andSHA256SUMS.txt. - Use GitHub Release title suffix
(ETB Win x64)and release-body heading## Play Store App Audit v1.5.0 (Engineering Test Build - Windows x64 Only). - Keep the package clearly described as unsigned. Do not spend money on signing for v1.5.
v1.6 Windows x64 Engineering Test Build (ETB) profile
The v1.6.0 release profile is frozen as an unsigned Windows x64 ETB. Product scope is closed for the release candidate.
- Canonical application version is
1.6.0. - Build Windows x64 only from the exact frozen
mainSHA after the post-merge Quality gate passes. - Use
.github/workflows/build-windows-exe.ymlwithtarget=x64. - Do not invoke production Windows signing or macOS production signing/notarization for v1.6.
- Do not build Windows ARM64, Linux or macOS release candidates for v1.6.
- Assemble with
.github/workflows/assemble-windows-engineering-release.yml. - The public asset set is exactly
PlayStoreAppAudit-v1.6.0-windows-x64.zip,PlayStoreAppAudit-v1.6.0-third-party-sources.tar.xz, andSHA256SUMS.txt. - The current GitHub Release title is
Play Store App Audit v1.6.0 (Win x64 Only); the body heading remains## Play Store App Audit v1.6.0 (Engineering Test Build - Windows x64 Only). - Keep the package clearly described as unsigned.
- Do not add the optional richer dashboard/summary to v1.6.0.
- If source or release tooling changes after the exact release SHA is recorded, discard that candidate SHA and rebuild the required ETB artifacts from the new exact SHA.
v1.7-v1.99 Windows x64 Engineering Test Build (ETB) profile
v1.7.0, v1.8.0, v1.9.0 and v1.99.0 are published and immutable as unsigned Windows x64 ETBs.
- Build Windows x64 only from one exact frozen
mainSHA after the required Quality gates pass. - Use
.github/workflows/build-windows-exe.ymlwithtarget=x64. - Do not invoke production Windows signing or build Windows ARM64, Linux or macOS release candidates for v1.8, v1.9 or v1.99.
- Assemble with
.github/workflows/assemble-windows-engineering-release.yml. - Publish exactly three project-defined assets: the Windows x64 ZIP, one consolidated third-party source
tar.xz, andSHA256SUMS.txt. - Current/future Windows x64 ETB GitHub Release titles use suffix
(Win x64 Only); the release-body heading still identifiesEngineering Test Build - Windows x64 Onlyand the package remains clearly described as unsigned. - v1.7.0 is frozen at
e2d09098bc42c6f16d202d010deda3eb24d99aa3. Do not rebuild, retag or replace it. - v1.8.0 is frozen at
ac328f0dffddb6b70fa7600f1291377376bc05d4. Do not rebuild, retag or replace it. - v1.9.0 is frozen at
6c117009525f40434e9db714dadf1dd01b79f9ab. Do not rebuild, retag or replace it. - v1.99.0 is frozen at
1065744488e548663e3ba365566a9932837f5fb5. Do not rebuild, retag or replace it. - v1.99's additional real packaged Windows x64 acceptance requirement was satisfied by RC8; its accepted package remains historical evidence and is not the immutable final release artifact.
v1.99 product guardrails
v1.99 is feature complete, published and immutable as the final planned Windows x64-only release before v2.0. Preserve its shipped product scope while later development moves to v2.0 planning.
- Preserve the implemented cooperative Stop/Cancel lifecycle across the real audit pipeline. Never use
QThread.terminate()or another unsafe forced-termination mechanism. Preserve completed valid results and independent cache entries, mark the audit cancelled/incomplete, do not promote it to the completed history baseline, and return to a reusable idle state. - Preserve the accepted C2 operations header: Run/Pause/Resume, Stop, the canonical always-present progress widget, Export Results and Clear Results in that order. The second header row keeps status chips, Hide System Apps, search and the single Details selector. Details continues to reuse the same Auto/Right/Below/Hidden state and View-menu synchronization; do not duplicate state or move operational status text out of the native status bar.
- Preserve the semantic warning hierarchy across the table, Details surfaces and HTML report:
DifferentandAging targetreuse the status palette's dark-yellow foreground with DemiBold 600 emphasis;Legacy targetreuses dark orange with DemiBold 600 emphasis;Modernremains Regular 400 and the Status column remains Bold 700. The selection background remains Qt-managed, with warning colours chosen for both selected and unselected readability, and machine-readable values remain unchanged. - Alternative Distribution Discovery is informational exact-package-ID evidence, not endorsement or an automatic equivalent-app association. v1.99 automatic checks are limited to F-Droid main and optional authorized Aptoide, require conclusive eligible Google Play evidence and must not run for transient, scraper or ambiguous failures. The remaining providers in the limitations panel are not implemented.
- The v1.99 Maintenance Score update applies
-60only for rawplay_status == "not_found_in_checked_countries", then recovers+10for current conclusive F-Droid main availability and+5for current conclusive Aptoide availability. Recovery is cumulative, deduplicated, limited to the current+15provider mapping and disabled unless the-60component is active; it is never an unconditional multi-store bonus. Store anomaly is-20; Other/inconclusive is-15; stale/aging freshness is-25/-15; legacy/aging target SDK is-15/-10; installed/store difference is-5. Regional unavailability is not definitive absence. Scores remain clamped to 0-100 andhealth_scoreremains the compatibility identifier. - The internal
health_scorerename did not ship in v2.1. It remains a separate, unassigned compatibility migration and is not implied by the scoring update. QDockWidgetis rejected and not planned. Retain the Details Panel's Auto/Right/Below/Hidden placement and narrow/wide/extra-wide responsiveness.- Do not add Local APK Audit functionality in v1.99. Begin v2.0 with a parser/verifier spike, then a typed
LocalArtifactmodel with SHA-256 artifact identity and package-deduplicated Store/provider fan-out before implementing Local APK Audit and the persistent Local APK Library core. - A richer dashboard is not part of v1.99 or required for the v2.0 core. Revisit it in later v2.x or v3.0 only when multiple mature sources and longitudinal/history workflows justify it.
v2.0-and-later six-platform profile
v2.0 established the full multi-platform release architecture. Production signing remains a preferred later target, but it must not be promised until provider eligibility, credentials, cost and end-to-end signing/notarization validation are confirmed.
- Windows x64/ARM64, Linux x64/ARM64 and macOS x64/ARM64 final candidates must all come from the same frozen SHA.
- Windows final candidates require a publicly trusted code-signing provider with native post-sign verification.
- macOS final candidates require Developer ID Application signing, hardened runtime, notarization, stapling and Gatekeeper verification.
- Linux production packaging remains Nuitka standalone, not onefile, with replaceable Qt/PySide/Shiboken shared libraries.
- Assemble with
.github/workflows/assemble-release.ymlonly after all six final candidates validate. - The full production public asset set is exactly eight files: six platform ZIPs, one consolidated third-party source
tar.xz, and oneSHA256SUMS.txt. - Local APK analysis is a major v2.x product pillar. v2.0 introduced explicit local APK/container files and recursive folder discovery; v2.1 added safe single-file and mass file management. A separate persistent library-management UI and duplicate management remain later work.
v2.1.0 immutable release profile
v2.1.0 is published and immutable at df2726b959963e5dbb096638d5072bd15eb1de92.
- Public assets are exactly six platform ZIPs, one consolidated third-party source
tar.xz, andSHA256SUMS.txt. - Windows x64/ARM64 and Linux x64/ARM64 are unsigned.
- macOS x64/ARM64 use ad-hoc engineering signing only and are not Developer ID signed or notarized.
- Canonical final runs are Quality
35775208797, Windows35776095408, Linux35776120755, and macOS35776146620. - The public assets passed clean re-download, size, SHA-256, and byte-for-byte verification. Do not rebuild, retag, move, or replace them.
v1.3.0 at commit fb2193dfc13d0f0e6b7be660c1342bbf87d26081 is already published and immutable. Do not rebuild, retag or replace its artifacts.
Tests and validation
For source-code changes, complete the normal cheap Quality checks before considering the change ready:
python -m compileall playstore_app_auditpython -m pytestruff check playstore_app_audit tests main.py- Run the Qt offscreen smoke test used by CI.
Add regression tests for bugs before or together with the fix when practical.
For workflow or packaging changes, run targeted static/unit validation first. Trigger expensive Nuitka package builds only when the change genuinely requires package evidence.
For release candidates, compiler success is not sufficient. Validate package contents, architecture, version, startup behaviour, legal material and release provenance as documented in docs/BUILDING.md.
Ruff exceptions for inherited Qt patterns are intentionally narrow and configured per-file in pyproject.toml. Prefer removing an exception when relevant code is modernised rather than broadening the global ignore list.
Git workflow
mainis the single canonical permanent branch.- Use short-lived
feature/,fix/,refactor/,docs/,release/oragent/branches, merge them back with normal PR merge commits, then delete them. - Keep maintenance work scoped. Documentation cleanup, workflow restructuring, signing, API migrations and UI redesign should not be bundled without a release-engineering reason.
- Do not create permanent branches per operating system.
- Historical implementations belong in Git tags, not live maintenance branches.
Dependency/API evolution
- Replace APIs that are already deprecated or scheduled for deprecation when semantics are understood.
- Evaluate documented preferred replacements when behaviour is equivalent and migration risk is low.
- Do not rewrite stable supported APIs merely because they are old.
- The application itself does not use Node. Follow official GitHub Action majors when their maintainers move bundled runtimes; do not add
setup-nodejust to chase a newer Node LTS.
Style
- Use type annotations on new code.
- Prefer
dataclass(slots=True)andEnum/StrEnumfor stable domain structures instead of open-ended dictionaries when introducing new APIs. - Keep side effects at the edges: UI, filesystem, network and subprocess.
- Prefer small focused modules over new version-suffixed files.
- Do not create
*_v10.py,*_fixed.pyor*_stable.pyfiles for normal evolution. Change canonical package modules and rely on Git history/tags for versions.
