Repository navigation
feat(skill): make aso_skill a real, tested, installable Python package - #10
Conversation
|
Invalid PR source PRs to Current source: Please:
|
|
Large PR alert: this PR has 10642 changes. Consider splitting it into smaller PRs (<200 changes) for faster review and fewer conflicts. |
|
Large PR alert: this PR has 10645 changes. Consider splitting it into smaller PRs (<200 changes) for faster review and fewer conflicts. |
|
Merge conflict detected This branch has conflicts with git fetch origin
git rebase origin/dev
# Resolve conflicts, then:
git rebase --continue
git push --force-with-lease |
This is foundation-only work. There are no agent-contract changes -- the four
slash commands, the outputs/[app-name]/ folder layout, and every legacy file
path inside app-store-optimization/ and .claude/skills/aso/ continue to work
unchanged via symlinks.
The change in one sentence: rename the canonical source from the
hyphenated, un-importable app-store-optimization/ directory to a proper
aso_skill/ Python package, add a pytest suite, expose an aso CLI, fix the
hardcoded reference date in load-bearing agent prompts, end the drift
between the duplicate skill copies, and add a 24h iTunes cache.
Why this is needed:
- Before: app-store-optimization/ was not a valid Python identifier so the
package declared in pyproject.toml could not actually be pip-installed.
None of the eight analytic modules had a __main__ block, which meant
the agent prompt at aso-strategist.md:932 ('python3 aso_scorer.py < ...')
was broken in main. The duplicate copy under .claude/skills/aso/ had
silently drifted from app-store-optimization/. The reference date
'2025-11-07' was hard-coded into the strategist and prelaunch prompts.
- After: import aso_skill works, pip install -e . works, the aso CLI
works, the agent contract works, and the duplicate is a symlink so drift
is structurally impossible.
Highlights:
- aso_skill/ holds the canonical .py files; app-store-optimization/*.py
and .claude/skills/aso/ are symlinks back into it.
- aso CLI exposes score / optimize / validate / keywords / ab-test /
checklist / itunes subcommands. All read JSON from --input or stdin,
write JSON to --output or stdout. Validate exits 1 on character-limit
violations, 0 otherwise.
- 50 pytest tests cover the math (scorer, A/B significance, character
limits), the CLI (subprocess invocations), iTunes cache behaviour, and
a regression guard against the hardcoded date.
- iTunes file cache at $XDG_CACHE_HOME/aso-skill/itunes/, 24h TTL by
default, ASO_ITUNES_NO_CACHE=1 to bypass, stale-fallback on network
failure.
- Stdlib only -- pytest is the lone optional dependency
(pip install '.[test]').
- scripts/materialize_compat.py replaces the symlinks with real copies
for Windows / ZIP-extract users whose filesystem doesn't support them.
CI:
- python-quality.yml now lints aso_skill scripts tests instead of the
hyphenated path, installs the package with the test extra, and runs
pytest across the existing 3.8-3.13 matrix.
https://claude.ai/code/session_01CbA3Mp4rD4vW9Yjd2aPEXw
- scripts/materialize_compat.py: use os.readlink instead of Path.readlink (Path.readlink is Python 3.9+; we target 3.8+). - aso_skill/itunes_cache.py: drop unused _CACHE_DIR_NAME global; add explanatory comments on the two best-effort empty excepts (failure paths must not propagate through to callers). - tests/test_itunes_cache.py: use a single 'from aso_skill import itunes_cache' instead of both 'import' and 'from import' forms. https://claude.ai/code/session_01CbA3Mp4rD4vW9Yjd2aPEXw
The build-system declared setuptools>=82.0.1 (from an earlier dependabot PR) but setuptools 80+ dropped Python 3.8 support. The 3.8 matrix entry was passing before this PR because the workflow only ran ruff -- now that we install the package with pip install -e ".[test]" the 3.8 build fails with "package requires a newer Python". Aligning the project's advertised support window with the actual buildable matrix: requires-python = >=3.9, drop the 3.8 classifier and matrix entry, bump ruff target-version and mypy python_version accordingly. Python 3.8 reached EOL in October 2024. https://claude.ai/code/session_01CbA3Mp4rD4vW9Yjd2aPEXw
Code Review — PR #10:
|
| Area | Tests | Quality |
|---|---|---|
| Character limits (Apple + Google) | test_metadata.py (12 tests) |
✅ Exhaustive boundary tests |
| Scorer math | test_scorer.py (9 tests) |
✅ Zero-input, high-input, weight sum |
| A/B significance | test_ab_test.py |
z_beta path |
| CLI subprocess | test_cli.py |
✅ Exit codes, stdin/stdout |
| iTunes cache | test_itunes_cache.py (6 tests) |
✅ Cache hit, bypass, TTL, stale fallback |
| Legacy path compat | test_golden.py |
✅ python3 app-store-optimization/aso_scorer.py |
| Date regression | test_dates.py |
time.sleep(1.1) in test_expired_entry_refetches and test_network_failure_falls_back_to_stale_cache is acceptable since the overall suite runs in <3s, but consider monkeypatch on time.time() if CI flakiness emerges.
Summary
Merge blockers:
- Verify
z_betais defined after removingbeta = 1 - power; add a direct test forcalculate_sample_sizeif not covered - Add
required=Truetoitunessubparser
Should fix before merge:
3. Broaden test_dates.py regex to catch any hardcoded date, not just Nov 7 2025
4. Update CLAUDE.md to remove stale dual-copy references
Nice to have:
5. Add aso-optimizer.md to test_dates.py load-bearing prompts list
6. Replace write-probe with tempfile approach in ITunesCache._ensure_writable
7. Consistent from __future__ import annotations across new modules
The core refactor is well-structured and the backwards-compatibility story is solid. Once the z_beta question is resolved and CLAUDE.md is updated, this is ready for a non-draft review.
d00aacd to
4e3cb48
Compare
|
Large PR alert: this PR has 10658 changes. Consider splitting it into smaller PRs (<200 changes) for faster review and fewer conflicts. |
Code Review — PR #10: Make
|
| Category | Status |
|---|---|
| Packaging fix (importable package) | ✅ |
| Backward compat via symlinks | ✅ |
__main__ blocks added |
✅ |
| Hardcoded dates fixed + regression test | ✅ |
| iTunes 24h TTL cache | ✅ |
| 50 tests, runs in <3s | ✅ |
| CLI with correct exit codes | ✅ |
| CLAUDE.md updated | ❌ Blocker |
beta removal in ab_test.py |
|
| CI char-limit grep pattern | |
| Apple promo text test coverage |
Three issues to resolve before merge, then this is solid foundation work.
|
Branch |
Summary
Foundation-only refactor. No agent-contract changes — the four slash commands (
/aso-full-audit,/aso-optimize,/aso-prelaunch,/aso-competitor), theoutputs/[app-name]/folder layout, and every legacy path insideapp-store-optimization/and.claude/skills/aso/continue to work unchanged via symlinks.In one sentence: rename the canonical source from the un-importable hyphenated
app-store-optimization/to a properaso_skill/Python package, add apytestsuite (50 tests), expose anasoCLI, fix the hardcoded2025-11-07reference date in load-bearing agent prompts, end the drift between the duplicate skill copies, and add a 24h iTunes cache.Why this is needed
Three issues surfaced during the planning audit:
app-store-optimization/is not a valid Python module identifier. No__init__.py, notests/.pyproject.tomldeclared a package that could not actually bepip installd.main.aso-strategist.md:932invokespython3 aso_scorer.py < /tmp/aso_input.jsonagainst a module with no__main__block. The call was a silent no-op..claude/skills/aso/had drifted. Every analytic.pydiffered from its twin inapp-store-optimization/. The drift had no enforcement mechanism.aso-strategist.mdhardcodedToday's date: November 7, 2025(lines 27, 237, 1097) — every timeline generated after Nov 2025 referenced past dates.What changed
app-store-optimization/*.py(hyphenated, un-importable)aso_skill/*.py(real package,pip install-able)aso_skill/.claude/skills/aso/app-store-optimization/__main__blocksaso score / optimize / validate / keywords / ab-test / checklist / itunes2025-11-07date -u +%Y-%m-%dBackwards compatibility
app-store-optimization/to~/.claude/skills/keep working (symlinks resolve oncp -r).cd app-store-optimization && python3 <module>.pykeep working — and now actually succeed end-to-end, because the underlying file finally has a__main__block.scripts/materialize_compat.pyreplaces symlinks with real copies for Windows / archive-extraction users whose filesystem doesn't support them.pytestis the lone optional extra (pip install '.[test]').Test plan
pip install -e ".[test]"succeeds locally on Python 3.11pytest tests/— 50 passed in 2.72saso --helplists the seven subcommandsaso validate --platform apple --field title --value "X"*50exits 1aso validate --platform apple --field title --value "TaskFlow"exits 0aso score < tests/fixtures/score_input.json→overall_score: 91.5python3 app-store-optimization/aso_scorer.py < tests/fixtures/score_input.jsonworks via symlink → identical scorepython3 .claude/skills/aso/aso_scorer.py < tests/fixtures/score_input.jsonworks via two-hop symlink chain → identical scorereadlink -f app-store-optimization/aso_scorer.py→aso_skill/scorer.pyToday's date: November 7, 2025in load-bearing agent prompts (enforced bytests/test_dates.py)/aso-full-audit TestAppin a real Claude Code session produces the expectedoutputs/TestApp/folder structure (manual)https://claude.ai/code/session_01CbA3Mp4rD4vW9Yjd2aPEXw
Generated by Claude Code