docs(vendoring): record re-sync decision and measured consumer drift

Vendoring stands: 26/27 vendored files are byte-identical in both consumers 3.5 months on, with no local drift. No re-sync command is published yet - the script is recoverable in full from catalog history and is already polyrepo-ready, but restoring it unchanged would copy this repo's root wholesale, STATE.md included.

Also records that MANIFEST.json's source_commit c1b7bad is not merely unreachable but false: the vendored tree carries components-tier4-project-view.css, which did not exist in that commit. Verified with git cat-file -e plus a known-positive control on components-tier3.css in the same commit.

Verification was find/git cat-file/SHA-256 comparison, not grep - the full log is in docs/vendoring-and-re-sync.md.
This commit is contained in:
Kjell Tore Guttormsen 2026-08-27 00:17:19 +02:00
commit c4253027ed
2 changed files with 181 additions and 0 deletions

View file

@ -12,6 +12,7 @@ Playgrounds are the visual self-service UIs that complement a plugin's terminal
- [Provenance](#provenance) - [Provenance](#provenance)
- [Directory layout](#directory-layout) - [Directory layout](#directory-layout)
- [Quick start](#quick-start) - [Quick start](#quick-start)
- [Vendoring and re-sync](#vendoring-and-re-sync)
- [Design principles](#design-principles) - [Design principles](#design-principles)
- [Token system](#token-system) - [Token system](#token-system)
- [Component reference](#component-reference) - [Component reference](#component-reference)
@ -162,6 +163,34 @@ reader switches theme — the bootstrap script only reads it back on the next lo
bootstrap script, the page renders in the HTML attribute's default theme for one frame before bootstrap script, the page renders in the HTML attribute's default theme for one frame before
JavaScript applies the saved/OS preference — the FOUC it exists to prevent. JavaScript applies the saved/OS preference — the FOUC it exists to prevent.
## Vendoring and re-sync
Vendoring remains the recommended consumer model. Measured 2026-08-27 across both consumers
(`ms-ai-architect`, `llm-security`): 26 of 27 vendored files are byte-identical to this repo's
current content three and a half months after their last sync, and neither copy has been edited
locally. The only file that differs is this README.
**There is no re-sync command today.** The `sync-design-system.mjs` script that produced the
existing vendored copies was deleted with the monorepo layout in 2026-06. It is recoverable in
full from the `catalog` repo's history and belongs in this repo once restored, but restoring it
unchanged would copy this repo's root wholesale — including files that are not part of the
delivered system. That boundary is an open decision, so no command is published here rather than
one that would be wrong.
Until then, a consumer can still check its own copy without any script:
- **Integrity** — re-hash the vendored files against the SHA-256 values in that copy's own
`MANIFEST.json`. Answers "has anyone edited the vendored files locally?"
- **Drift** — hash each vendored file, stripping the
`/* Code generated by sync-design-system.mjs; DO NOT EDIT. */` header line the sync injects into
every `.css`, and compare against the same filename at this repo's root.
`MANIFEST.json`'s `source` and `source_commit` fields in the existing copies point at the old
monorepo layout. Leave them alone for now — the recorded `source_commit` is not just unreachable
but inaccurate, and rewriting only the path would make a false pointer look plausible. See
[docs/vendoring-and-re-sync.md](docs/vendoring-and-re-sync.md) for the full decision, the
measurements behind it, and the recovery command.
## Design principles ## Design principles
1. **Aksel/Digdir-aligned.** Inter font, body 17px, Digdir blue `#0062BA`, semantic CSS tokens. Norwegian public sector users recognize this DNA. 1. **Aksel/Digdir-aligned.** Inter font, body 17px, Digdir blue `#0062BA`, semantic CSS tokens. Norwegian public sector users recognize this DNA.

View file

@ -0,0 +1,152 @@
# 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.
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
recommended consumer model, and where `MANIFEST.json`'s `source` field should
point now that the marketplace is a polyrepo.
Every number below was measured against ground truth on 2026-08-27, not
recalled. The measurements are listed in [Verification log](#verification-log)
so a reader can re-run them.
## Background
Until 2026-06-18 the marketplace was a monorepo. This design system lived at
`shared/playground-design-system/`, and `scripts/sync-design-system.mjs`
vendored it into each plugin's `playground/vendor/playground-design-system/`.
Commit `e84dffd` ("thin catalog to manifest + docs (polyrepo migration
complete)") deleted both paths in the same change. This repo was extracted as a
sibling with the CSS files at its root and a fresh 17-commit history.
Consumer documentation kept pointing at the monorepo layout, so the instructions
it gave named a directory and a script that no longer existed anywhere.
## Decision
### 1. Is vendoring still the recommended model? Yes.
This is settled first, because the other two answers depend on it.
The measurement supports keeping it. Three and a half months after the last
sync, in both consumers, **26 of 27 vendored files are byte-identical to this
repo's current content**, and each `MANIFEST.json` still matches its own files
exactly — no consumer has edited a vendored file locally. The one file that
differs is this repo's own `README.md`, which documents the system rather than
being part of what it delivers.
Vendoring did what it promised: the consumers stayed standalone and kept
rendering correctly when the source moved out from under them. What broke was
the *documentation pointing at the mechanism*, not the mechanism.
Nothing replaces it. A git submodule or an npm package would contradict the
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.
`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:
```sh
git -C <marketplace>/catalog show e84dffd^:scripts/sync-design-system.mjs
```
It is 225 lines, has no npm dependencies, and — this matters — it was **already
prepared for the polyrepo split before the split happened**. It accepts
`--source <dir>` and `--target <dir>`, both of which override the hardcoded
monorepo paths, and its own comment says the `--target` flag exists "so the
script still works once `plugins/<name>` no longer exists in-repo
(post-migration / extracted repo)". It also has a `--check` mode that re-hashes
a consumer's vendored tree against its committed `MANIFEST.json` and exits
non-zero on drift, needing no source at all.
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.
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.
### 3. Where should `MANIFEST.json`'s `source` point? Here — but not yet.
This is not the consumer's business alone: the field is written by this repo's
script and describes this repo's source, so the value is ours to define.
The important finding is that `source_commit` is not merely unreachable — **it
is false**. Both consumers record
`source_commit: c1b7bad3899c5cfe9ff90663003609b018aa79a0`, but the vendored tree
contains `components-tier4-project-view.css`, and that file demonstrably did not
exist in `c1b7bad`. The sync labelled its output with the marketplace's `HEAD`
while copying the working tree, which at that moment held a v0.6.0 file that had
not been committed yet.
The consequence for repair: **do not fix the field by translating the path.**
Rewriting `shared/playground-design-system/` to this repo's name while keeping
`c1b7bad` would turn an obviously stale pointer into a plausible false one, and
a plausible false pointer is worse — it stops inviting the check that would
catch it.
The correct order is: restore the script with a source boundary, run one
re-sync, and let the script write a truthful manifest in which `source_commit`
is this repo's `HEAD` — reachable from this repo, unlike `c1b7bad`. Until then,
a visibly stale field is the more honest state.
One correction to the premise this question arrived with: the lineage is **not**
severed. `c1b7bad` is unreachable from this repo and from either consumer, but
it is alive in `catalog`. "Nobody can compute how far behind a vendored copy is"
does not hold — it was computed, and the answer is one file.
## Current state
What a consumer can do today, with no script:
- **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.
What a consumer cannot do today: re-sync with one command. That is pending the
source-boundary decision above.
`MANIFEST.json` should be left alone in the meantime.
## Verification log
Measured 2026-08-27 against ground truth. `<marketplace>` is the polyrepo root.
| Claim | How it was checked | Result |
|---|---|---|
| `sync-design-system.mjs` absent from the marketplace | `find` over the tree, maxdepth 5, `.git`/`node_modules` pruned | 0 hits. Denominator: the same query returned 836 `.mjs` files; known-positive control found `catalog/scripts/check-versions.mjs`, so the query can find. |
| `shared/` absent | `find -type d -name 'shared*'`, maxdepth 3 | 0 hits |
| Two consumers vendor the system | `find -type d -name playground-design-system`, maxdepth 4 | `ms-ai-architect` and `llm-security`, 27 files + `MANIFEST.json` each |
| `c1b7bad` unreachable from this repo | `git cat-file -t` | fatal: could not get object info. Known-positive control on this repo's `HEAD` returned `commit`. |
| `c1b7bad` reachable from `catalog` | `git -C catalog cat-file -t` | `commit` — 2026-05-15, monorepo history, 977 commits |
| The monorepo commit held both deleted paths | `git -C catalog ls-tree -r c1b7bad` | `shared/playground-design-system/` (26 files) and `scripts/sync-design-system.mjs` both present |
| Both paths died in the migration | `git -C catalog log --diff-filter=D` | `e84dffd`, 2026-06-18, deleted both |
| `source_commit` is false | `git -C catalog cat-file -e c1b7bad:shared/playground-design-system/components-tier4-project-view.css` | path does not exist in `c1b7bad`. Known-positive control on `components-tier3.css` in the same commit succeeded. |
| 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()` |
Not verified: whether `catalog`'s history is itself mirrored anywhere off this
machine. The recovery path above assumes a local `catalog` checkout.