Drift detection
Drift is when a resource exists but its value no longer matches iap.yaml —
typically because someone edited it by hand in a store console. storectl
separates this from a first-time create:
create(+) — the item is missing and would be created.drift(~) — the item exists but differs;current → desiredis reported.
iapctl plan -config iap.yaml# ~ price sonir.pro.yearly JPY 5800 → JPY 5400 (someone changed it in App Store Connect)What M0 detects
Section titled “What M0 detects”| Detected (current → desired) | Not yet monitored |
|---|---|
| Subscription & one-time prices | availability / territories |
| Store listings / localizations (name, description) | billing period, base-plan config |
| App Store / Play state where applicable | RevenueCat wiring, display names |
storectl reports only what it checks — it does not silently claim coverage it
doesn’t have. (App Store non-consumable price drift currently reports desired
only; subscriptions report both current and desired.)
Exit codes
Section titled “Exit codes”-detailed-exitcode makes plan terraform-style, so CI can branch on it:
| Code | Meaning |
|---|---|
0 |
no changes (everything matches) |
2 |
pending changes / drift |
1 |
error |
Add -drift-only so only drift counts as pending (a first-time create is
ignored) — exactly what a scheduled drift monitor wants.
Scheduled drift monitor
Section titled “Scheduled drift monitor”Run plan -drift-only on a schedule; if it exits 2, open/update a GitHub
Issue (and/or ping Slack). No hosted service required.
name: drift-cronon: schedule: [{ cron: "17 */6 * * *" }] # every 6h workflow_dispatch: {}permissions: { contents: read, issues: write }jobs: drift: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: curl -fsSL https://storectl.dev/install.sh | sh - id: drift uses: storectl-dev/storectl/.github/actions/storectl-comment@v1 with: { command: plan, config: iap.yaml, drift-only: "true", post-comment: "false" } env: { /* your store secrets */ } # if steps.drift.outputs.exit-code == '2' → open/update an Issue (see the sample)A complete drift-cron.yml (Issue upsert + optional Slack) is in the storectl
repo under examples/github-actions/.
JSON report
Section titled “JSON report”-o json emits a versioned, machine-readable report for dashboards and
notifications (see the CLI reference):
{ "schemaVersion": 1, "app": "Sonir", "command": "plan", "summary": { "create": 0, "created": 0, "drift": 1, "exists": 12, "skip": 1, "error": 0 }, "actions": [ { "provider": "appstore", "op": "price", "target": "sonir.pro.yearly", "status": "drift", "current": "JPY 5800", "desired": "JPY 5400" } ]}