Skip to content

[Protocol] Adopt UCP 2026-08-25 across Checkout Kit - #765

Draft
adrian-augustyn wants to merge 1 commit into
Shopify:mainfrom
adrian-augustyn:ucp-2026-08-25
Draft

adrian-augustyn wants to merge 1 commit into
Shopify:mainfrom
adrian-augustyn:ucp-2026-08-25

Conversation

@adrian-augustyn

@adrian-augustyn adrian-augustyn commented Sep 14, 2026

Copy link
Copy Markdown

What changes are you making?

Checkout Kit currently replaces caller-supplied ec_version with its April protocol constant. This change pins the August UCP snapshot and updates the SDK sources to request and decode 2026-08-25.

  • Tracking: shop/issues-checkout-kit#1237.
  • Checkout-web prerequisite: shop/issues-checkout-kit#1236.
  • Base: 63967cce95c05f43bbab8c1fc53b0b3d2679b56c, fetched from origin/main and rebased on September 14, 2026. The original September 10 implementation was based on dd79f3628a2f5ba6aead42bfce1a628ddb138e21.
  • Branch: ucp-2026-08-25, kept as one squashed commit. The September 14 rebase alone preserved the original patch (git range-diff reported =); the later review fixes and their verification are recorded below.
  • UCP: v2026-08-25, resolved by the updater to cd78fb38e819de77d9b527d110476eccb876f1bd.

Changes by layer:

  • Snapshot: reconcile 19 moved paths, remove three obsolete schemas, and add 14 dependencies. All 99 manifest paths mirror upstream, including source/services/shopping/embedded.openrpc.json; all 412 $ref references resolve, including their JSON pointers. The updater replaced 72 files, and the snapshot matches the pinned commit byte-for-byte.
  • Generators: follow the common-types relocation; derive TypeScript, Swift and Kotlin versions from the lockfile; preserve semantic model names using temporary schema titles. Fix the pre-existing quicktype typeMap declaration mismatch with tests for exported and unexported declarations. Suppress the internal rename-map declaration artifact emitted by tsc. Preserve typed destination address/location fields and accept April destinations without August's discriminator. Keep fulfillment-method extension preservation when August makes schema openness implicit.
  • TypeScript/Web: regenerate models, codecs/rename metadata and declarations; update negotiation expectations and specification links. Regeneration also synchronizes the already-existing Client.onDecodeError / DecodeErrorContext declarations, whose drift was reproduced before the schema upgrade.
  • Swift: regenerate models and the negotiated revision from the lockfile, adapt four explicit UCP-response initializers to mapOrder: nil, update open-string fulfillment expectations and duplicate/stale URL coverage at the protocol and SDK layers, and regenerate the protocol API report. The other Swift module reports remain unchanged. The review follow-up moves specVersion into the generated extension without changing its name, type or getter.
  • Kotlin/Android: regenerate protocol models/catalog, add explicit version and duplicate/stale URL coverage, adapt Android tests to string-valued fulfillment types, and regenerate the Kotlin protocol API report. The Android SDK API file is unchanged; compiled SDK/protocol API checks, Android tests and lint now pass with the installed Android SDK.
  • React Native: retain April relay coverage and validate JavaScript and the public API report. Native iOS integration with --local passes 73/73; Android local integration passed 26/26 debug and 26/26 release on September 14; published native SDK pointers and package/release versions remain unchanged.

This is schema/runtime adoption. The protocol-agnostic public-event work in #748 is outside this change. No changes were taken from stale draft #203.

Checkout-web is a separate state. Gitstream source inspected on September 10 at 405cff8f197d2309f91ed44ac83124af1bf485aa contains the August client, mapper, registration and selection tests. The client factory explicitly selects August while its default/fallback remains April. The source implementation prerequisite was present in that inspection. A fresh September 14 issue check confirms #1236 is closed (September 10, 13:17 UTC). Checkout-web tests were not rerun here, and deployed readiness has not been proved. This PR changes Checkout Kit's own negotiated version.

