Skip to content

Commit fc77f77

Browse files
authored
Merge branch 'main' into main
2 parents e3ae796 + 7e8548d commit fc77f77

32 files changed

Lines changed: 1164 additions & 1149 deletions

.cspell/custom-words.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ Paymentech
3030
Paypal
3131
Preorders
3232
Queensway
33+
Quicktype
3334
Sephora
3435
Shopify
3536
Shopee
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: 'Configure Site URL'
2+
description: >-
3+
Resolves the GitHub Pages URL for the current repository and exports it as
4+
SITE_URL and SPEC_URL environment variables for subsequent steps.
5+
inputs:
6+
github-token:
7+
description: >-
8+
Token used to query the GitHub Pages API. Defaults to the workflow token.
9+
required: false
10+
default: ${{ github.token }}
11+
runs:
12+
using: "composite"
13+
steps:
14+
- name: Resolve and export site URLs
15+
shell: bash
16+
env:
17+
GITHUB_TOKEN: ${{ inputs.github-token }}
18+
run: |
19+
PAGES_URL=$(gh api "repos/${{ github.repository }}/pages" --jq '.html_url' 2>/dev/null || true)
20+
if [ -z "$PAGES_URL" ] || [ "$PAGES_URL" = "null" ]; then
21+
PAGES_URL="https://${{ github.repository_owner }}.github.io/${GITHUB_REPOSITORY#*/}"
22+
fi
23+
if [[ "$PAGES_URL" != */ ]]; then
24+
PAGES_URL="${PAGES_URL}/"
25+
fi
26+
echo "SITE_URL=$PAGES_URL" >> "$GITHUB_ENV"
27+
echo "SPEC_URL=${PAGES_URL}latest/specification/overview/" >> "$GITHUB_ENV"

.github/pull_request_template.md

Lines changed: 0 additions & 93 deletions
This file was deleted.

.github/workflows/auto-label.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Auto Label Merged PRs
2+
3+
on:
4+
pull_request:
5+
types: [closed]
6+
branches:
7+
- main
8+
- "release/**"
9+
10+
jobs:
11+
label_prs:
12+
runs-on: ubuntu-latest
13+
14+
if: github.event.pull_request.merged == true
15+
16+
permissions:
17+
pull-requests: write
18+
19+
steps:
20+
- name: Apply labels based on Conventional Commits
21+
uses: actions/github-script@v7
22+
with:
23+
script: |
24+
const title = context.payload.pull_request.title.toLowerCase();
25+
const prNumber = context.payload.pull_request.number;
26+
const owner = context.repo.owner;
27+
const repo = context.repo.repo;
28+
29+
let labelsToAdd = [];
30+
31+
// The Regex checks: Starts with type (^type), optional scope (\([^)]+\))?, optional bang (!?), and a colon (:)
32+
if (/^feat(\([^)]+\))?!?:/.test(title)) {
33+
labelsToAdd.push('enhancement');
34+
} else if (/^docs(\([^)]+\))?!?:/.test(title)) {
35+
labelsToAdd.push('documentation');
36+
}
37+
38+
if (labelsToAdd.length > 0) {
39+
console.log(`Adding labels: ${labelsToAdd} to merged PR #${prNumber}`);
40+
41+
await github.rest.issues.addLabels({
42+
owner: owner,
43+
repo: repo,
44+
issue_number: prNumber,
45+
labels: labelsToAdd
46+
});
47+
} else {
48+
console.log('No matching Conventional Commit prefix found. No labels added.');
49+
}

.github/workflows/docs.yml

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -85,15 +85,7 @@ jobs:
8585
8686
- uses: ./.github/actions/setup-build-env
8787

88-
- name: Configure Site URL
89-
env:
90-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
91-
run: |
92-
PAGES_URL=$(gh api "repos/${{ github.repository }}/pages" --jq '.html_url' 2>/dev/null || true)
93-
if [ -z "$PAGES_URL" ] || [ "$PAGES_URL" = "null" ]; then PAGES_URL="https://${{ github.repository_owner }}.github.io/${GITHUB_REPOSITORY#*/}"; fi
94-
if [[ "$PAGES_URL" != */ ]]; then PAGES_URL="${PAGES_URL}/"; fi
95-
echo "SITE_URL=$PAGES_URL" >> $GITHUB_ENV
96-
echo "SPEC_URL=${PAGES_URL}latest/specification/overview/" >> $GITHUB_ENV
88+
- uses: ./.github/actions/configure-site-url
9789

9890
- name: Build and Verify Documentation Site (Main/PR)
9991
run: |
@@ -122,15 +114,7 @@ jobs:
122114
123115
- uses: ./.github/actions/setup-build-env
124116

