11name : Contract Drift
2- # Fails the PR if widget's oRPC contract mirrors (src/sdk/routes.ts,
3- # src/sdk/schema.ts) have drifted STRUCTURALLY from the source of truth in
4- # Marketrix-ai/api (routes.ts, schema.ts). "Structural" = presence of routes,
5- # exported schema identifiers, and discriminated-union event tags — comments,
6- # import paths, and whitespace are ignored.
7- #
8- # Widget is a strict SUBSET of the api contract: it intentionally omits the
9- # dashboard-only `simulationIssue*` routes and `SimulationIssue*` schemas. The
10- # drift script is run with --allow-subset, which tolerates those (and only
11- # those) being absent. Anything else missing — or anything EXTRA in the widget
12- # mirror — is still drift. See scripts/check-contract-drift.mjs for the known
13- # field-level gap.
2+ # Fails the PR if widget's scoped SDK mirror (src/sdk/contract.ts + contracts/*)
3+ # has drifted from the source of truth in Marketrix-ai/api (sdk/widget.ts +
4+ # contracts/*). Uses the same sync-consumers.mjs generator in --check mode so
5+ # the gate and the write path are provably equivalent.
146#
157# TOKEN REQUIREMENT
168# -----------------
17- # This workflow reads two files from the PRIVATE Marketrix-ai/api repo, so it
18- # needs a token with read access. Create a repo or org secret:
9+ # This workflow sparse-checkouts the relevant paths from the PRIVATE
10+ # Marketrix-ai/api repo, so it needs a token with read access. Create a
11+ # repo or org secret:
1912#
2013# CONTRACTS_READ_TOKEN = fine-grained PAT with "Contents: read" on
2114# Marketrix-ai/api (read-only, no write scopes).
@@ -25,9 +18,7 @@ name: Contract Drift
2518on :
2619 pull_request :
2720 paths :
28- - src/sdk/routes.ts
29- - src/sdk/schema.ts
30- - scripts/check-contract-drift.mjs
21+ - src/sdk/**
3122 - .github/workflows/contract-drift.yml
3223 workflow_dispatch :
3324 schedule :
@@ -57,34 +48,26 @@ jobs:
5748 exit 1
5849 fi
5950
60- - name : Fetch api contract source (routes.ts, schema.ts) from Marketrix-ai/api@dev
51+ - name : Sparse-checkout api contracts + sync generator from Marketrix-ai/api@dev
6152 env :
6253 GH_TOKEN : ${{ secrets.CONTRACTS_READ_TOKEN }}
6354 run : |
6455 set -euo pipefail
6556 mkdir -p .api-src
66- for f in routes.ts schema.ts; do
67- echo "Fetching api/${f}@dev ..."
68- gh api "repos/Marketrix-ai/api/contents/${f}?ref=dev" \
69- -H 'Accept: application/vnd.github.raw' > ".api-src/${f}"
70- if [ ! -s ".api-src/${f}" ]; then
71- echo "::error::Fetched empty .api-src/${f} — check the token has Contents:read on Marketrix-ai/api and that the file exists on dev."
72- exit 1
73- fi
74- done
75-
76- - name : Check routes drift (subset mode)
77- run : |
78- node scripts/check-contract-drift.mjs \
79- --api .api-src/routes.ts \
80- --mirror src/sdk/routes.ts \
81- --kind routes \
82- --allow-subset
57+ git -C .api-src init
58+ git -C .api-src remote add origin "https://x-access-token:${GH_TOKEN}@github.com/Marketrix-ai/api.git"
59+ git -C .api-src config core.sparseCheckout true
60+ printf 'contracts/\nscripts/sync-consumers.mjs\nsdk/\n' > .api-src/.git/info/sparse-checkout
61+ git -C .api-src fetch --depth=1 origin dev
62+ git -C .api-src checkout FETCH_HEAD
63+ if [ ! -f ".api-src/scripts/sync-consumers.mjs" ]; then
64+ echo "::error::sync-consumers.mjs not found in .api-src — check token and branch."
65+ exit 1
66+ fi
8367
84- - name : Check schema drift (subset mode )
68+ - name : Check contract drift (sync-consumers --check )
8569 run : |
86- node scripts/check-contract-drift.mjs \
87- --api .api-src/schema.ts \
88- --mirror src/sdk/schema.ts \
89- --kind schema \
90- --allow-subset
70+ node .api-src/scripts/sync-consumers.mjs widget \
71+ --check \
72+ --api-root .api-src \
73+ --dest src/sdk
0 commit comments