Compatibility and public API

Equivalent JSON fixtures run through TypeScript, Swift and Kotlin. They cover August ucp.version, typed map_order, drone_delivery in both fulfillment method lists, August shipping-address and business-location destinations, and representative April checkout/error payloads including postal addresses and retail locations without type. All three languages assert typed business-location id, name, and nested address fields and verify the full checkout round-trip. SwiftPM and JVM resource conventions require harness-local copies; the TypeScript tests enforce byte-for-byte equality across all three copies.

Round-trip checks preserve unknown checkout and fulfillment-method properties plus arbitrary signals. Native codecs accept and ignore unknown UCP metadata; TypeScript preserves it. The tests explicitly reflect that existing boundary. This is representative April wire compatibility, not a claim that every historical shape or public API is unchanged.

Public API review:

  • Existing generated model names and the fulfillment-method serializer are retained. The removed model type names are FulfillmentMethodType and MethodType (plus Kotlin companions); fulfillment type and expectation methodType become open strings. Native callers using enum cases or exhaustive switches must migrate; TypeScript callers importing the removed union aliases must also migrate.
  • Additions include map ordering, actions, policies, payment preferences, measures, quantity units and unit prices. FulfillmentDestination.type is optional in the SDK compatibility model; businesses emitting August responses must still supply it.
  • Source/binary breaks: generated Swift initializers require new arguments even for optional fields; Kotlin/Java constructor, copy, and component signatures change. FulfillmentOption.description becomes a structured Description object with plain/html/markdown fields, and payment-instrument constraints changes from an arbitrary map to ConstraintsElement. The generated description has no legacy string alternative, so April string-valued fulfillment descriptions are outside the tested compatibility guarantee. Legacy constraint keys outside the new closed schema are not promised native round-trip preservation.
  • Swift and Kotlin protocol reports were reviewed and checked. No unrelated Swift module report or React Native API report changed. Android SDK API verification and library tests, including the Java interop suite, now pass. The review follow-up changes only the placement/extension metadata of Swift's existing specVersion in the API report; the API digester reports no compatibility changes.

How to test

The full initial verification below was performed locally on September 10, 2026. A separate September 14 rebase-verification section records fresh checks; earlier passes are not presented as new runs. Every dev command means:

shadowenv exec --dir /Users/adrianaugustyn_1/src/github.com/Shopify/checkout-kit-ucp-2026-08-25 -- /opt/dev/bin/dev ...

JVM commands additionally used env JAVA_HOME=/private/tmp/jdk-17.0.9+9/Contents/Home inside that prefix after a temporary Temurin 17 installation. It is a per-command environment setting, not a repository or system default.

