Files
msd-core/tests/ui-consideration-probe-docs-fixtures.test.cjs
Dave 4bce86650d feat(#1867): add UI Considerations section to UI-SPEC template (WIRE-02)
Record resolved UI-state considerations in the UI-SPEC, backward-compatibly
(Phase 2, WIRE-02). templates/UI-SPEC.md gains a '## UI Considerations' section
(analog of SPEC '## Edge Coverage') after '## Copywriting Contract' — a
| Category | Element(s) | Status | Resolution / Reason | table with
covered/backstop/unresolved rows in the locked probe-core projectTruths format
the shipped plan-phase lift (plan-phase.md:921) reads. Empty/error COPY stays in
Copywriting; this section covers shape-rooted STATE and references those rows
(de-dup).

Tests: docs-fixtures parsed-heading assertion (UI Considerations present +
distinct from Copywriting Contract; allow-test-rule, parsed structure); typed
backward-compat (projectTruths(undefined/[])===[], old UI-SPEC still plans —
Hyrum), format-match, and idempotency (proposeElements determinism). The
template-structure test was the RED driver.

Install-parity cascade (INVENTORY-MANIFEST + 16 golden fixtures +
agent-size-baseline) deferred to Phase 3 SHIP-01, as planned.

Claude-Session: https://claude.ai/code/session_01BKt4hgNZwXSeJYJtYAQUSS
2026-07-10 14:40:03 -04:00

69 lines
3.6 KiB
JavaScript

// allow-test-rule: runtime-contract-is-the-product (see #1867) — the rendered reference doc's taxonomy table IS the runtime contract; this pins its bijection to the code (docs-parity, ADR-456 exception matrix)
// Asserts gsd-core/references/ui-consideration-probe.md keeps its taxonomy id column in
// sync with the source-of-truth UI_TAXONOMY (built .cjs), and that the closed compiled
// taxonomy stays DISJOINT from the open-prose domain-probes.md bank (the mixed-axis boundary,
// ADPT-02). The comparison is on PARSED table ids and PARSED `##` headings, never a raw
// full-text substring match — a reformat that preserves the data does not fail; semantic drift does.
'use strict';
process.env.GSD_TEST_MODE = '1';
const { test, describe } = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const uc = require(path.join(__dirname, '..', 'gsd-core', 'bin', 'lib', 'ui-consideration-probe.cjs'));
const docPath = path.join(__dirname, '..', 'gsd-core', 'references', 'ui-consideration-probe.md');
const domainPath = path.join(__dirname, '..', 'gsd-core', 'references', 'domain-probes.md');
const templatePath = path.join(__dirname, '..', 'gsd-core', 'templates', 'UI-SPEC.md');
// Extract the first-column ids from the `## Taxonomy` markdown table (skips the `id` header
// row and the `|----|` separator; an id is a lowercase-hyphen token).
function docTaxonomyIds(md) {
const section = md.split(/^## Taxonomy/m)[1].split(/^## /m)[0];
return section.split('\n')
.filter((l) => l.trim().startsWith('|'))
.map((l) => l.split('|')[1].trim())
.filter((c) => /^[a-z][a-z0-9-]*$/.test(c) && c !== 'id');
}
// The `##` topic headings of the open-prose bank (lower-cased).
function domainTopics(md) {
return md.split('\n')
.filter((l) => /^## /.test(l))
.map((l) => l.replace(/^## /, '').trim().toLowerCase());
}
describe('ui-consideration-probe doc/code parity (ADPT-02)', () => {
test('reference doc exists', () => {
assert.ok(fs.existsSync(docPath), `${docPath} must exist`);
});
test('doc taxonomy ids deep-equal the code UI_TAXONOMY ids, in order (doc == code)', () => {
const md = fs.readFileSync(docPath, 'utf8');
assert.deepEqual(docTaxonomyIds(md), uc.UI_TAXONOMY.map((c) => c.id));
});
test('no taxonomy id overlaps a domain-probes.md open-prose topic (closed/open disjointness)', () => {
const topics = domainTopics(fs.readFileSync(domainPath, 'utf8'));
for (const id of uc.UI_TAXONOMY.map((c) => c.id)) {
assert.ok(!topics.includes(id), `taxonomy id "${id}" must not overlap a domain-probes.md topic`);
}
});
test('the doc names domain-probes.md as the companion open-prose bank (links, does not duplicate)', () => {
const md = fs.readFileSync(docPath, 'utf8');
assert.match(md, /domain-probes\.md/);
});
});
describe('UI-SPEC template `## UI Considerations` section (WIRE-02 SC3 de-dup)', () => {
// PARSED `##` headings only (never a raw copy substring) — a reformat that preserves the data
// does not fail; a missing/merged section does. Reuses the domainTopics() heading parser.
test('template ## headings include BOTH `UI Considerations` and `Copywriting Contract` as distinct sections', () => {
const headings = domainTopics(fs.readFileSync(templatePath, 'utf8'));
assert.ok(headings.includes('ui considerations'), 'template must gain a ## UI Considerations section');
assert.ok(headings.includes('copywriting contract'), 'template must retain the distinct ## Copywriting Contract section (de-dup, not a rename)');
});
});