125-
- name: Configure Site URL
126-
env:
127-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
128-
run: |
129-
PAGES_URL=$(gh api "repos/${{ github.repository }}/pages" --jq '.html_url' 2>/dev/null || true)
130-
if [ -z "$PAGES_URL" ] || [ "$PAGES_URL" = "null" ]; then PAGES_URL="https://${{ github.repository_owner }}.github.io/${GITHUB_REPOSITORY#*/}"; fi
131-
if [[ "$PAGES_URL" != */ ]]; then PAGES_URL="${PAGES_URL}/"; fi
132-
echo "SITE_URL=$PAGES_URL" >> $GITHUB_ENV
133-
echo "SPEC_URL=${PAGES_URL}latest/specification/overview/" >> $GITHUB_ENV
117+
- uses: ./.github/actions/configure-site-url
134118

135119
- name: Build and Verify Specification Docs (Release Branches)
136120
run: |
@@ -159,15 +143,7 @@ jobs:
159143
160144
- uses: ./.github/actions/setup-build-env
161145

162-
- name: Configure Site URL
163-
env:
164-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
165-
run: |
166-
PAGES_URL=$(gh api "repos/${{ github.repository }}/pages" --jq '.html_url' 2>/dev/null || true)
167-
if [ -z "$PAGES_URL" ] || [ "$PAGES_URL" = "null" ]; then PAGES_URL="https://${{ github.repository_owner }}.github.io/${GITHUB_REPOSITORY#*/}"; fi
168-
if [[ "$PAGES_URL" != */ ]]; then PAGES_URL="${PAGES_URL}/"; fi
169-
echo "SITE_URL=$PAGES_URL" >> $GITHUB_ENV
170-
echo "SPEC_URL=${PAGES_URL}latest/specification/overview/" >> $GITHUB_ENV
146+
- uses: ./.github/actions/configure-site-url
171147

172148
- name: Deploy development version from main branch
173149
run: |
@@ -220,15 +196,7 @@ jobs:
220196
221197
- uses: ./.github/actions/setup-build-env
222198

223-
- name: Configure Site URL
224-
env:
225-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
226-
run: |
227-
PAGES_URL=$(gh api "repos/${{ github.repository }}/pages" --jq '.html_url' 2>/dev/null || true)
228-
if [ -z "$PAGES_URL" ] || [ "$PAGES_URL" = "null" ]; then PAGES_URL="https://${{ github.repository_owner }}.github.io/${GITHUB_REPOSITORY#*/}"; fi
229-
if [[ "$PAGES_URL" != */ ]]; then PAGES_URL="${PAGES_URL}/"; fi
230-
echo "SITE_URL=$PAGES_URL" >> $GITHUB_ENV
231-
echo "SPEC_URL=${PAGES_URL}latest/specification/overview/" >> $GITHUB_ENV
199+
- uses: ./.github/actions/configure-site-url
232200

233201
- name: Deploy release version
234202
run: |

.github/workflows/linter.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
fetch-depth: 0
3737

3838
- name: Lint Code Base
39-
uses: super-linter/super-linter/slim@v8.5.0
39+
uses: super-linter/super-linter/slim@v8.6.0
4040
env:
4141
DEFAULT_BRANCH: ${{ github.base_ref }}
4242
MULTI_STATUS: false

MAINTAINERS.md

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,29 @@
2121
The Tech Council is responsible for the technical direction and overall
2222
design of the protocol.
2323

24-
<!-- cSpell:ignore Amit Handa Anurag Sinha Chris Sauve Daniel Wyckoff Drew -->
25-
<!-- cSpell:ignore Olson Ilya Grigorik Imran Hoosain Lee Richmond Maxime -->
26-
<!-- cSpell:ignore Najim Naga Malepati Venu Vemula -->
24+
<!-- cSpell:ignore Amit Handa Anurag Sinha Daniel Wyckoff Drew Olson -->
25+
<!-- cSpell:ignore Greg Smith Ilya Grigorik Imran Hoosain Lee Richmond -->
26+
<!-- cSpell:ignore James Andersen Maxime Najim Najim Naga Malepati -->
27+
<!-- cSpell:ignore Patrick Jordan Prasad Wangikar Scot DeDeo -->
28+
<!-- cSpell:ignore Twum Djin Venu Vemula Victoria Duggan -->
2729
| Name | Company |
2830
| :--- | :--- |
29-
| Aaron Glazer | Shopify |
3031
| Amit Handa | Google |
3132
| Anurag Sinha | Google |
32-
| Chris Sauve | Shopify |
3333
| Daniel Wyckoff | Shopify |
3434
| Drew Olson | Google |
35+
| Greg Smith | Amazon |
3536
| Ilya Grigorik | Shopify |
3637
| Imran Hoosain | Etsy |
38+
| James Andersen | Meta |
39+
| Lee Richmond | Shopify |
3740
| Maxime Najim | Target |
3841
| Naga Malepati | Wayfair |
42+
| Patrick Jordan | Microsoft |
43+
| Prasad Wangikar | Stripe |
44+
| Scot DeDeo | Salesforce |
3945
| Venu Vemula | Google |
40-
| Open | to be elected |
46+
| Victoria Duggan | Shopify |
4147