Command Result
dev protocol check-tools PASS: installed codegen tools match the pinned tooling manifest.
dev protocol update-upstream --ref v2026-08-25 PASS: expected commit; 72 files updated, 99 checked.
dev protocol check-upstream PASS: all 99 files match the pinned commit.
dev codegen typescript PASS after fixing the baseline marker defect; subsequent compatibility and reproducibility runs pass.
dev codegen swift PASS, including compatibility and reproducibility reruns.
dev codegen kotlin PASS, including compatibility and reproducibility reruns.
dev protocol test typescript PASS: 64/64, including both fixture versions and rename-map tests.
dev web test PASS: 247/247, including exactly one August URL version after stale/duplicate caller values.
dev protocol test kotlin PASS after correcting the native metadata test expectation; final standalone and aggregate Kotlin runs pass 49/49.
dev protocol test swift BLOCKED: macOS runner exits 1 after successful compilation with no diagnostics, including outside the sandbox; reproduced with clean-main sources. Simulator evidence is below.
dev protocol check BLOCKED: Swift/Kotlin builds and Kotlin tests/API check pass, then the macOS Swift runner exits 1. The aggregate's subsequent TypeScript step is skipped; it passes independently.
dev android test BLOCKED: Android SDK location missing; sample configuration was recovered before the final attempt.
dev android api dump BLOCKED at the Android SDK module by the missing SDK. Kotlin's report was dumped independently.
dev android api check BLOCKED at the Android SDK module by the missing SDK. Kotlin's report passes independently.
dev android format PASS, including detekt after the final Android enum-to-string test fix.
dev android lint PARTIAL/BLOCKED: detekt passes; Android lint cannot run without the SDK.
dev swift test PASS after setup recovery, exit 0: 928/928 package tests and 43/43 sample tests.
dev swift test EmbeddedCheckoutProtocolTests/VersionCompatibilityTests PASS on the final model/fixture changes: August and April checkout cases plus April error.
dev swift test ShopifyCheckoutKitTests/CheckoutURLDecoratorTests PASS after the final test enhancement, exit 0: exactly one August version replaces duplicate/stale values and decoration is idempotent.
dev swift api dump PASS after final generation; only the protocol module report changes.
dev swift api check PASS for EmbeddedCheckoutProtocol, ShopifyCheckoutKit and ShopifyAcceleratedCheckouts.
dev swift lint / dev swift format PASS, including the final test changes: SwiftLint, SwiftFormat and CocoaPods lint all exit 0; no unrelated files changed.
dev rn test js PASS: 239/239.
dev rn api check PASS; no API dump was needed.
dev rn lint PASS.
dev rn test ios --local PASS after setup recovery, exit 0: 73/73 using local native sources. The temporary local-mode Podfile.lock was restored and excluded.
dev rn test android --local BLOCKED during local SDK publication dependency resolution: Android SDK missing.
dev web lint PASS: package/sample typechecks, lint and formatting.
dev protocol lint PASS after replacing optional chaining in the new TypeScript test as required by lint policy.
dev web start PASS: local sample served at localhost:5173. Stopped the task-owned server after validation (SIGINT/exit 130). Deployed handshake validation is blocked by the browser connection failure; rendering or April fallback is not counted as success.

September 10 additional commands and diagnostics (with the same shadowenv prefix):

  • git fetch origin main, git worktree add -b ucp-2026-08-25 <worktree> origin/main, git rev-parse HEAD, and repository instruction/status reads: PASS; original checkout remains untouched.
  • gh issue view 1237, gh issue view 1236, issue timeline reads, gh pr view 548, and open-PR searches/listing: PASS; both issues and Use SemVer for the Kotlin protocol artifact #548 were open at that time. An initial broad PR search was unsuitable; a full list of 80 open Checkout Kit PRs was inspected and no current August adoption implementation was found.
  • UCP tag-tree query and a Python manifest/reference audit: PASS, 99 mirrored paths and 412 resolved references including JSON pointers. An initial unquoted ?recursive=1 endpoint was rejected by shell globbing and succeeded when quoted.
  • Checkout-web GitHub searches did not establish current readiness. Its README identifies the old repository as a migration mirror. World instruction reads, git fetch origin main, git show origin/main:<client/mapper/factory/test paths>, and a GitHub commit lookup established the source evidence above.
  • Clean-main dev codegen typescript: FAIL with typeMap literal not found; the generator required export const while quicktype emitted const. Retrying with only that fix succeeded and reproduced stale client declarations and the unwanted internal .d.ts before the snapshot upgrade.
  • Clean-main dev protocol check: Swift build passed, then Java was missing. Temurin download/extraction and java -version: PASS; JVM checks were rerun with the explicit temporary JAVA_HOME.
  • protocol/languages/kotlin/gradlew -p protocol/languages/kotlin clean :embedded-checkout-protocol:test :embedded-checkout-protocol:apiDump: PASS; later final :embedded-checkout-protocol:test :embedded-checkout-protocol:apiDump and :embedded-checkout-protocol:apiCheck pass. Earlier overlapping Gradle invocations produced a transient cache error, and an API check failed before the reviewed report was updated; serialized reruns resolved both.
  • swift test --verbose, swift test --disable-xctest, and swift test against a clean-main package exported with git archive: all reproduce the macOS runner's exit 1 after compilation. The initial target-only dev swift test EmbeddedCheckoutProtocolTests was rejected because that argument expects a test class; the explicit target/suite command in the table passes.
  • The first native compatibility assertions incorrectly expected unknown UCP metadata to round-trip. XCTest/JUnit results identified that assumption; expectations were corrected to the existing native preservation boundary, and the final suites pass. xcrun xcresulttool get test-results summary confirms the full Swift package and final fixture-suite results.
  • dev up and its outside-sandbox retry: BLOCKED downloading Maestro with an SSL connection error. scripts/setup_dev_workspace recovered storefront configuration and gems, then hit a keychain error while installing Swift tooling. Its outside-sandbox retry PASSED, including pinned SwiftLint, SwiftFormat, XcodeGen, sample generation and gems.
  • Final generated-file hash comparison: PASS, all 11 tracked generated artifacts unchanged on regeneration. The built-in fallback-name guard passes; stable model names remain, no rename-spine models were lost, and ProtocolRenameMap.d.ts is absent.
  • git diff --check, git diff --cached --check, and release-pointer/lockfile reviews: PASS. No published coordinate, RN native pointer or Podfile.lock change is included. git restore -- platforms/react-native/test/rct-integration-app/Podfile.lock restored only the task-generated local lockfile.
  • git add -- <reviewed paths> and git commit -m 'feat(protocol): adopt UCP 2026-08-25': PASS. git status --short --branch confirms both worktrees are clean; git diff HEAD^ HEAD --check passes. The local commit changes 131 files, mostly vendored schemas, generated models and API reports.
  • In-app browser initialization failed before interaction with missing field sandboxPolicy; no deployed checkout was exercised. No alternate browser path was used.

