feat(consumer): versioned IR manifest + drift-check (WHYNOT-WP-0003 T03-T07,T09)
Make ir/ the unit of versioned downstream consumption so consuming repos can pin a version, inspect it, and follow changes at their own pace. - T03 ir/manifest.json: per-version inventory + diff anchor with deterministic sha256-over-canonicalised-JSON hashes; no-churn generatedAt; manifest schema. - T07 ir/INDEX.md: human-readable catalog generated by make ir. - T04 .whynot-design.lock sync-point format + lock schema. - T05 npx @whynot/design drift: consumer drift-check (bin entry), exit 0/2/3, --json/--update/--manifest/--version/--lock. - T06 CONSUMING.md guide + examples/consumer-fixture/ runnable demo; README + MultiFrameworkSupport cross-links; fix README version pin (@0.3.0 not @v0.3.0). - T09 CONSUMER_CONTRACT_PARITY.md design-only note (live-UI parity deferred). T02 (publish) and T08 (showcase, blocked on WP-0002 T11) remain wait. Repo stays in dev mode; no outward publish performed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
36
examples/consumer-fixture/README.md
Normal file
36
examples/consumer-fixture/README.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# consumer-fixture — the drift loop, copy-pasteable
|
||||
|
||||
A tiny stand-in for a repo that **consumes** `@whynot/design`. It exercises the
|
||||
full downstream loop — **pin → inspect → drift → update** — against this repo's
|
||||
own `ir/manifest.json`, with no real npm install, so you can see exactly what a
|
||||
consumer experiences.
|
||||
|
||||
```bash
|
||||
./run.sh
|
||||
```
|
||||
|
||||
What it shows:
|
||||
|
||||
1. **Inspect** — the head of `ir/INDEX.md` (the browsable catalog of the version).
|
||||
2. **drift** — [`adopted.lock`](./adopted.lock) is a sample `.whynot-design.lock`
|
||||
pinned to a pretend older `0.2.0` sync-point (Button changed since, TopNav added
|
||||
since, tokens changed). `drift` reports those and exits `3`.
|
||||
3. **drift --update** — adopts the current version as the new sync-point.
|
||||
4. **drift** again — now in sync, exits `0`.
|
||||
|
||||
The run is **non-destructive**: `adopted.lock` is copied into a scratch dir and
|
||||
only the copy is mutated.
|
||||
|
||||
## In a real consuming repo
|
||||
|
||||
You would **not** pass `--manifest`/`--lock`. The installed package supplies its
|
||||
own `ir/manifest.json`, and the lock lives at `./.whynot-design.lock`:
|
||||
|
||||
```bash
|
||||
npm i @whynot/design@0.3.0 lit # pin
|
||||
npx @whynot/design drift --update # adopt a sync-point (writes .whynot-design.lock)
|
||||
# ...later, after bumping the version...
|
||||
npx @whynot/design drift # see what changed; exit 3 on drift
|
||||
```
|
||||
|
||||
Full guide: [`../../CONSUMING.md`](../../CONSUMING.md).
|
||||
19
examples/consumer-fixture/adopted.lock
Normal file
19
examples/consumer-fixture/adopted.lock
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"designVersion": "0.2.0",
|
||||
"adoptedAt": "2026-05-01T12:00:00.000Z",
|
||||
"manifestSchemaVersion": "1.0.0",
|
||||
"manifestHashes": {
|
||||
"tokens": "sha256:00000000bbbbbbbb",
|
||||
"components": {
|
||||
"Button": "sha256:00000000aaaaaaaa",
|
||||
"Eyebrow": "sha256:56baa59a49b5f32c",
|
||||
"Icon": "sha256:2557fbffb3aa6ee1",
|
||||
"PageHeader": "sha256:93e12068e2f58f10",
|
||||
"PipelineStrip": "sha256:89c40afe4742d64e",
|
||||
"Sidebar": "sha256:8340b292fff7a80d",
|
||||
"StageDot": "sha256:f6f7790aa886261e",
|
||||
"Stamp": "sha256:0b32f43ed19ac470",
|
||||
"Tag": "sha256:91ee34eac1457016"
|
||||
}
|
||||
}
|
||||
}
|
||||
38
examples/consumer-fixture/run.sh
Executable file
38
examples/consumer-fixture/run.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env bash
|
||||
# Exercise the consumer drift loop against this repo's own ir/manifest.json,
|
||||
# without a real npm install. Non-destructive: the committed adopted.lock is
|
||||
# copied into a scratch dir; only that copy is mutated.
|
||||
#
|
||||
# In a REAL consuming repo you would not pass --manifest at all — the installed
|
||||
# @whynot/design package supplies its own ir/manifest.json, and the lock lives at
|
||||
# ./.whynot-design.lock. Here we point at the repo copy so the demo is hermetic.
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
REPO_ROOT="$(cd ../.. && pwd)"
|
||||
CLI="$REPO_ROOT/bin/whynot-design.mjs"
|
||||
MANIFEST="$REPO_ROOT/ir/manifest.json"
|
||||
|
||||
WORK="$(mktemp -d)"
|
||||
trap 'rm -rf "$WORK"' EXIT
|
||||
cp adopted.lock "$WORK/.whynot-design.lock"
|
||||
LOCK="$WORK/.whynot-design.lock"
|
||||
|
||||
echo "### 1. Inspect — what's in this version"
|
||||
sed -n '1,6p' "$REPO_ROOT/ir/INDEX.md"
|
||||
echo
|
||||
|
||||
echo "### 2. drift — what changed since the adopted (0.2.0) sync-point (expect exit 3)"
|
||||
set +e
|
||||
node "$CLI" drift --manifest "$MANIFEST" --lock "$LOCK"
|
||||
echo "(exit $?)"
|
||||
set -e
|
||||
echo
|
||||
|
||||
echo "### 3. drift --update — adopt the current version as the new sync-point"
|
||||
node "$CLI" drift --manifest "$MANIFEST" --lock "$LOCK" --update >/dev/null
|
||||
echo
|
||||
|
||||
echo "### 4. drift again — now in sync (expect exit 0)"
|
||||
node "$CLI" drift --manifest "$MANIFEST" --lock "$LOCK"
|
||||
echo "(exit $?)"
|
||||
Reference in New Issue
Block a user