4248
## Governance Council
4349

@@ -48,4 +54,6 @@ the protocol.
4854
| :--- | :--- |
4955
| Amit Handa | Google |
5056
| Ilya Grigorik | Shopify |
57+
| Twum Djin | Stripe |
58+
| Open | to be elected |
5159
| Open | to be elected |

docs/documentation/roadmap.md

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,14 +34,9 @@ community feedback.
3434
To move beyond isolated transactions, we are expanding the protocol's scope to
3535
tackle key user journeys such as multi-item checkout, loyalty, and lifecycle
3636
management, while ensuring the business's brand and logic remain central to all
37-
shopping experiences. Key upcoming initiatives include:
37+
shopping experiences. With product discovery, cart building, and post-order
38+
management now part of the specification, key upcoming initiatives include:
3839

39-
* **Product discovery and post-order management:** By facilitating the entire
40-
journey, we help businesses maximize lifetime and average order value rather
41-
than just processing a single item for checkout.
42-
* **Cart and basket building:** Support for multi-item checkout from a
43-
business, complex basket rules (e.g., promotions, tax, shipping), and varied
44-
fulfillment logic that reflects how people actually shop.
4540
* **Loyalty & Member benefits:** Capabilities to enable loyalty and member
4641
benefits to help users find the best value and businesses achieve a deeper
4742
connection with their consumers through account linking.

docs/documentation/schema-authoring.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,70 @@ Capabilities outside `dev.ucp.*` version fully independently:
303303

304304
Vendor schemas follow the same self-describing requirements.
305305

306+
## Extensibility and Forward Compatibility
307+
308+
When designing schemas, you must account for how older clients will validate newer payloads. In serialization formats
309+
like Protobuf, adding a new field or enum value is generally a safe, forward-compatible change.
310+
311+
Because modern code generators (e.g. [Quicktype](https://quicktype.io/)) translate JSON Schemas into strictly typed
312+
classes (e.g., Go structs or Java Enums), certain schema constraints will cause deserialization errors on older clients
313+
as the protocol evolves. Avoiding such changes helps minimize the need to up-version the protocol.
314+
315+
### Open Enumerations
316+
317+
If a field's list of values might expand in the future (e.g., adding a `"refunded"` status or a new payment method),
318+
**do not use `enum`**.
319+
320+
Instead, define a standard `string`, document the requirement to ignore unknown values in the `description`, and use
321+
`examples` to convey current expected values to code generators. Avoid complex "Open Set" validation patterns
322+
(e.g., combining `anyOf` with `const`), as they frequently confuse client-side code generators and make schemas
323+
difficult to read.
324+
325+
```json
326+
"cancellation_reason": {
327+
"type": "string",
328+
"description": "Reason for order cancellation. Clients MUST tolerate and ignore unknown values.",
329+
"examples": ["customer_requested", "inventory_shortage", "fraud_suspected"]
330+
}
331+
```
332+
333+
### Closed Enumerations
334+
335+
Use strict `enum` or `const` only for permanently fixed domains or when unknown values are inherently unsupported.
336+
Reserve them for cases where adding a new value inherently requires integrators to update their code (e.g., protocol
337+
versions, strict type discriminators, or days of the week).
338+
339+
```json
340+
"status": {
341+
"type": "string",
342+
"enum": ["open", "completed", "expired"],
343+
"description": "Lifecycle state. This domain is strictly bounded; unknown states represent a breakdown in the state machine and MUST be rejected."
344+
}
345+
```
346+
347+
### Open Objects (`additionalProperties`)
348+
349+
Marking an object as closed preemptively prevents any future non-breaking additions to the schema. In a distributed
350+
protocol, what would otherwise be a backward-compatible field addition (e.g., adding a "gift_message" field to an order)
351+
becomes a breaking change for any client validating against a closed schema.
352+
353+
By default, JSON Schema is open and ignores unknown properties. Authors should leave this keyword omitted except in rare
354+
circumstances: polymorphic discriminators (where strictness prevents oneOf validation ambiguity), security-critical
355+
payloads (where unknown fields may indicate tampering), or protocol envelopes (where strictness is useful to catch
356+
typos in core metadata like the `ucp` block).
357+
358+
**Anti-Pattern (Prevents adding new fields without a reversion):**
359+
360+
```json
361+
"totals": {
362+
"type": "object",
363+
"properties": {
364+
"subtotal": {"type": "integer"}
365+
},
366+
"additionalProperties": false
367+
}
368+
```
369+
306370
## Complete Example: Capability Schema
307371

308372
A capability schema defines both payload structure and declaration variants:

0 commit comments

Comments
 (0)