No remote package publication or release was performed. The successful September 14 RN Android --local run published only to Maven Local for validation. React Native API dump was skipped because its check passed without changes. Checkout-web tests and the deployed August handshake remain unverified.

Rebase verification — September 14, 2026

The rebase applied cleanly over nine new main commits. No implementation or public API changes were required. #1236 is now closed; #1237 and #548 remain open. There was no existing PR or remote branch for this change.

Command September 14 result
git fetch origin main; git rebase origin/main PASS: base 63967cce95c05f43bbab8c1fc53b0b3d2679b56c; no conflicts.
git range-diff dd79f362..1ebd06fe origin/main..HEAD PASS: identical reviewed patch; no new implementation changes. A local backup branch preserves the original reviewed commit.
gh issue view 1236; gh issue view 1237; gh pr view 548; PR/remote-branch lookup PASS: #1236 closed; #1237 and #548 open; no duplicate PR/branch.
pnpm --dir protocol install --frozen-lockfile PASS: installed main's Vitest 4.1.11 without changing the lockfile.
dev protocol check-tools; dev protocol check-upstream PASS: pinned tools match and all 99 snapshot files match upstream.
dev protocol test typescript; dev protocol lint PASS: 64/64 and lint.
dev web test; dev web lint PASS: 247/247 and package/sample lint/typechecks/format checks.
dev protocol check BLOCKED, exit 1: Swift/Kotlin builds, Kotlin protocol tests (49/49) and Kotlin API check pass; macOS Swift test runner exits after successful compilation without diagnostics. TypeScript passes separately.
dev swift test PARTIAL, exit 1: package tests pass 928/928; sample phase initially blocked by stale generated storefront configuration.
dev up BLOCKED, exit 1: OpenJDK 17 setup requires an interactive privileged symlink under /Library/Java/JavaVirtualMachines. Existing per-command JDK 17 remains usable.
scripts/setup_storefront_env; scripts/check_storefront_env PASS: regenerated and validated local sample configuration without committing configuration or exposing values.
dev swift test sample PASS after configuration refresh, exit 0: 43/43. Combined with the package result above, both Swift test phases passed.
dev swift api check PASS: all three modules match their reviewed reports.
dev swift lint PASS, exit 0: SwiftLint, SwiftFormat and CocoaPods lint.
dev rn test js; dev rn api check; dev rn lint PASS: 239/239, unchanged API report and lint.
dev rn test ios --local PASS, exit 0: 73/73 with the local native sources. Restored the generated local-mode Podfile.lock afterward.
dev android test BLOCKED, exit 1: initial stale configuration was fixed; the retry reaches the missing Android SDK blocker.
dev android api check; dev android lint BLOCKED, exit 1: Android SDK location missing. Kotlin protocol API verification passes separately in dev protocol check.
dev rn test android --local BLOCKED, exit 1: missing Android SDK during local publication task dependency resolution; no package publication completed.
xcrun xcresulttool get test-results summary PASS: confirms 928 Swift package tests with zero failures or skips.
git diff --check; final status and release-pointer reviews PASS: clean worktree, unchanged reviewed patch, no local lockfile or release-pointer changes.

