feat(sync): restore sync-design-system.mjs with an explicit source boundary

The script that produced the existing vendored copies was deleted with the
monorepo layout in 2026-06 and recovered from catalog's history
(e84dffd^:scripts/sync-design-system.mjs). It could not be restored unchanged:
it walks its source directory and copies everything, and this repo's root is no
longer a directory holding only the design system. Run verbatim it vendored 109
files instead of 27, STATE.md and the whole of .git/ among them - and STATE.md
is gitignored precisely because this repo's remote is public.

The boundary is an explicit allowlist (DELIVERED_FILES) rather than a dist/
directory: one definition, read directly by the tests, with no copy step to go
stale. The allowlist's own failure mode - a new design-system file forgotten
from the list ships nothing, and --check stays green because it hashes a
consumer's tree against that consumer's own MANIFEST - is closed by scanning
the source for unlisted root-level *.css, fonts/* and schemas/* and refusing to
run.

tests/sync-source-boundary.test.mjs pins both directions. It was red on the
verbatim script for the right reason (STATE.md present in the target, with
tokens.css as the known-positive control) before the boundary was written.

--target is the consumer's repo root; the script appends
playground/vendor/playground-design-system/ itself. --check verified read-only
against both consumers: MANIFEST OK (27 files) for ms-ai-architect and
llm-security alike. No re-sync was run, so both MANIFEST.json files are
untouched and the stale source_commit is still theirs to inherit at the first
real re-sync.

README and docs/vendoring-and-re-sync.md now publish the command, and warn that
a plain diff/cmp against this repo reports all nine stylesheets as drifted
because the sync injects a generated-header line the source does not have -
17/27 raw, 26/27 with line 1 stripped. Found by ms-ai-architect, re-measured
here.
This commit is contained in:
Kjell Tore Guttormsen 2026-08-27 00:45:58 +02:00
commit 7448cec304
4 changed files with 601 additions and 51 deletions

View file

@ -1,8 +1,8 @@
# Vendoring and re-sync
**Status:** decision recorded 2026-08-27. The re-sync script is recoverable but
not yet restored — see [Current state](#current-state) for what a consumer can
and cannot do today.
**Status:** decision recorded 2026-08-27; the re-sync script was restored the
same day with an explicit source boundary. See
[Current state](#current-state) for the published command.
This document answers three questions raised by a consumer repo on 2026-08-26:
whether a current re-sync path exists, whether vendoring is still the
@ -47,11 +47,11 @@ Non-goals in [README.md](../README.md): no build step, no bundler, no package
registry, and a Playground that opens from `file://` with only the CSS files
alongside it.
### 2. Is there a current re-sync path? Not yet — but the script is not lost.
### 2. Is there a current re-sync path? Yes, since 2026-08-27.
`scripts/sync-design-system.mjs` is absent from the entire marketplace tree
today. It survives in full in the `catalog` repo's history, which carries the
pre-migration monorepo history (977 commits). It can be read back with:
`scripts/sync-design-system.mjs` was absent from the entire marketplace tree.
It survived in full in the `catalog` repo's history, which carries the
pre-migration monorepo history (977 commits), and was read back with:
```sh
git -C <marketplace>/catalog show e84dffd^:scripts/sync-design-system.mjs
@ -70,19 +70,31 @@ So restoring it is recovery, not new development, and it belongs in **this
repo** — the mechanism vendors *from* the design system, so the design system
owns it.
**It cannot be restored unchanged, and that is why no command is published
here yet.** The script walks its source directory and copies everything it
finds. In the monorepo, `shared/playground-design-system/` contained only the
design system. This repo's root contains the design system *plus* the repo
apparatus: `STATE.md`, `LICENSE`, `SECURITY.md`, `.git/`, `docs/`, and
`playground-examples/`. A naive `--source .` would vendor all of it into both
consumers — including `STATE.md`, which is deliberately gitignored and must
never reach a public mirror.
**It could not be restored unchanged.** The script walked its source directory
and copied everything it found. In the monorepo, `shared/playground-design-system/`
contained only the design system. This repo's root contains the design system
*plus* the repo apparatus: `STATE.md`, `LICENSE`, `SECURITY.md`, `.git/`,
`docs/`, and `playground-examples/`. That is not a hypothetical: run verbatim
against this repo's root, the recovered script vendored **109 files instead of
27**, `STATE.md` and the whole of `.git/` among them — and `STATE.md` is
deliberately gitignored because this repo's remote is public.
Restoration therefore needs an explicit source boundary — an allowlist of the
27 delivered files, or a `dist/` directory the script reads from. Choosing
between those is the next decision, and it is a real one; publishing a
`--source .` command today would be a guess that leaks.
The boundary chosen is an **explicit allowlist** (`DELIVERED_FILES` in the
script) rather than a `dist/` directory. A `dist/` would duplicate every
stylesheet and insert a copy step that can silently go stale; the allowlist
names the delivered set in one place that the tests read directly, so there is
no second definition to drift from.
An allowlist has one failure mode of its own: a file added to the design system
but not to the list would silently stop shipping, and `--check` would never
notice, because it hashes a consumer's tree against that consumer's own
`MANIFEST.json` and never against the source. This repo has already lived
through that shape once — `components-tier4-project-view.css` was added in
v0.6.0 and was missing from the README's own directory tree until 2026-08-18.
So the script scans the source for design-system files the allowlist does not
name (root-level `*.css`, plus everything under `fonts/` and `schemas/`) and
refuses to run, naming the file. Both directions are covered by
`tests/sync-source-boundary.test.mjs`.
### 3. Where should `MANIFEST.json`'s `source` point? Here — but not yet.
@ -115,20 +127,40 @@ does not hold — it was computed, and the answer is one file.
## Current state
What a consumer can do today, with no script:
Re-sync, run from a checkout of this repo with the consumer checked out
alongside it:
- **Verify integrity** — re-hash the vendored files against the SHA-256 values
in the copy's own `MANIFEST.json`. This needs nothing but the consumer's own
checkout and answers "has anyone edited the vendored copy locally?"
- **Measure drift against this repo** — hash each vendored file (stripping the
`/* Code generated by sync-design-system.mjs; DO NOT EDIT. */` header line
that the sync injects into every `.css`) and compare against the file of the
same name at this repo's root.
```sh
node scripts/sync-design-system.mjs <consumer-name> --target ../<consumer-repo>
```
What a consumer cannot do today: re-sync with one command. That is pending the
source-boundary decision above.
Integrity check, which needs no source checkout and writes nothing to the
consumer:
`MANIFEST.json` should be left alone in the meantime.
```sh
node scripts/sync-design-system.mjs <consumer-name> --target ../<consumer-repo> --check
```
`--target` is the consumer's **repo root**; the script appends
`playground/vendor/playground-design-system/` itself. Pointing `--target` at
the vendor directory instead makes `--check` look one level too deep, find no
`MANIFEST.json`, and report drift that does not exist.
One trap worth naming for anyone checking by hand instead. The sync injects
`/* Code generated by sync-design-system.mjs; DO NOT EDIT. */` as line 1 of
every `.css`, and the source has no such line, so a plain `diff` or `cmp`
against this repo reports **all nine stylesheets as drifted** when none of them
is: raw `cmp` matches 17 of 27 files, and stripping line 1 from the vendored
`.css` files puts it back at 26 of 27 with this repo's README the only real
difference. `--check` is immune, because it hashes the vendored tree against
`MANIFEST.json`, which was built after the header was injected. This was found
by `ms-ai-architect` on their own copy and re-measured here (see the
[Verification log](#verification-log)).
`MANIFEST.json` should still be left alone. This session restored the script
but ran no re-sync, so the fields described in § 3 above are unchanged and the
reasoning there still holds: the first real re-sync is what rewrites them
truthfully.
## Verification log
@ -147,6 +179,11 @@ Measured 2026-08-27 against ground truth. `<marketplace>` is the polyrepo root.
| No local drift in either consumer | SHA-256 of each vendored file vs its own `MANIFEST.json` | both `MANIFEST OK`, 27/27 |
| Drift vs this repo | SHA-256 vs this repo's root, generated-header stripped from `.css` | 26/27 identical in both consumers; `README.md` the only difference |
| The recovered script supports polyrepo | read of `git show e84dffd^:scripts/sync-design-system.mjs` | `--source`, `--target`, `--check` all present and honoured in `main()` |
| The verbatim script leaks this repo's apparatus | ran the recovered script unchanged, `--source <repo root>`, into a temp target | 109 files vendored instead of 27; `STATE.md`, `.git`, `.gitignore`, `docs`, `playground-examples`, `LICENSE`, `SECURITY.md` all present. `tests/sync-source-boundary.test.mjs` red on this build, with `tokens.css` present as the known-positive control proving the assertions read the right path. |
| The allowlisted script does not leak | `node --test tests/sync-source-boundary.test.mjs` after the boundary was added | 2/2 pass: 27 files + `MANIFEST.json`, none of the seven apparatus entries present |
| An unlisted design-system file fails the sync | test adds `components-tier5.css` to a complete synthetic source | non-zero exit, filename named in stderr. Known-positive control: the same source without the extra file syncs cleanly. |
| The published `--check` command works against both consumers | `node scripts/sync-design-system.mjs <name> --target ../<name> --check` | `MANIFEST OK (27 files, source_commit c1b7bad3899c5cfe9ff90663003609b018aa79a0)`, exit 0, for `ms-ai-architect` and `llm-security` alike |
| A raw `cmp` misreports the CSS as drifted | `cmp` per file vs this repo's root, then `cmp` with line 1 stripped | raw: 17/27 match, the 10 differing being 9 `.css` + `README.md`; line-1-stripped: 26/27, `README.md` alone. Independently re-measured here; matches `ms-ai-architect`'s finding exactly. |
Not verified: whether `catalog`'s history is itself mirrored anywhere off this
machine. The recovery path above assumes a local `catalog` checkout.