feat(design): write/read DESIGN.md in the open spec; persisted format choice

gstack's design skills now write DESIGN.md in the open DESIGN.md format and
read tokens from it. {{DESIGN_MD_CHECK}} renders the format check through
bin/gstack-design-md.ts: design-consultation's Phase 0 settles the format once
(spec → update tokens in the front matter; legacy without a marker → one
AskUserQuestion: convert with a .legacy.bak, keep the legacy file, or start
fresh; the answer is written into the file as the format marker so no skill
asks again; a marker already present is obeyed silently; unknown → prose;
missing → Phase 6 writes one). Phase 6's template is the spec form: YAML front
matter with name, description, and exactly the five token groups (colors,
typography.display/body/label/mono with fontFeature: tnum on mono, rounded,
spacing, components with {path} references), then Overview (Creative North
Star, product context, mode per surface, references, key characteristics),
Colors (opening with the Restrained / Committed / Full palette / Drenched
strategy), Typography, Layout, Elevation & Depth, Shapes, Components, Do's and
Don'ts, plus gstack's Motion and Decisions Log as extras; the template ends
with a check that the file parses as `spec`.

design-review runs the `:calibrate` form in Setup: a spec file's flat tokens
are the calibration source (a value present in the tokens is never a finding),
the marker is respected, and conversion is never offered there; its DESIGN.md
export writes the spec form. design-html's token extraction writes the spec
form and respects an existing choice. review/design-checklist.md category 5 and
ship's review-lite step 1 name `gstack-design-md tokens` as the calibration
source; plan-design-review Pass 5 cites tokens by path when front matter
exists.

The contract owns the bin's DESIGN_MD_MARKER / REASON / WRITTEN / BACKUP
lines; the contract test's pending list closes. Carve guard: design-
consultation skeleton 66,500 → 67,500 (measured 67,014; +1,508 B against the
1.5 KB cap). Codex and Factory ship goldens refreshed (review-lite step 1).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-09-08 16:26:15 +00:00
co-authored by Claude Fable 5.1
parent e49d1eea49
commit 35d641b4b2
23 changed files with 319 additions and 93 deletions
+6
View File
@@ -50,6 +50,11 @@ export const SENTINEL = {
DESIGN_MD_CONVERT_REFUSED: 'DESIGN_MD_CONVERT_REFUSED',
DESIGN_MD_INTERNAL_ERROR: 'DESIGN_MD_INTERNAL_ERROR',
DESIGN_MD_TOKEN_REF_INVALID: 'DESIGN_MD_TOKEN_REF_INVALID',
/** printed by gstack-design-md check / convert */
DESIGN_MD_MARKER: 'DESIGN_MD_MARKER',
DESIGN_MD_REASON: 'DESIGN_MD_REASON',
DESIGN_MD_WRITTEN: 'DESIGN_MD_WRITTEN',
DESIGN_MD_BACKUP: 'DESIGN_MD_BACKUP',
} as const;
export type SentinelName = keyof typeof SENTINEL;
@@ -64,6 +69,7 @@ export const SELF_DESCRIBING_SENTINELS: readonly string[] = [
SENTINEL.HOOK_OTHER, SENTINEL.IGNORED_FILES, SENTINEL.CONFIG_UNREADABLE, SENTINEL.ENV_IGNORED,
SENTINEL.ENGINE_UNTESTED, SENTINEL.DETECT_EXIT, SENTINEL.DETECT_REFUSED, SENTINEL.DETECT_NO_TARGETS,
SENTINEL.DETECT_TIMEOUT, SENTINEL.DETECT_PARSE_ERROR, SENTINEL.DETECT_OUTPUT_TOO_LARGE,
SENTINEL.DESIGN_MD_TOKEN_REF_INVALID, SENTINEL.DESIGN_MD_WRITTEN, SENTINEL.DESIGN_MD_BACKUP,
];
/** Engine versions the committed fixtures were captured from. */