Generators and API dumps were not repeated because the rebase preserved the exact reviewed patch and did not change the schema or generator inputs. API checks were rerun. The deployed checkout-web handshake was not retried; its September 10 browser blocker remains an unverified integration gap, not evidence of deployed readiness. No release coordinate or published React Native native SDK pointer changed.

Review follow-up — September 14, 2026

Squashed review head: fc0bbb069132543d632b59fbd848263367b9a114.

Addresses the two review findings:

  • Swift's existing EmbeddedCheckoutProtocol.specVersion is now emitted by generate_swift_catalog.mjs from source-lock.json, as TypeScript and Kotlin already were. Protocol tests also compare the TypeScript runtime and both generated native constants with the lockfile, so skipped regeneration fails verification. The Swift test previously named matchesOpenRPCInfoVersion is renamed to reflect its actual August-version assertion.
  • Synchronized August and April fixtures now include a pickup location alongside the postal-address case. Every language asserts typed id, name, and six nested address fields and verifies the complete decode/re-encode result. August carries type: "business_location"; April retains its historical retail-location shape without that discriminator. Both TypeScript decoding paths are exercised. No destination model or serializer change was needed.

The Swift API report changes only the placement of specVersion and its isFromExtension metadata. A structural comparison confirmed the variable/getter signatures are identical and the rest of the report is unchanged; the digester reports no compatibility changes. Both other Swift module reports, both Android/Kotlin API reports, the RN public report, release coordinates, and published native SDK pointers are unchanged by this follow-up. The original upgrade's source/binary compatibility considerations above still apply.

All commands below use the checkout's required shadowenv exec --dir <worktree> -- prefix. Android commands use env ANDROID_HOME=/Users/adrianaugustyn_1/Library/Android/sdk before /opt/dev/bin/dev; Java is the installed OpenJDK 17, without the earlier temporary override.

