Skip to content

p0: formalize the contract synchronization invariant#22

Merged
ryandmonk merged 1 commit into
mainfrom
feat/p0-contract-sync
Jul 22, 2026
Merged

p0: formalize the contract synchronization invariant#22
ryandmonk merged 1 commit into
mainfrom
feat/p0-contract-sync

Conversation

@ryandmonk

Copy link
Copy Markdown
Contributor

Completes PHASE-NEXT P0 on the studio side, following dspack #22 (the one-time studio → dspack catch-up).

The invariant, now explicit and enforced: at every green commit on main, the canonical Astryx contract in dspack/examples/ and the copy consumed in packages/contracts/ are byte-identical. Repository synchronization is absolute byte equality; design-system fidelity (x-drift divergences from the Astryx component API, checked by drift-check.ts) lives inside the synchronized artifact — never conflated.

What ships:

  • packages/contracts/scripts/check-sync.mjs — the dspack-gen check-sync pattern verbatim (node builtins + fetch, one retry, --write to re-sync), wired as check:sync.
  • CI's previous inline curl | diff sync step replaced by the script — same semantics, one implementation, locally runnable. (That inline step has been failing on main since the milestone authored governance in the studio copy; this PR makes it green again and impossible to quietly ignore.)
  • PHASE-NEXT: P0 marked delivered; the invariant and the contract-change merge protocol join the standing constraints as the definition of done: canonical change in dspack first → consuming studio PR carries the byte-copied file (intent-plus-scenario PRs stay atomic, merging after their paired upstream PR) → sync checks green in both repositories.

Fail-first evidence (run before dspack #22 merged):

DRIFT    astryx.dspack.json  (the Astryx contract — copy of the spec repo's source of truth)
in sync  shadcn-ui.dspack.json
Exit status 1

After #22: both entries in sync, exit 0 — and byte identity confirmed at the git level directly against dspack main (not just through the CDN, which lagged ~4 minutes).

Follow-up queued: dspack-gen's own check-sync now correctly flags its fixtures/astryx.v0_1_2.dspack.json for re-sync — that PR lands next with regenerated goldens.

🤖 Generated with Claude Code

THE INVARIANT: at every green commit on main, the canonical Astryx
contract in dspack/examples and the copy consumed in packages/contracts
are byte-identical. Repository synchronization is absolute byte
equality; design-system fidelity (documented x-drift divergences from
the Astryx component API, checked by drift-check.ts) lives inside the
synchronized artifact — the two are never conflated.

Enforcement: packages/contracts/scripts/check-sync.mjs, the dspack-gen
check-sync pattern verbatim (node builtins + fetch, --write to
re-sync), wired as check:sync and run by CI in place of the previous
inline curl|diff step — same semantics, one implementation, locally
runnable. The contract-change merge protocol is now the documented
definition of done: canonical change lands in dspack first, the
consuming studio PR carries the byte-copied file (intent-plus-scenario
PRs stay atomic; they merge after their paired upstream PR), sync
checks green in both repositories.

Fail-first: run before dspack #22 merged, the check was red with
  DRIFT    astryx.dspack.json  (the Astryx contract — copy of the spec
           repo's source of truth)
  in sync  shadcn-ui.dspack.json
matching the CI failures main has carried since the milestone authored
governance in the studio copy. After #22: both entries in sync, exit 0,
and git-level byte identity confirmed directly against dspack main.
PHASE-NEXT: P0 marked delivered; the invariant and protocol join the
standing constraints; the take-home "byte-synced copy of dspack main"
sentence is accurate again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 22, 2026 01:52
@ryandmonk
ryandmonk merged commit aba0b69 into main Jul 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR formalizes and enforces the “contract synchronization invariant” for @dspack-studio/contracts, ensuring the locally consumed contract JSON files remain byte-identical to the canonical copies in aestheticfunction/dspack at every green commit on main.

Changes:

  • Adds a reusable sync-check script (check-sync.mjs) to compare (and optionally re-write) local contract copies against dspack/examples/* via raw.githubusercontent.com.
  • Wires the sync check into package scripts (check:sync) and replaces the CI inline curl | diff step with the new script.
  • Updates the PHASE-NEXT roadmap to mark P0 delivered and document the invariant + merge protocol.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
packages/contracts/scripts/check-sync.mjs Introduces a Node script to detect/write byte-level drift vs canonical upstream contracts.
packages/contracts/package.json Adds check:sync script entry to run the sync check locally/CI.
docs/PHASE-NEXT.md Documents the invariant and marks P0 as delivered with updated protocol wording.
.github/workflows/ci.yml Replaces inline `curl

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread docs/PHASE-NEXT.md
Comment on lines +71 to +73
copies. Enforcement: `packages/contracts/scripts/check-sync.mjs`
(`pnpm --filter @dspack-studio/contracts check:sync`, `--write` to
re-sync locally), run by CI on every push and PR; dspack-gen's existing
Comment on lines +81 to +83
console.error(` canonical change lands in dspack first; then either`);
console.error(` node scripts/check-sync.mjs --write, or copy this file upstream via a dspack PR.`);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants