Skip to content

Commit 6e9eebe

Browse files
hyochanclaude
andauthored
feat: complete commerce implementation guide (#445)
Commerce Protocol now walks readers through purchase, verification, ownership, access, events, and account deletion, with IAPKit and the runnable example alongside each step. The architecture opens explanations in place; navigation, nested accordions, and transitions follow the same documentation layout. IAPKit binds Amazon and Horizon purchases to authenticated app accounts and rechecks ownership before returning access. Only entitled evidence binds, at most 20 purchases per app account; the 21st binding answers `bound: false` (SPEC §4.4) and is logged, and the read keeps the same bound as a backstop. Rechecks draw on their own admission bucket (300 tokens, 5/s, one per bound purchase) before any store call and do not write back an unchanged verdict. Erasure refuses the erased app user id while its job is retained; another app account may bind the same Amazon or Horizon evidence afterwards as a first binding. Apple and Google subscription rows keep their permanent erasure marker. The example → IAPKit → example check keeps one app backend and receiver unchanged: 170 assertions, recorded at the committed sources. The docs build verifies that the report, snapshots, hashes, and `#L<n>` anchors agree with each other; freshness against the current IAPKit sources is the advisory `bun run audit:commerce-evidence`, run with `continue-on-error` in the web E2E job, and a recording from an uncommitted tree is marked `-dirty`. Static HTML, canonical metadata, sitemap generation, and readable AI entry points make the same guides available without JavaScript. Companion example: hyodotdev/openiap-commerce-protocol-example#1. Checks: IAPKit lint and the full IAPKit test suite (one existing skip), compiled-server smoke, the protocol suite, 170 provider-replacement assertions, the composition and source-provenance checks, 144 prerendered pages, and the SDK parity, docs, layout, CI-path, and agent-surface audits pass locally. Review: CodeRabbit skips this diff (over its 100-file limit) and Codex is over its usage limit until Sep 15, so this head was reviewed by three independent read-only review-self lenses (kit correctness, tests and tooling, docs and protocol) and by Grok on the pasted diff. Every finding that did not need a product decision was fixed in `3bf91680` and the follow-up commit; the Grok notes left as they are, with reasons, are in the PR comments. Merge gate: device regression remains pending for the `packages/kit` Martie live-receipt rows on iOS and Android/Play. The local four-store checks use synthetic evidence and mocked store responses; no real Amazon, Horizon, Apple, or Google checkout is claimed. Cross-company adoption and production migration are not established by this run. Preview [commerce-docs.webm](https://github.com/user-attachments/assets/853d1473-14bd-4c04-82bb-d9278f4eeb9f) 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
1 parent e338ca6 commit 6e9eebe

223 files changed

Lines changed: 23395 additions & 2156 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/commands/e2e-tests.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,12 @@ Run this row as part of every full E2E regression. When the request is narrowed
9191
to IAPKit, run this row plus the focused package/example checks that support it;
9292
do not rerun unrelated framework/store rows.
9393

94+
Read the "Device and Workspace State That Silently Breaks a Row" section of
95+
`.codex/skills/iapkit-e2e-martie/SKILL.md` first. A leftover store flavor in the
96+
generated Android project, a leftover iOS scene session from another app sharing
97+
the bundle id, and prebuilt React Native each break a row in a way that looks
98+
like a store or account failure.
99+
94100
Prerequisites:
95101

96102
- A connected iPhone or Google Play-capable Android phone with a sandbox/tester

‎.claude/commands/verify-all.md‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ set -euo pipefail
4040
# Docs formatting, typecheck, and production bundle
4141
(cd packages/docs && bun run format:check && bun run build)
4242

43+
# Advisory: recorded IAPKit interop evidence versus the current sources
44+
bun test ./scripts/audit-commerce-evidence.test.mjs
45+
bun run audit:commerce-evidence || echo "commerce evidence differs from current sources; re-record before deploying docs"
46+
4347
# Swift build and unit tests (packages/apple)
4448
(cd packages/apple && swift test)
4549

‎.codex/skills/iapkit-e2e-martie/SKILL.md‎

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,61 @@ inspect the generated key value. After building, install with
261261
`VEGA_DEVICE_ID="$VEGA_DEVICE_ID" bun run run:vega:firetv`, then require the
262262
same local-server and purchases-view evidence as the other live lanes.
263263

264+
## Device and Workspace State That Silently Breaks a Row
265+
266+
Every item below has cost a full debugging session. Check them before
267+
concluding that a store, an account, or the code is at fault.
268+
269+
**The Android project keeps the last store it was prebuilt for.** The FireOS
270+
and Horizon rows run `expo prebuild --platform android --clean` with
271+
`EXPO_IAP_FIREOS=1` or `EXPO_IAP_HORIZON=1`, and the generated `android/`
272+
directory keeps that store afterwards. A later Play run then links the wrong
273+
`openiap-google` flavor, so the example sits on `Connecting to Store...` with
274+
`initConnection failed: Failed to initialize connection` and
275+
`getStorefront failed: Billing client not ready`. Re-run
276+
`bunx expo prebuild --platform android --clean` with no store variable before
277+
the Play row, then confirm `horizonEnabled=false` and `fireOsEnabled=false` in
278+
`android/gradle.properties` and `missingDimensionStrategy "platform", "play"`
279+
in `android/app/build.gradle`.
280+
281+
**A Play "not compatible with your device" banner does not block billing.** The
282+
Martie production listing sets `minSdkVersion 31`, so Play marks an Android 11
283+
device incompatible and refuses to install that artifact. The examples this
284+
repository builds declare a lower minimum and install fine: `packages/google`
285+
Example inherits `minSdk = 23` from the library, and the Expo example ships 24.
286+
Both use the `dev.hyo.martie` application id, so a license tester buys and
287+
verifies through them normally despite the banner. Confirm with the
288+
`packages/google` Example, whose subscription screen enables `OpenIapLog` and
289+
prints the real `BillingResult`, before blaming the store.
290+
291+
**iOS keeps a scene session per bundle id.** Any other app built with
292+
`dev.hyo.martie` — the SwiftUI `packages/apple/Example`, or the Godot and
293+
Flutter Martie examples — leaves a scene session behind. Installing the Expo
294+
example over it restores that session, so UIKit attaches the previous app's
295+
scene delegate and the example's own `SceneDelegate`, which is what starts
296+
React Native, never runs. The process stays alive, the screen is black, Metro
297+
receives no bundle request, and nothing crashes. Run
298+
`xcrun devicectl device uninstall app --device "$IOS_UDID" dev.hyo.martie`
299+
before installing; an upgrade install does not clear it.
300+
301+
**Prebuilt React Native has no packager support.** Expo links React Native as a
302+
prebuilt binary by default, and that slice compiles without `DEBUG`, so
303+
`RCTBundleURLProvider` returns no bundle URL and a Debug build never contacts
304+
Metro whatever host `ip.txt` holds. Set `"ios.buildReactNativeFromSource"` to
305+
`"true"` and `"EXPO_USE_PRECOMPILED_MODULES"` to `"false"` in
306+
`ios/Podfile.properties.json`, then run `pod install` and rebuild.
307+
308+
**Reinstalling resets the iOS local-network permission.** Allow it again when
309+
the prompt appears, otherwise both Metro and the local server are unreachable.
310+
311+
**The local origin differs per platform and is baked in at bundle time.**
312+
Android reaches the server through an `adb reverse` rule on `127.0.0.1`; iOS
313+
needs the Mac's LAN address. `EXPO_PUBLIC_*` values are inlined when Metro
314+
starts, so restart Metro and relaunch the app after editing the environment
315+
file. A stale value sends verification to the hosted service instead, which
316+
surfaces as `Unable to parse verification response` while the local server log
317+
stays empty.
318+
264319
## Martie Catalog
265320

266321
- `dev.hyo.martie.10bulbs`: consumable; preferred repeatable receipt fixture

‎.codex/skills/ship-release/SKILL.md‎

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,17 @@ still return to the normal PR loop.
107107

108108
From a clean local `main` equal to `origin/main`:
109109

110-
1. Run `npm run deploy` and wait for successful production completion.
111-
2. Fetch the production release page and generated LLM documents with a cache
110+
1. Run `bun run audit:commerce-evidence`. If it reports drift, re-record the
111+
IAPKit interop per `packages/kit/scripts/docs/commerce-interop.md` before
112+
deploying; the guide page shows the recorded revision either way.
113+
2. Run `npm run deploy` and wait for successful production completion.
114+
3. Fetch the production release page and generated LLM documents with a cache
112115
buster. Confirm the new release title, API name, versions, and generated
113116
timestamp are present.
114-
3. If the OpenIAP Spec advanced, dispatch the docs release workflow with the
117+
4. If the OpenIAP Spec advanced, dispatch the docs release workflow with the
115118
current version and verify the resulting `docs-{spec}` GitHub Release points
116119
to the deployed commit.
117-
4. Recheck required CI for the final `main` head and report any still-pending
120+
5. Recheck required CI for the final `main` head and report any still-pending
118121
external listing or registry state separately.
119122

120123
## 6. Leave the shipped comment
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
name: Commerce Protocol proposal
2+
description: Propose shared behavior or contribute implementation interoperability evidence.
3+
title: "[Commerce Protocol]: "
4+
body:
5+
- type: markdown
6+
attributes:
7+
value: |
8+
Start with a concrete connection between products. See the [contribution procedure](https://github.com/hyodotdev/openiap/blob/main/specs/commerce-protocol/CONVENTION.md#public-collaboration-and-implementation-evidence).
9+
IAPKit and other implementations are reviewed against the same contract. Submitting a report is not a conformance or endorsement claim.
10+
- type: dropdown
11+
id: contribution
12+
attributes:
13+
label: Contribution
14+
options:
15+
- Interoperability reproduction
16+
- Contract extension
17+
- Compatibility problem
18+
validations:
19+
required: true
20+
- type: textarea
21+
id: outcome
22+
attributes:
23+
label: Use case and expected outcome
24+
description: Which services or roles need to connect, and what should the user observe?
25+
validations:
26+
required: true
27+
- type: textarea
28+
id: implementations
29+
attributes:
30+
label: Implementations and reviewers
31+
description: List source revisions, roles, stores, bindings, declared profiles, and relevant affiliations. Distinguish project-authored fixtures from an external implementation or review.
32+
validations:
33+
required: true
34+
- type: textarea
35+
id: reproduction
36+
attributes:
37+
label: Runnable evidence
38+
description: Provide commands, source/report links, expected results, and a failure or rejection case. List configuration fields and adapter/client changes; omit credentials and customer data.
39+
validations:
40+
required: true
41+
- type: textarea
42+
id: compatibility
43+
attributes:
44+
label: Compatibility and alternatives
45+
description: Can existing profiles or extensions express this? For a contract change, identify MAJOR/MINOR impact and migration work. For a reproduction, state whether the client and receiver code changed.
46+
validations:
47+
required: true
48+
- type: textarea
49+
id: limits
50+
attributes:
51+
label: Limits and unresolved questions
52+
description: State what remains untested, who has reproduced the result, and any disagreement about expected behavior.
53+
validations:
54+
required: true

‎.github/workflows/ci.yml‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ jobs:
219219
# time, so a spec change must rebuild and probe the binary.
220220
- 'specs/commerce-protocol/**'
221221
- 'scripts/e2e-web-sites.mjs'
222+
- 'scripts/audit-commerce-evidence.mjs'
223+
- 'scripts/audit-commerce-evidence.test.mjs'
222224
- 'package.json'
223225
- 'bun.lock'
224226
- '.github/workflows/ci.yml'
@@ -592,6 +594,10 @@ jobs:
592594
bun test scripts/audit-docs.test.ts
593595
bun run audit:docs
594596
597+
- name: Check static discovery guards
598+
working-directory: packages/docs
599+
run: bun run test:discoverability
600+
595601
- name: Lint
596602
working-directory: packages/docs
597603
run: bun run lint
@@ -631,7 +637,13 @@ jobs:
631637
done
632638
633639
- name: Install Playwright chromium
634-
run: bunx playwright install --with-deps chromium
640+
# `--with-deps` runs apt, which fails whenever Google's Chrome
641+
# repository serves a stale index. Playwright downloads its own
642+
# chromium, so drop that source first: nothing here needs it.
643+
run: |
644+
sudo rm -f /etc/apt/sources.list.d/google-chrome.list \
645+
/etc/apt/sources.list.d/google-chrome.sources
646+
bunx playwright install --with-deps chromium
635647
636648
- name: Build docs site
637649
working-directory: packages/docs
@@ -643,6 +655,15 @@ jobs:
643655
VITE_KIT_CONVEX_URL: https://placeholder-build-1.convex.cloud
644656
run: bun run build:all
645657

658+
- name: Test the Commerce evidence audit
659+
run: bun test ./scripts/audit-commerce-evidence.test.mjs
660+
661+
- name: Report Commerce evidence freshness
662+
# Advisory: the recorded IAPKit interop stays valid for its recorded
663+
# revision; drift only means the guide shows older sources than main.
664+
continue-on-error: true
665+
run: bun run audit:commerce-evidence
666+
646667
- name: Run docs and IAPKit web E2E
647668
env:
648669
WEB_E2E_DOCS_BASE_URL: http://127.0.0.1:4173

‎.github/workflows/deploy-kit.yml‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,13 @@ jobs:
152152
- name: Install Playwright chromium
153153
# smoke-browser.ts loads the SPA in headless Chromium to catch
154154
# runtime bundle crashes that HTTP probes miss (see PR #120).
155-
run: bunx playwright install --with-deps chromium
155+
# `--with-deps` runs apt, which fails whenever Google's Chrome
156+
# repository serves a stale index. Playwright downloads its own
157+
# chromium, so drop that source first: nothing here needs it.
158+
run: |
159+
sudo rm -f /etc/apt/sources.list.d/google-chrome.list \
160+
/etc/apt/sources.list.d/google-chrome.sources
161+
bunx playwright install --with-deps chromium
156162
157163
- name: Smoke test compiled server
158164
run: ./scripts/smoke-server.sh

‎CONTRIBUTING.md‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,12 @@ second type-copy command or maintain another target list.
9696

9797
### Changing the Commerce Protocol
9898

99+
Start shared behavior proposals with the **Commerce Protocol proposal** issue
100+
form. The [protocol contribution procedure](specs/commerce-protocol/CONVENTION.md#public-collaboration-and-implementation-evidence)
101+
defines the evidence and compatibility review. You can also contribute an
102+
independent reproduction using the [service composition example](https://openiap.dev/commerce-protocol/ecosystem#composition-proof)
103+
without proposing a contract change.
104+
99105
1. Edit `specs/commerce-protocol/SPEC.md` and the owning GraphQL layer
100106
under `schema/`.
101107
2. Run `cd specs/commerce-protocol && bun run build` to regenerate the

‎knowledge/_agent-context/context.md‎

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# OpenIAP Project Context
22

33
> **Auto-generated shared context for AI assistants**
4-
> Last updated: 2026-09-07T14:34:17.286Z
4+
> Last updated: 2026-09-09T00:37:16.148Z
55
>
66
> Canonical file: `knowledge/_agent-context/context.md`
77
@@ -1689,6 +1689,47 @@ Before finishing, read the rendered page as a user. Remove any sentence that
16891689
does not clarify what changed, how to use it, who is affected, or what action is
16901690
required.
16911691

1692+
## Human and AI Acceptance
1693+
1694+
Apply these checks whenever changing a guide, example, SDK entry point, or AI
1695+
implementation brief. They are completion criteria, not an optional final polish.
1696+
1697+
- **First-time reader:** walk through the rendered page on desktop and mobile.
1698+
The reader should understand what they get, which decisions they own, and what
1699+
to do next before seeing an API table or a long AI prompt. Introduce terms at
1700+
the step that needs them; keep detailed references available afterward.
1701+
- **Two implementations:** Commerce Protocol guides must connect each relevant
1702+
responsibility to the runnable example and to at least one independent
1703+
implementation's code and checks (today `openiap-commerce-protocol-example`
1704+
and IAPKit). Explain differences in supported operations, stores, and
1705+
profiles. Do not present a fixture as a real purchase, one provider as
1706+
evidence of interoperability with another, or any single implementation as
1707+
the protocol. Follow the source links and operate the guide.
1708+
- **Fresh AI implementation:** when a brief or runnable example changes, replay
1709+
its install, implementation, startup, and acceptance instructions in a clean
1710+
project using only the published inputs. Record the input revision, commands,
1711+
observed results, failures, and remaining limits. Retain previously exercised
1712+
cases; do not hide failures by shrinking declarations or accepting known
1713+
conformance failures. Reuse an earlier run only when its relevant inputs have
1714+
not changed, and identify that run rather than calling it a new reproduction.
1715+
- **Independent acceptance:** test the promised customer behavior, including
1716+
failure and recovery, against the running result, and record the commands
1717+
and observed results in the PR body or the published run report. An agent
1718+
simulation is useful evidence, but must be labeled as a simulation, not a
1719+
human user study.
1720+
- **SDK discovery:** verify the initial HTTP response contains the page's actual
1721+
text, title, description, and canonical URL without JavaScript. Canonical
1722+
pages belong in the generated sitemap. Framework names, install commands,
1723+
versions, and setup links come from their existing metadata sources. Generated
1724+
`llms.txt` references must lead to the same current contracts and examples.
1725+
1726+
Run `bun run build` and `bun run test:discoverability` in `packages/docs` for
1727+
static content and metadata checks. The repository's `bun run e2e:web`
1728+
checks the served HTML and the interactive Commerce Protocol walkthrough.
1729+
These checks catch regressions; they do not prove that a person understood the
1730+
page or that an AI chose the SDK, and `llms.txt` or structured data do not
1731+
guarantee indexing or recommendation. Do not claim adoption effects from them.
1732+
16921733
## Modal Pattern with Preact Signals
16931734

16941735
### Global Modal Management

‎knowledge/internal/05-docs-patterns.md‎

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,47 @@ Before finishing, read the rendered page as a user. Remove any sentence that
2424
does not clarify what changed, how to use it, who is affected, or what action is
2525
required.
2626

27+
## Human and AI Acceptance
28+
29+
Apply these checks whenever changing a guide, example, SDK entry point, or AI
30+
implementation brief. They are completion criteria, not an optional final polish.
31+
32+
- **First-time reader:** walk through the rendered page on desktop and mobile.
33+
The reader should understand what they get, which decisions they own, and what
34+
to do next before seeing an API table or a long AI prompt. Introduce terms at
35+
the step that needs them; keep detailed references available afterward.
36+
- **Two implementations:** Commerce Protocol guides must connect each relevant
37+
responsibility to the runnable example and to at least one independent
38+
implementation's code and checks (today `openiap-commerce-protocol-example`
39+
and IAPKit). Explain differences in supported operations, stores, and
40+
profiles. Do not present a fixture as a real purchase, one provider as
41+
evidence of interoperability with another, or any single implementation as
42+
the protocol. Follow the source links and operate the guide.
43+
- **Fresh AI implementation:** when a brief or runnable example changes, replay
44+
its install, implementation, startup, and acceptance instructions in a clean
45+
project using only the published inputs. Record the input revision, commands,
46+
observed results, failures, and remaining limits. Retain previously exercised
47+
cases; do not hide failures by shrinking declarations or accepting known
48+
conformance failures. Reuse an earlier run only when its relevant inputs have
49+
not changed, and identify that run rather than calling it a new reproduction.
50+
- **Independent acceptance:** test the promised customer behavior, including
51+
failure and recovery, against the running result, and record the commands
52+
and observed results in the PR body or the published run report. An agent
53+
simulation is useful evidence, but must be labeled as a simulation, not a
54+
human user study.
55+
- **SDK discovery:** verify the initial HTTP response contains the page's actual
56+
text, title, description, and canonical URL without JavaScript. Canonical
57+
pages belong in the generated sitemap. Framework names, install commands,
58+
versions, and setup links come from their existing metadata sources. Generated
59+
`llms.txt` references must lead to the same current contracts and examples.
60+
61+
Run `bun run build` and `bun run test:discoverability` in `packages/docs` for
62+
static content and metadata checks. The repository's `bun run e2e:web`
63+
checks the served HTML and the interactive Commerce Protocol walkthrough.
64+
These checks catch regressions; they do not prove that a person understood the
65+
page or that an AI chose the SDK, and `llms.txt` or structured data do not
66+
guarantee indexing or recommendation. Do not claim adoption effects from them.
67+
2768
## Modal Pattern with Preact Signals
2869

2970
### Global Modal Management

0 commit comments

Comments
 (0)