Command Review follow-up result
dev codegen swift PASS, including a repeat with both generated Swift files byte-for-byte unchanged. Only the catalog gains the generated constant; Models.swift is unchanged.
dev protocol check-upstream PASS: all 99 files match the pinned UCP commit.
dev protocol test typescript PASS, exit 0: 66/66, including native-version consistency and synchronized August/April destination coverage.
dev protocol lint PASS, exit 0.
dev web test PASS, exit 0: 247/247.
dev android test PASS, exit 0: library 462/462 (including Java interop), protocol 49/49 and demo 94/94; zero failures, errors or skips in JUnit reports.
dev android api check PASS, exit 0: SDK and protocol reports match.
dev android lint PASS, exit 0: detekt and Android library/sample lint.
dev swift test EmbeddedCheckoutProtocolTests/VersionCompatibilityTests PASS, exit 0: August checkout, April checkout and April error (three runs); zero failures or skips in the simulator result bundle.
dev swift test EmbeddedCheckoutProtocolTests/DescriptorTests PASS, exit 0: 6/6, including the August version assertion.
dev swift api check First run FAIL, exit 1: the constant's move changes report ordering/extension metadata. After reviewing and dumping that metadata-only change, final check: PASS, exit 0, for all three modules.
dev swift api dump PASS, exit 0; structural comparison proves only specVersion placement/extension metadata changes. Neither other Swift module drifts.
dev swift lint PASS, exit 0: SwiftLint, SwiftFormat and CocoaPods lint.
dev rn test ios --local PASS, exit 0: 73/73. Restored the task-generated local-mode Podfile.lock; it is excluded from the commit.
dev rn api check PASS, exit 0: unchanged public report.
xcrun xcresulttool get test-results summary; Python JUnit/fixture/API comparisons PASS: confirms native counts, complete fixture equality and the narrowly reviewed API delta.
git diff --check; generated-file/release-pointer/lockfile/status review PASS; only the two feedback items and Swift API metadata are changed.
Repository instruction/source reads; gh pr view 765; gh pr view 548 PASS: worktree started clean at f6f1b4cccaff02bccb00ec592ac2ba22b548fc71; #765 remains a draft; #548 is still open.
git branch backup/ucp-2026-08-25-pre-feedback-20260914; git add -- <15 reviewed paths>; git diff --cached --check; git commit --amend --no-edit; git rev-list --count <base>..HEAD PASS: saved the prior commit locally, amended the existing commit, and confirmed one commit above the unchanged base.
git ls-remote fork refs/heads/ucp-2026-08-25; git push --force-with-lease=refs/heads/ucp-2026-08-25:f6f1b4cccaff02bccb00ec592ac2ba22b548fc71 fork HEAD:refs/heads/ucp-2026-08-25 PASS: published the squashed update with an explicit lease against the previous remote head.

Android Studio follow-up earlier on September 14 also completed dev rn test android --local: PASS, exit 0, 26/26 debug and 26/26 release, with no failures, errors or skips. These are two variants of the suite. That run used commit f6f1b4cccaff02bccb00ec592ac2ba22b548fc71; this review follow-up does not change Kotlin/Android production sources. Its successful local-only Maven publication and native integration supersede the historical missing-SDK blockers retained in the earlier tables.

Verification scope: TypeScript/Kotlin codegen, the full Swift package/sample suites, RN JavaScript/native Android suites and their unchanged platform lint were not repeated for these focused fixes; their earlier September 14 results are retained above. No additional Android/RN API dump was needed. The standalone macOS Swift runner and aggregate dev protocol check were not retried here; that diagnosis remains separate. GitHub CI and the deployed August handshake remain unverified. No package release or remote publication was performed.

Before you merge

  • Add compatibility tests and review generated public APIs.
  • Complete Android tests/API/lint and RN Android integration with an Android SDK (September 14).
  • Resolve the macOS Swift aggregate-runner failure and verify a deployed August handshake.
  • Resolve the protocol artifact version. #548 is still open and proposes CalVer → SemVer; this change deliberately leaves the coordinate unchanged rather than guessing.
  • Review and communicate the native source/binary breaks before publication.

Required future release sequence, not executed here:

  1. Publish Embedded Checkout Protocol with the agreed artifact version.
  2. Release Android and Swift Kit versions.
  3. Bump React Native's published native SDK pointers to those released versions, then release React Native.

Keep this as a draft until the versioning decision and outstanding validation are resolved.

@github-actions github-actions Bot added the #gsd:50662 Rebase Checkout Kit on UCP label Sep 14, 2026
Comment thread protocol/scripts/generate_models.mjs Outdated

const unitPricePath = path.join(specDir, "types", "unit_price.json");
const unitPrice = await readJson(unitPricePath);
unitPrice.properties.measure.title = "ProductMeasure";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these be their own types? Putting the title on the allOf wrapper makes quicktype add a suffix, so we get ProductMeasureClass/ReferenceMeasureClass (*Object in TS) — and they have exactly the same fields as the existing Measure. If you point both fields at measure.json in the codegen copy, they just reuse Measure and the odd names never ship.

Comment thread protocol/scripts/generate_models.mjs Outdated
@@ -206,9 +218,33 @@ async function prepareCodegenSchemas(tempDir) {
for (const fulfillmentSchema of ["fulfillment_available_method", "fulfillment_method"]) {
const schema = await readJson(path.join(specDir, "types", `${fulfillmentSchema}.json`));
schema.properties.type.title = "FulfillmentMethodType";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This title does nothing now — in August type is a plain string, quicktype ignores titles on strings, and FulfillmentMethodType is gone from the generated code. I'd drop it and trim the comment so nobody looks for a model that doesn't exist. Only fulfillment_method needs the openness flag, so the loop can go too.

await writeJson(path.join(specDir, "types", "totals.json"), totals);
await writeJson(path.join(schemaDir, "common", "types", "totals.json"), totals);

// Keep new anonymous payment/measure shapes from renaming existing public models.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are ConstraintsElement/PropertyValue names you're happy shipping? They're just where quicktype found the shapes in the recursive constraint schema, and they become public API in all three languages. Titling the recursive parts in the codegen copy would get you ConstraintExpression/ValueConstraint — or if these are fine, a quick note here saying so.

}
relocateCommonRefs(destinationFields);
destination.properties = {...destinationFields, ...destination.properties};
destination.required = ["id"];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One gap: an April string description on a fulfillment option still breaks native decode (August made it an object), and the fixtures have no groups[].options[] at all — so the one known break is the one shape the tests never touch. Since it's already called out as out of scope, maybe add a fixture option with a string description that pins the current behavior?

Comment thread protocol/scripts/generate_models.mjs Outdated
schema.properties.type.title = "FulfillmentMethodType";
// August leaves methods implicitly open. Make that explicit for the native
// extension generator so the existing additionalProperties API survives.
if (fulfillmentSchema === "fulfillment_method") schema.additionalProperties = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If another model quietly stops being open on the next upstream bump, nothing fails — the existing guard only checks the other direction. A list of expected open models that codegen checks would catch it.

${conformances}

extension EmbeddedCheckoutProtocol {
public static let specVersion = "${specVersion}"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could this get a short /// comment saying it comes from source-lock.json and shouldn't be edited by hand? Everything else in this generated extension has one.


@Test
fun `decodes August and April checkouts preserving extensions`() {
for (version in listOf("2026-08-25", "2026-04-08")) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small one: Swift and TS run one test per revision, but the loop here means if August fails you never see the April result. Two @Tests calling a shared helper would match the others.

"methods": [
{
"id": "drone-1",
"type": "pickup",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

drone-1 is a pickup method here but its destination is a bare postal address — April pickups used retail locations, so this isn't a payload April would actually send. Making it "type": "shipping" (in all three copies, plus the 'pickup' asserts) would make the April/August pair easier to follow.


// Catch skipped regeneration even when a native test still expects an older
// revision. These files are emitted by the same codegen commands used in CI.
test.each([

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice — checking the generated Swift/Kotlin constants against the lockfile means forgetting to regenerate now fails CI.

const bytes = readFileSync(new URL('./fixtures/' + name + '.json', import.meta.url), 'utf8');
// SwiftPM bundles resources inside its test target; JVM tests use classpath
// resources. Keep the three harness-native copies byte-for-byte equivalent.
for (const directory of [

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The byte-equality check across the three fixture copies is exactly what duplicated fixtures need.

@adrian-augustyn
adrian-augustyn force-pushed the ucp-2026-08-25 branch 2 times, most recently from ec2522f to ce90809 Compare September 16, 2026 13:00
Assisted-By: devx/9ecb7751-82f9-4062-885f-a23b95dfc4a7
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

#gsd:50662 Rebase Checkout Kit on UCP

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants