diff --git a/CHANGELOG.md b/CHANGELOG.md index aec4847..f9a7ff3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ ## Unreleased +- Preserved no-config UI implementation contracts with the JudgmentKit package-default design-system source while validating malformed explicit `design_system_source` values as failures. +- Retired public `/design-system` pages in favor of the canonical Surfaces contract without removing JudgmentKit's built-in package default. + ## 0.5.0 - 2026-06-20 - Added `review_cognitive_dimensions_candidate` as a library and MCP tool for reviewing UI workflow or implementation candidates against activity mapping, evidence visibility, hidden dependencies, premature commitment, progressive evaluation, change cost, mental operations, role expressiveness, and disclosure discipline. diff --git a/README.md b/README.md index c46a012..dcc06a8 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ The canonical examples live beside it: They cover setup/onboarding, an operational dashboard, and a high-stakes review/refund workflow. The renderer package is still deferred; these examples prove the contract and repair behavior before visual rendering. -By default, `implementation_contract.design_system_source.mode` is `judgmentkit_default`: tokens, font roles, icon catalog policy, and component contracts come from JudgmentKit `/design-system/` exports. If a complete `design_system_adapter` is supplied to `create_ui_implementation_contract`, the mode becomes `external_design_system` and that adapter owns tokens, typography, icons, and renderer components. Incomplete external adapters fail instead of falling back to JudgmentKit defaults. +By default, `implementation_contract.design_system_source.mode` is `judgmentkit_default`: tokens, font roles, icon catalog policy, and component contracts come from the JudgmentKit package default. Public `/design-system/` routes are retired and are not the source of truth for this default. If a complete `design_system_source` or `design_system_adapter` is supplied to `create_ui_implementation_contract`, the mode becomes `external_design_system` and that source owns tokens, typography, icons, and renderer components. Incomplete external sources or adapters fail instead of falling back to JudgmentKit defaults. The JudgmentKit default source does not load a font CDN, runtime icon CDN, or external runtime icon package. Font guidance uses system stacks, and icon guidance points to the committed Lucide catalog exposed through `list_icon_catalog`, `search_icon_catalog`, and `get_icon_svg`. diff --git a/api/design-system-retired.js b/api/design-system-retired.js new file mode 100644 index 0000000..b761a3a --- /dev/null +++ b/api/design-system-retired.js @@ -0,0 +1,47 @@ +const CANONICAL_SURFACES_DESIGN_SYSTEM_URL = + "https://surfaces.systems/design-system"; +const DESIGN_SYSTEM_MIGRATION_CODE = "judgmentkit_design_system_retired"; + +function requestedPath(req) { + const queryPath = req.query?.requestedPath; + + if (Array.isArray(queryPath)) { + return queryPath[0] ?? "/design-system"; + } + + if (typeof queryPath === "string" && queryPath.length > 0) { + return queryPath; + } + + return req.url ?? "/design-system"; +} + +export default function handler(req, res) { + if (req.method !== "GET" && req.method !== "HEAD") { + res.statusCode = 405; + res.setHeader("Allow", "GET, HEAD"); + res.end("Method not allowed.\n"); + return; + } + + const payload = { + code: DESIGN_SYSTEM_MIGRATION_CODE, + message: + "judgmentkit.ai/design-system is retired. Use the canonical Surfaces design-system contract.", + canonicalUrl: CANONICAL_SURFACES_DESIGN_SYSTEM_URL, + requestedPath: requestedPath(req), + }; + const body = `${JSON.stringify(payload, null, 2)}\n`; + + res.statusCode = 410; + res.setHeader("Content-Type", "application/json; charset=utf-8"); + res.setHeader("Cache-Control", "public, max-age=300"); + res.setHeader("Content-Length", Buffer.byteLength(body)); + + if (req.method === "HEAD") { + res.end(); + return; + } + + res.end(body); +} diff --git a/contracts/ai-ui-generation.activity-contract.json b/contracts/ai-ui-generation.activity-contract.json index a0447e0..58b1135 100644 --- a/contracts/ai-ui-generation.activity-contract.json +++ b/contracts/ai-ui-generation.activity-contract.json @@ -1586,7 +1586,7 @@ "mode": "judgmentkit_default", "name": "JudgmentKit", "package": "judgmentkit", - "definition_point": "implementation_contract", + "definition_point": "package_default", "required_authorities": [ "tokens", "fonts", @@ -1596,13 +1596,13 @@ "fallback_policy": "fail_incomplete", "provenance_required": true, "source_exports": { - "overview": "/design-system/", - "manifest": "/design-system/manifest.json", - "visual_token_adapter": "/design-system/visual-token-adapter.json", - "component_contracts": "/design-system/component-contracts.json", - "pattern_contracts": "/design-system/pattern-contracts.json", - "accessibility_policy": "/design-system/accessibility-policy.json", - "icon_catalog": "/design-system/icons/", + "overview": "package://judgmentkit/design-system/", + "manifest": "package://judgmentkit/design-system/manifest.json", + "visual_token_adapter": "package://judgmentkit/design-system/visual-token-adapter.json", + "component_contracts": "package://judgmentkit/design-system/component-contracts.json", + "pattern_contracts": "package://judgmentkit/design-system/pattern-contracts.json", + "accessibility_policy": "package://judgmentkit/design-system/accessibility-policy.json", + "icon_catalog": "package://judgmentkit/design-system/icons/", "icon_tools": [ "list_icon_catalog", "search_icon_catalog", @@ -1658,9 +1658,9 @@ ], "component_contract_source": "implementation_contract.default_ai_native_design_system.component_contracts", "provenance_rules": [ - "visual tokens, fonts, icons, and renderer components must come from this active design-system source", + "visual tokens, fonts, icons, and renderer components come from the JudgmentKit package default when no design system is supplied", "local CSS may define layout and UI structure but must not become the source of visual tokens, typography, icon assets, or renderer components", - "external design systems must be supplied as complete contract-time adapters; missing authorities do not fall back to JudgmentKit defaults" + "external design systems must be supplied as complete contract-time adapters or complete design-system sources; missing authorities do not fall back to JudgmentKit defaults" ] }, "visual_token_adapter": { diff --git a/contracts/judgmentkit-kernel.schema.json b/contracts/judgmentkit-kernel.schema.json index ea893ba..52f5c78 100644 --- a/contracts/judgmentkit-kernel.schema.json +++ b/contracts/judgmentkit-kernel.schema.json @@ -334,19 +334,25 @@ "default_include_svg" ], "properties": { - "source": { "type": "string" }, - "library": { "type": "string" }, - "package": { "type": "string" }, - "version": { "type": "string" }, + "source": { "type": "string", "minLength": 1 }, + "library": { "type": "string", "minLength": 1 }, + "package": { "type": "string", "minLength": 1 }, + "version": { "type": "string", "minLength": 1 }, "icon_count": { "type": "number", "minimum": 1 }, - "license": { "type": "string" }, - "notice": { "type": "string" }, - "style_system": { "type": "string" }, + "license": { "type": "string", "minLength": 1 }, + "notice": { "type": "string", "minLength": 1 }, + "style_system": { "type": "string", "minLength": 1 }, "style_attributes": { "type": "object", + "minProperties": 1, "additionalProperties": { "type": "string" } }, - "mcp_tools": { "type": "array", "items": { "type": "string" } }, + "mcp_tools": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "type": "string", "minLength": 1 } + }, "default_include_svg": { "type": "boolean" } } }, @@ -502,16 +508,18 @@ "provenance_rules" ], "properties": { - "id": { "type": "string" }, + "id": { "type": "string", "minLength": 1 }, "mode": { "type": "string", "enum": ["judgmentkit_default", "external_design_system"] }, - "name": { "type": "string" }, - "package": { "type": "string" }, - "definition_point": { "type": "string" }, + "name": { "type": "string", "minLength": 1 }, + "package": { "type": "string", "minLength": 1 }, + "definition_point": { "type": "string", "minLength": 1 }, "required_authorities": { "type": "array", + "minItems": 4, + "uniqueItems": true, "items": { "type": "string", "enum": ["tokens", "fonts", "icons", "components"] @@ -524,26 +532,36 @@ "provenance_required": { "type": "boolean" }, "source_exports": { "type": "object", + "minProperties": 1, "additionalProperties": { "oneOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } + { "type": "string", "minLength": 1 }, + { + "type": "array", + "minItems": 1, + "items": { "type": "string", "minLength": 1 } + } ] } }, "token_prefixes": { "type": "array", - "items": { "type": "string" } + "minItems": 1, + "uniqueItems": true, + "items": { "type": "string", "minLength": 1 } }, "icon_catalog": { "$ref": "#/$defs/iconCatalog" }, "renderer_components": { "type": "array", - "items": { "type": "string" } + "minItems": 1, + "uniqueItems": true, + "items": { "type": "string", "minLength": 1 } }, - "component_contract_source": { "type": "string" }, + "component_contract_source": { "type": "string", "minLength": 1 }, "provenance_rules": { "type": "array", - "items": { "type": "string" } + "minItems": 1, + "items": { "type": "string", "minLength": 1 } } } }, diff --git a/docs/agent-usage-contract.md b/docs/agent-usage-contract.md index cafb4e2..3d43bff 100644 --- a/docs/agent-usage-contract.md +++ b/docs/agent-usage-contract.md @@ -10,7 +10,7 @@ Use JudgmentKit before UI generation, UI critique, implementation planning, or h 4. Call `recommend_surface_types` to classify the activity purpose before workflow or frontend implementation guidance. 5. If a model or agent proposes a UI workflow, call `review_ui_workflow_candidate` before treating it as acceptable. 6. Call `review_cognitive_dimensions_candidate` when a workflow or implementation candidate needs Cognitive Dimensions review for mapping, visibility, hidden dependencies, premature commitment, progressive evaluation, change cost, mental operations, or disclosure. -7. Call `create_ui_implementation_contract`. Use the default JudgmentKit design-system source, or pass a complete `design_system_adapter` when an external design system should own tokens, typography, icons, and renderer components. +7. Call `create_ui_implementation_contract`. Omit design-system fields to use the JudgmentKit package default, or pass a complete `design_system_source` or `design_system_adapter` when an external design system should own tokens, typography, icons, and renderer components. 8. Call `create_ui_generation_handoff` on the reviewed workflow with the implementation contract before generating UI. Pass the Cognitive Dimensions review when it should block handoff until ready. 9. Call `create_frontend_generation_context` when frontend implementation guidance needs a selected surface type, project frontend context, and verification expectations. 10. Call `create_frontend_implementation_skill_context` when the implementing agent needs a compiled frontend skill packet that is portable across MCP clients. @@ -24,7 +24,7 @@ Use JudgmentKit before UI generation, UI critique, implementation planning, or h - Treat `needs_source_context` as a prompt to gather source context or ask the packet's targeted questions. - Treat surface type as activity-purpose guidance, not visual styling. - Treat the implementation contract as the authority for allowed primitives, control semantics, states, static checks, browser QA, visual asset handling, and accessibility evidence. -- Treat `implementation_contract.design_system_source` as the active authority for visual tokens, typography, icon assets, and renderer components. `judgmentkit_default` uses JudgmentKit `/design-system/` exports; `external_design_system` requires a complete adapter and has no implicit JudgmentKit fallback. `external_authority` is trace metadata unless paired with `design_system_adapter`. +- Treat `implementation_contract.design_system_source` as the active authority for visual tokens, typography, icon assets, and renderer components. When no external source is supplied, JudgmentKit uses its package default. `external_design_system` requires a complete source or adapter and has no implicit JudgmentKit fallback. `external_authority` is trace metadata unless paired with `design_system_source` or `design_system_adapter`. - Treat `visual_token_adapter` as the token/font/icon evidence envelope for the active design-system source. Asset guidance cannot replace activity fit, primitive coverage, state coverage, accessibility evidence, static checks, or browser QA. - Keep implementation terms out of product UI unless the activity is setup, debugging, auditing, integration, or explicit source inspection. - When a model proposes an activity model, call `review_activity_model_candidate` before trusting it. @@ -53,7 +53,7 @@ Before handing off UI work, confirm: - implementation terms contained in disclosure, evidence, or guardrails - workflow topology, work units, surface set, primary actions, decision support, and handoff are named - implementation contract names approved primitives and required states -- token, font, icon, and renderer component guidance comes from `implementation_contract.design_system_source`, with no implied font CDN, remote icon package, or fallback from external systems to JudgmentKit defaults +- token, font, icon, and renderer component guidance comes from `implementation_contract.design_system_source`, with no implied font CDN, remote icon package, or fallback from external systems to JudgmentKit default assets - substantive visual requirements have an image-generation, premium 3D/rendering, or high-quality visualization path when present - static checks, browser QA, core accessibility evidence, and any conditional visual-background contrast, non-text contrast, forced-colors, target-size, focus-not-obscured, no-keyboard-trap, reduced-motion, pause/stop/hide, form/error/status, media alternative, or semantic fallback evidence are specified when required - review-packet terms are not copied into the product UI diff --git a/docs/daily-agent-workflows.md b/docs/daily-agent-workflows.md index 8cdb45f..5ed81da 100644 --- a/docs/daily-agent-workflows.md +++ b/docs/daily-agent-workflows.md @@ -224,7 +224,7 @@ review_cognitive_dimensions_candidate({ brief, candidate, activity_review, surfa Use the returned `findings` and `repair_instructions` as diagnostic guidance. If a Cognitive Dimensions review is supplied to the handoff gate, it must be `ready_for_review`. -Call `create_ui_implementation_contract` with the default JudgmentKit design-system source, or with a complete `design_system_adapter` when an external design system should own tokens, typography, icons, and renderer components. `external_authority` is trace metadata unless it is paired with a complete adapter. The implementation contract names approved primitives, required states, static checks, browser QA expectations, `design_system_source`, visual asset policy, and accessibility policy. +Call `create_ui_implementation_contract`. Omit design-system fields to use the JudgmentKit package default, or pass a complete `design_system_source` or `design_system_adapter` when an external design system should own tokens, typography, icons, and renderer components. `external_authority` is trace metadata unless it is paired with a source or complete adapter. The implementation contract names approved primitives, required states, static checks, browser QA expectations, `design_system_source`, visual asset policy, and accessibility policy. MCP handoff calls should pass this packet as `implementation_contract`. @@ -241,6 +241,7 @@ Library equivalent: ```js const workflowReview = reviewUiWorkflowCandidate(brief, workflowCandidate); const implementationContract = createUiImplementationContract({ + design_system_source: optionalCompleteExternalDesignSystemSource, design_system_adapter: optionalCompleteExternalDesignSystemAdapter, }); const handoff = createUiGenerationHandoff(workflowReview, { @@ -276,7 +277,7 @@ create_frontend_implementation_skill_context({ The skill context compiles the local frontend implementation workflow into structured instructions, approved primitives, approved component families, active design-system policy, visual asset policy, accessibility policy, verification checklist, and disclosure guardrails. It requires a ready frontend context and does not expose raw `SKILL.md` contents. The legacy `design_system_adapter` argument is a compatibility path only; prefer passing the adapter to `create_ui_implementation_contract`. -The JudgmentKit default source includes semantic token roles, system font stacks for body, heading, label, numeric, and diagnostic text, and a committed Lucide icon catalog exposed through `list_icon_catalog`, `search_icon_catalog`, and `get_icon_svg`. Normal implementation context returns only the catalog summary, policy, count, source/version, and tool names; it does not embed the full catalog. These defaults do not load a font CDN, ship font files, use a runtime icon CDN, or mix with an external design system unless the external adapter explicitly names those assets. +JudgmentKit still exposes icon catalog tools for review and examples, and the package default remains the active design-system source when no external source is supplied. Normal implementation context returns only the active source metadata, catalog summary, policy, count, source/version, and tool names; it does not embed a full catalog or imply a fallback from external systems to JudgmentKit assets. When a frontend spec calls for substantive visuals, the implementation path should use `imagegen`, premium Three.js/WebGL rendering, or D3-style data visualization. Deterministic CSS, SVG, and JavaScript remain appropriate for layout, exact text, UI chrome, icons, state indicators, simple diagrams, and accessible fallback structure. diff --git a/docs/releases/v0.6.0.md b/docs/releases/v0.6.0.md index cf1e17b..8841ba7 100644 --- a/docs/releases/v0.6.0.md +++ b/docs/releases/v0.6.0.md @@ -6,7 +6,7 @@ JudgmentKit 0.6.0 makes design-system provenance a contract authority for genera ## Improvements -- Added `implementation_contract.design_system_source` with explicit `judgmentkit_default` and `external_design_system` modes. +- Added `implementation_contract.design_system_source` with `judgmentkit_default` and `external_design_system` modes. - Added complete external design-system adapter support for tokens, fonts, icons, and components. - Added fail-fast validation for incomplete external design-system authority. - Added a hard `design_system_provenance` implementation review gate. diff --git a/docs/releases/v0.6.1.md b/docs/releases/v0.6.1.md index df68939..a36503a 100644 --- a/docs/releases/v0.6.1.md +++ b/docs/releases/v0.6.1.md @@ -7,7 +7,7 @@ JudgmentKit 0.6.1 is the public release for contract-first design-system authori ## Improvements - Carries the 0.6 design-system authority contract into the public MCP metadata and examples. -- Normalizes committed model UI capture metadata to the new `judgmentkit_default` and `external_design_system` source modes. +- Normalizes committed model UI capture metadata to the `judgmentkit_default` package source mode and `external_design_system` source mode. - Keeps public model UI manifests, captures, and generated static routes aligned for release verification. ## Included from 0.6.0 diff --git a/evals/run-mcp-pilot-evals.mjs b/evals/run-mcp-pilot-evals.mjs index 3099f66..85f7f42 100644 --- a/evals/run-mcp-pilot-evals.mjs +++ b/evals/run-mcp-pilot-evals.mjs @@ -1367,7 +1367,9 @@ export async function buildMcpContextForCase(testCase, mcpRuntime) { toolCalls, mcpRuntime, "create_ui_implementation_contract", - testCase.implementation_contract_args ?? {}, + { + ...(testCase.implementation_contract_args ?? {}), + }, ); const repairAttempts = testCase.repair_loop?.attempts ?? null; const attemptReviews = []; diff --git a/examples/model-ui/b2b-renewal-risk/index.html b/examples/model-ui/b2b-renewal-risk/index.html index b1d2121..b45b02b 100644 --- a/examples/model-ui/b2b-renewal-risk/index.html +++ b/examples/model-ui/b2b-renewal-risk/index.html @@ -1080,7 +1080,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "1d8e76fc26786b9dedec7282d019ef0afdcedd2470a9d76302217cb84c9743da", + "source_context_sha256": "5d677fed08c50669639a4a034df58840fab7546694b4be011ccb277dddc77267", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1252,7 +1252,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "7698fd44d47d2c9f90951ccdd6cabbcdc68b69cb7b433d45cf7def83f7f2998b", + "source_context_sha256": "bf28617b5c1856871efe2e9e4bc1f8ef37bbd238aa07abea7c21abbc6893e1e2", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -2458,7 +2458,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "1d8e76fc26786b9dedec7282d019ef0afdcedd2470a9d76302217cb84c9743da", + "source_context_sha256": "5d677fed08c50669639a4a034df58840fab7546694b4be011ccb277dddc77267", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -2630,7 +2630,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "7698fd44d47d2c9f90951ccdd6cabbcdc68b69cb7b433d45cf7def83f7f2998b", + "source_context_sha256": "bf28617b5c1856871efe2e9e4bc1f8ef37bbd238aa07abea7c21abbc6893e1e2", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", diff --git a/examples/model-ui/b2b-renewal-risk/manifest.json b/examples/model-ui/b2b-renewal-risk/manifest.json index 8a58ad5..02e296c 100644 --- a/examples/model-ui/b2b-renewal-risk/manifest.json +++ b/examples/model-ui/b2b-renewal-risk/manifest.json @@ -143,7 +143,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "1d8e76fc26786b9dedec7282d019ef0afdcedd2470a9d76302217cb84c9743da", + "source_context_sha256": "5d677fed08c50669639a4a034df58840fab7546694b4be011ccb277dddc77267", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -315,7 +315,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "7698fd44d47d2c9f90951ccdd6cabbcdc68b69cb7b433d45cf7def83f7f2998b", + "source_context_sha256": "bf28617b5c1856871efe2e9e4bc1f8ef37bbd238aa07abea7c21abbc6893e1e2", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1521,7 +1521,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "1d8e76fc26786b9dedec7282d019ef0afdcedd2470a9d76302217cb84c9743da", + "source_context_sha256": "5d677fed08c50669639a4a034df58840fab7546694b4be011ccb277dddc77267", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1693,7 +1693,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "7698fd44d47d2c9f90951ccdd6cabbcdc68b69cb7b433d45cf7def83f7f2998b", + "source_context_sha256": "bf28617b5c1856871efe2e9e4bc1f8ef37bbd238aa07abea7c21abbc6893e1e2", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", diff --git a/examples/model-ui/b2b-renewal-risk/reviewed-handoff.fixture.json b/examples/model-ui/b2b-renewal-risk/reviewed-handoff.fixture.json index aab882e..6fe44ed 100644 --- a/examples/model-ui/b2b-renewal-risk/reviewed-handoff.fixture.json +++ b/examples/model-ui/b2b-renewal-risk/reviewed-handoff.fixture.json @@ -1325,7 +1325,7 @@ "mode": "judgmentkit_default", "name": "JudgmentKit", "package": "judgmentkit", - "definition_point": "implementation_contract", + "definition_point": "package_default", "required_authorities": [ "tokens", "fonts", @@ -1335,13 +1335,13 @@ "fallback_policy": "fail_incomplete", "provenance_required": true, "source_exports": { - "overview": "/design-system/", - "manifest": "/design-system/manifest.json", - "visual_token_adapter": "/design-system/visual-token-adapter.json", - "component_contracts": "/design-system/component-contracts.json", - "pattern_contracts": "/design-system/pattern-contracts.json", - "accessibility_policy": "/design-system/accessibility-policy.json", - "icon_catalog": "/design-system/icons/", + "overview": "package://judgmentkit/design-system/", + "manifest": "package://judgmentkit/design-system/manifest.json", + "visual_token_adapter": "package://judgmentkit/design-system/visual-token-adapter.json", + "component_contracts": "package://judgmentkit/design-system/component-contracts.json", + "pattern_contracts": "package://judgmentkit/design-system/pattern-contracts.json", + "accessibility_policy": "package://judgmentkit/design-system/accessibility-policy.json", + "icon_catalog": "package://judgmentkit/design-system/icons/", "icon_tools": [ "list_icon_catalog", "search_icon_catalog", @@ -1397,9 +1397,9 @@ ], "component_contract_source": "implementation_contract.default_ai_native_design_system.component_contracts", "provenance_rules": [ - "visual tokens, fonts, icons, and renderer components must come from this active design-system source", + "visual tokens, fonts, icons, and renderer components come from the JudgmentKit package default when no design system is supplied", "local CSS may define layout and UI structure but must not become the source of visual tokens, typography, icon assets, or renderer components", - "external design systems must be supplied as complete contract-time adapters; missing authorities do not fall back to JudgmentKit defaults" + "external design systems must be supplied as complete contract-time adapters or complete design-system sources; missing authorities do not fall back to JudgmentKit defaults" ] }, "visual_token_adapter": { diff --git a/examples/model-ui/clinical-intake-review/index.html b/examples/model-ui/clinical-intake-review/index.html index 99ad02a..2884a3a 100644 --- a/examples/model-ui/clinical-intake-review/index.html +++ b/examples/model-ui/clinical-intake-review/index.html @@ -1080,7 +1080,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "755e176db735b772cf6645a1800f1188f03d1605e2264bea190472968171ecd5", + "source_context_sha256": "09ae87ab18aff0fd79a286a7060c5231b61e2c6e498f73ca90aa45cad6cb4710", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1252,7 +1252,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "68482b586c6b925e719289913c93c1cad1905c9c9a563618fa72e1c34a27a25a", + "source_context_sha256": "46304f2e381e272908c903d076134a3f047e0d2098c93badf8ebabdf567d5bca", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -2458,7 +2458,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "755e176db735b772cf6645a1800f1188f03d1605e2264bea190472968171ecd5", + "source_context_sha256": "09ae87ab18aff0fd79a286a7060c5231b61e2c6e498f73ca90aa45cad6cb4710", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -2630,7 +2630,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "68482b586c6b925e719289913c93c1cad1905c9c9a563618fa72e1c34a27a25a", + "source_context_sha256": "46304f2e381e272908c903d076134a3f047e0d2098c93badf8ebabdf567d5bca", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", diff --git a/examples/model-ui/clinical-intake-review/manifest.json b/examples/model-ui/clinical-intake-review/manifest.json index b646969..d65e997 100644 --- a/examples/model-ui/clinical-intake-review/manifest.json +++ b/examples/model-ui/clinical-intake-review/manifest.json @@ -143,7 +143,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "755e176db735b772cf6645a1800f1188f03d1605e2264bea190472968171ecd5", + "source_context_sha256": "09ae87ab18aff0fd79a286a7060c5231b61e2c6e498f73ca90aa45cad6cb4710", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -315,7 +315,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "68482b586c6b925e719289913c93c1cad1905c9c9a563618fa72e1c34a27a25a", + "source_context_sha256": "46304f2e381e272908c903d076134a3f047e0d2098c93badf8ebabdf567d5bca", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1521,7 +1521,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "755e176db735b772cf6645a1800f1188f03d1605e2264bea190472968171ecd5", + "source_context_sha256": "09ae87ab18aff0fd79a286a7060c5231b61e2c6e498f73ca90aa45cad6cb4710", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1693,7 +1693,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "68482b586c6b925e719289913c93c1cad1905c9c9a563618fa72e1c34a27a25a", + "source_context_sha256": "46304f2e381e272908c903d076134a3f047e0d2098c93badf8ebabdf567d5bca", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", diff --git a/examples/model-ui/clinical-intake-review/reviewed-handoff.fixture.json b/examples/model-ui/clinical-intake-review/reviewed-handoff.fixture.json index e08a093..dcffc78 100644 --- a/examples/model-ui/clinical-intake-review/reviewed-handoff.fixture.json +++ b/examples/model-ui/clinical-intake-review/reviewed-handoff.fixture.json @@ -1317,7 +1317,7 @@ "mode": "judgmentkit_default", "name": "JudgmentKit", "package": "judgmentkit", - "definition_point": "implementation_contract", + "definition_point": "package_default", "required_authorities": [ "tokens", "fonts", @@ -1327,13 +1327,13 @@ "fallback_policy": "fail_incomplete", "provenance_required": true, "source_exports": { - "overview": "/design-system/", - "manifest": "/design-system/manifest.json", - "visual_token_adapter": "/design-system/visual-token-adapter.json", - "component_contracts": "/design-system/component-contracts.json", - "pattern_contracts": "/design-system/pattern-contracts.json", - "accessibility_policy": "/design-system/accessibility-policy.json", - "icon_catalog": "/design-system/icons/", + "overview": "package://judgmentkit/design-system/", + "manifest": "package://judgmentkit/design-system/manifest.json", + "visual_token_adapter": "package://judgmentkit/design-system/visual-token-adapter.json", + "component_contracts": "package://judgmentkit/design-system/component-contracts.json", + "pattern_contracts": "package://judgmentkit/design-system/pattern-contracts.json", + "accessibility_policy": "package://judgmentkit/design-system/accessibility-policy.json", + "icon_catalog": "package://judgmentkit/design-system/icons/", "icon_tools": [ "list_icon_catalog", "search_icon_catalog", @@ -1389,9 +1389,9 @@ ], "component_contract_source": "implementation_contract.default_ai_native_design_system.component_contracts", "provenance_rules": [ - "visual tokens, fonts, icons, and renderer components must come from this active design-system source", + "visual tokens, fonts, icons, and renderer components come from the JudgmentKit package default when no design system is supplied", "local CSS may define layout and UI structure but must not become the source of visual tokens, typography, icon assets, or renderer components", - "external design systems must be supplied as complete contract-time adapters; missing authorities do not fall back to JudgmentKit defaults" + "external design systems must be supplied as complete contract-time adapters or complete design-system sources; missing authorities do not fall back to JudgmentKit defaults" ] }, "visual_token_adapter": { diff --git a/examples/model-ui/field-service-dispatch/index.html b/examples/model-ui/field-service-dispatch/index.html index e0fedab..7b6772f 100644 --- a/examples/model-ui/field-service-dispatch/index.html +++ b/examples/model-ui/field-service-dispatch/index.html @@ -1080,7 +1080,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "16aaf019c9ab3aeaa0fb017352c6a93724079c8c7563899152fdf8433376f48e", + "source_context_sha256": "bbb4f061035f5330caf38d1a2925211e75f66db52c74f666d2af83688b8e5be5", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1252,7 +1252,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "c181c8d039a79989ca4c353226afe83aca264dc15f8842e9f621e289e582a8be", + "source_context_sha256": "7111ce8033a34f36f5daa2498a043f36ac9bee0e2fbb84d5a43f1a5160c47b35", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -2458,7 +2458,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "16aaf019c9ab3aeaa0fb017352c6a93724079c8c7563899152fdf8433376f48e", + "source_context_sha256": "bbb4f061035f5330caf38d1a2925211e75f66db52c74f666d2af83688b8e5be5", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -2630,7 +2630,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "c181c8d039a79989ca4c353226afe83aca264dc15f8842e9f621e289e582a8be", + "source_context_sha256": "7111ce8033a34f36f5daa2498a043f36ac9bee0e2fbb84d5a43f1a5160c47b35", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", diff --git a/examples/model-ui/field-service-dispatch/manifest.json b/examples/model-ui/field-service-dispatch/manifest.json index 3a92cec..a93bf68 100644 --- a/examples/model-ui/field-service-dispatch/manifest.json +++ b/examples/model-ui/field-service-dispatch/manifest.json @@ -143,7 +143,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "16aaf019c9ab3aeaa0fb017352c6a93724079c8c7563899152fdf8433376f48e", + "source_context_sha256": "bbb4f061035f5330caf38d1a2925211e75f66db52c74f666d2af83688b8e5be5", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -315,7 +315,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "c181c8d039a79989ca4c353226afe83aca264dc15f8842e9f621e289e582a8be", + "source_context_sha256": "7111ce8033a34f36f5daa2498a043f36ac9bee0e2fbb84d5a43f1a5160c47b35", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1521,7 +1521,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "16aaf019c9ab3aeaa0fb017352c6a93724079c8c7563899152fdf8433376f48e", + "source_context_sha256": "bbb4f061035f5330caf38d1a2925211e75f66db52c74f666d2af83688b8e5be5", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1693,7 +1693,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "c181c8d039a79989ca4c353226afe83aca264dc15f8842e9f621e289e582a8be", + "source_context_sha256": "7111ce8033a34f36f5daa2498a043f36ac9bee0e2fbb84d5a43f1a5160c47b35", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", diff --git a/examples/model-ui/field-service-dispatch/reviewed-handoff.fixture.json b/examples/model-ui/field-service-dispatch/reviewed-handoff.fixture.json index 8739072..a98cca1 100644 --- a/examples/model-ui/field-service-dispatch/reviewed-handoff.fixture.json +++ b/examples/model-ui/field-service-dispatch/reviewed-handoff.fixture.json @@ -1326,7 +1326,7 @@ "mode": "judgmentkit_default", "name": "JudgmentKit", "package": "judgmentkit", - "definition_point": "implementation_contract", + "definition_point": "package_default", "required_authorities": [ "tokens", "fonts", @@ -1336,13 +1336,13 @@ "fallback_policy": "fail_incomplete", "provenance_required": true, "source_exports": { - "overview": "/design-system/", - "manifest": "/design-system/manifest.json", - "visual_token_adapter": "/design-system/visual-token-adapter.json", - "component_contracts": "/design-system/component-contracts.json", - "pattern_contracts": "/design-system/pattern-contracts.json", - "accessibility_policy": "/design-system/accessibility-policy.json", - "icon_catalog": "/design-system/icons/", + "overview": "package://judgmentkit/design-system/", + "manifest": "package://judgmentkit/design-system/manifest.json", + "visual_token_adapter": "package://judgmentkit/design-system/visual-token-adapter.json", + "component_contracts": "package://judgmentkit/design-system/component-contracts.json", + "pattern_contracts": "package://judgmentkit/design-system/pattern-contracts.json", + "accessibility_policy": "package://judgmentkit/design-system/accessibility-policy.json", + "icon_catalog": "package://judgmentkit/design-system/icons/", "icon_tools": [ "list_icon_catalog", "search_icon_catalog", @@ -1398,9 +1398,9 @@ ], "component_contract_source": "implementation_contract.default_ai_native_design_system.component_contracts", "provenance_rules": [ - "visual tokens, fonts, icons, and renderer components must come from this active design-system source", + "visual tokens, fonts, icons, and renderer components come from the JudgmentKit package default when no design system is supplied", "local CSS may define layout and UI structure but must not become the source of visual tokens, typography, icon assets, or renderer components", - "external design systems must be supplied as complete contract-time adapters; missing authorities do not fall back to JudgmentKit defaults" + "external design systems must be supplied as complete contract-time adapters or complete design-system sources; missing authorities do not fall back to JudgmentKit defaults" ] }, "visual_token_adapter": { diff --git a/examples/model-ui/refund-system-map/index.html b/examples/model-ui/refund-system-map/index.html index b0dcd64..16df4d3 100644 --- a/examples/model-ui/refund-system-map/index.html +++ b/examples/model-ui/refund-system-map/index.html @@ -1080,7 +1080,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "b585e9f4a5a35d762afe88430bd74653b97db726728e32e774f948a49e310219", + "source_context_sha256": "dce6548f1d7cfd0f785bcdf99d0b33a7a60aa80dfe19fd9d66e2f265c4cb23a6", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1252,7 +1252,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "3a498eace6fc78753c22b9544905011c9e1d6491b0cf5dfd1a19e157b3a06813", + "source_context_sha256": "c1d522ae401be0f83c9c91a51a0dc418f41e83ae631049e9681dc2c83c4a79bc", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -2499,7 +2499,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "b585e9f4a5a35d762afe88430bd74653b97db726728e32e774f948a49e310219", + "source_context_sha256": "dce6548f1d7cfd0f785bcdf99d0b33a7a60aa80dfe19fd9d66e2f265c4cb23a6", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -2671,7 +2671,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "3a498eace6fc78753c22b9544905011c9e1d6491b0cf5dfd1a19e157b3a06813", + "source_context_sha256": "c1d522ae401be0f83c9c91a51a0dc418f41e83ae631049e9681dc2c83c4a79bc", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", diff --git a/examples/model-ui/refund-system-map/manifest.json b/examples/model-ui/refund-system-map/manifest.json index 49716e0..bba3223 100644 --- a/examples/model-ui/refund-system-map/manifest.json +++ b/examples/model-ui/refund-system-map/manifest.json @@ -143,7 +143,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "b585e9f4a5a35d762afe88430bd74653b97db726728e32e774f948a49e310219", + "source_context_sha256": "dce6548f1d7cfd0f785bcdf99d0b33a7a60aa80dfe19fd9d66e2f265c4cb23a6", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -315,7 +315,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "3a498eace6fc78753c22b9544905011c9e1d6491b0cf5dfd1a19e157b3a06813", + "source_context_sha256": "c1d522ae401be0f83c9c91a51a0dc418f41e83ae631049e9681dc2c83c4a79bc", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1562,7 +1562,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "b585e9f4a5a35d762afe88430bd74653b97db726728e32e774f948a49e310219", + "source_context_sha256": "dce6548f1d7cfd0f785bcdf99d0b33a7a60aa80dfe19fd9d66e2f265c4cb23a6", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", @@ -1734,7 +1734,7 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "3a498eace6fc78753c22b9544905011c9e1d6491b0cf5dfd1a19e157b3a06813", + "source_context_sha256": "c1d522ae401be0f83c9c91a51a0dc418f41e83ae631049e9681dc2c83c4a79bc", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", "frontend_skill_context_status": "ready", diff --git a/examples/model-ui/refund-system-map/reviewed-handoff.fixture.json b/examples/model-ui/refund-system-map/reviewed-handoff.fixture.json index 05b2807..0818bf5 100644 --- a/examples/model-ui/refund-system-map/reviewed-handoff.fixture.json +++ b/examples/model-ui/refund-system-map/reviewed-handoff.fixture.json @@ -1340,7 +1340,7 @@ "mode": "judgmentkit_default", "name": "JudgmentKit", "package": "judgmentkit", - "definition_point": "implementation_contract", + "definition_point": "package_default", "required_authorities": [ "tokens", "fonts", @@ -1350,13 +1350,13 @@ "fallback_policy": "fail_incomplete", "provenance_required": true, "source_exports": { - "overview": "/design-system/", - "manifest": "/design-system/manifest.json", - "visual_token_adapter": "/design-system/visual-token-adapter.json", - "component_contracts": "/design-system/component-contracts.json", - "pattern_contracts": "/design-system/pattern-contracts.json", - "accessibility_policy": "/design-system/accessibility-policy.json", - "icon_catalog": "/design-system/icons/", + "overview": "package://judgmentkit/design-system/", + "manifest": "package://judgmentkit/design-system/manifest.json", + "visual_token_adapter": "package://judgmentkit/design-system/visual-token-adapter.json", + "component_contracts": "package://judgmentkit/design-system/component-contracts.json", + "pattern_contracts": "package://judgmentkit/design-system/pattern-contracts.json", + "accessibility_policy": "package://judgmentkit/design-system/accessibility-policy.json", + "icon_catalog": "package://judgmentkit/design-system/icons/", "icon_tools": [ "list_icon_catalog", "search_icon_catalog", @@ -1412,9 +1412,9 @@ ], "component_contract_source": "implementation_contract.default_ai_native_design_system.component_contracts", "provenance_rules": [ - "visual tokens, fonts, icons, and renderer components must come from this active design-system source", + "visual tokens, fonts, icons, and renderer components come from the JudgmentKit package default when no design system is supplied", "local CSS may define layout and UI structure but must not become the source of visual tokens, typography, icon assets, or renderer components", - "external design systems must be supplied as complete contract-time adapters; missing authorities do not fall back to JudgmentKit defaults" + "external design systems must be supplied as complete contract-time adapters or complete design-system sources; missing authorities do not fall back to JudgmentKit defaults" ] }, "visual_token_adapter": { diff --git a/scripts/demo-model-ui-matrix.mjs b/scripts/demo-model-ui-matrix.mjs index 7d7fc84..470a2a5 100644 --- a/scripts/demo-model-ui-matrix.mjs +++ b/scripts/demo-model-ui-matrix.mjs @@ -768,13 +768,16 @@ function captureMatchesFrontendSkillSummary(capture, contextPayload) { function normalizeSummary(summary) { if (!summary) return null; const designSystemMode = - /^no_design_system_.*provided$/.test(summary.design_system_mode ?? "") + summary.design_system_mode === "judgmentkit_default" + ? "judgmentkit_default" + : /^no_design_system_.*provided$/.test(summary.design_system_mode ?? "") ? "judgmentkit_default" : /^adapter_after_/.test(summary.design_system_mode ?? "") ? "external_design_system" : summary.design_system_mode; const designSystemName = - designSystemMode === "judgmentkit_default" && !summary.design_system_name + designSystemMode === "judgmentkit_default" && + (!summary.design_system_name || summary.design_system_name === "JudgmentKit") ? "JudgmentKit" : summary.design_system_name; diff --git a/scripts/site-local-server.mjs b/scripts/site-local-server.mjs index 7f5db4e..6af70ec 100644 --- a/scripts/site-local-server.mjs +++ b/scripts/site-local-server.mjs @@ -12,6 +12,41 @@ const ROOT = path.resolve(__dirname, ".."); const DEFAULT_SITE_DIR = path.join(ROOT, "site", "dist"); const DEFAULT_HOST = "127.0.0.1"; const DEFAULT_PORT = 4173; +const CANONICAL_SURFACES_DESIGN_SYSTEM_URL = + "https://surfaces.systems/design-system"; +const DESIGN_SYSTEM_MIGRATION_CODE = "judgmentkit_design_system_retired"; +const RETIRED_DESIGN_SYSTEM_REDIRECT_PATHS = new Set([ + "/design-system", + "/design-system/", + "/design-system/index.html", + "/design-system/index.html.md", + "/design-system/llms.txt", + "/design-system/llms-full.txt", + "/design-system/tokens", + "/design-system/tokens/", + "/design-system/tokens/index.html", + "/design-system/tokens/index.html.md", + "/design-system/fonts", + "/design-system/fonts/", + "/design-system/fonts/index.html", + "/design-system/fonts/index.html.md", + "/design-system/icons", + "/design-system/icons/", + "/design-system/icons/index.html", + "/design-system/icons/index.html.md", + "/design-system/components", + "/design-system/components/", + "/design-system/components/index.html", + "/design-system/components/index.html.md", + "/design-system/patterns", + "/design-system/patterns/", + "/design-system/patterns/index.html", + "/design-system/patterns/index.html.md", + "/design-system/accessibility", + "/design-system/accessibility/", + "/design-system/accessibility/index.html", + "/design-system/accessibility/index.html.md", +]); const CONTENT_TYPES = new Map([ [".css", "text/css; charset=utf-8"], @@ -98,6 +133,60 @@ function isLocalAnalyticsScriptPath(pathname) { return pathname === "/_vercel/insights/script.js"; } +function isRetiredDesignSystemPath(pathname) { + return RETIRED_DESIGN_SYSTEM_REDIRECT_PATHS.has(pathname); +} + +function isRetiredDesignSystemJsonPath(pathname) { + return ( + pathname.startsWith("/design-system/") && + pathname.endsWith(".json") && + !pathname.includes("//") + ); +} + +function designSystemRetiredPayload(pathname) { + return { + code: DESIGN_SYSTEM_MIGRATION_CODE, + message: + "judgmentkit.ai/design-system is retired. Use the canonical Surfaces design-system contract.", + canonicalUrl: CANONICAL_SURFACES_DESIGN_SYSTEM_URL, + requestedPath: pathname, + }; +} + +function sendDesignSystemRetiredJson(req, res, pathname) { + if (req.method !== "GET" && req.method !== "HEAD") { + sendMethodNotAllowed(res, ["GET", "HEAD"]); + return; + } + + const body = `${JSON.stringify(designSystemRetiredPayload(pathname), null, 2)}\n`; + res.statusCode = 410; + res.setHeader("Content-Type", "application/json; charset=utf-8"); + res.setHeader("Cache-Control", "public, max-age=300"); + res.setHeader("Content-Length", Buffer.byteLength(body)); + + if (req.method === "HEAD") { + res.end(); + return; + } + + res.end(body); +} + +function sendDesignSystemRedirect(req, res) { + if (req.method !== "GET" && req.method !== "HEAD") { + sendMethodNotAllowed(res, ["GET", "HEAD"]); + return; + } + + res.statusCode = 308; + res.setHeader("Location", CANONICAL_SURFACES_DESIGN_SYSTEM_URL); + res.setHeader("Cache-Control", "public, max-age=300"); + res.end(); +} + function serveLocalAnalyticsScript(req, res) { if (req.method !== "GET" && req.method !== "HEAD") { sendMethodNotAllowed(res, ["GET", "HEAD"]); @@ -285,6 +374,16 @@ export function createSiteLocalServer(options = {}) { return; } + if (isRetiredDesignSystemJsonPath(requestUrl.pathname)) { + sendDesignSystemRetiredJson(req, res, requestUrl.pathname); + return; + } + + if (isRetiredDesignSystemPath(requestUrl.pathname)) { + sendDesignSystemRedirect(req, res); + return; + } + serveStaticFile(req, res, siteDir, requestUrl.pathname).catch((error) => { if (res.headersSent) { return; diff --git a/site/build-site.mjs b/site/build-site.mjs index e7976f5..df525ea 100755 --- a/site/build-site.mjs +++ b/site/build-site.mjs @@ -199,7 +199,6 @@ const platformSites = [ const primaryNavLinks = [ { label: "Value", href: "/value/" }, { label: "Docs", href: "/docs/" }, - { label: "Design System", href: "/design-system/" }, { label: "Examples", href: "/examples/" }, { label: "Evals", href: "/evals/" }, { label: "MCP", href: "/mcp" }, @@ -211,15 +210,7 @@ function isPrimaryNavCurrent(link, pathName) { return pathName === link.href || pathName.startsWith(link.href); } -const DESIGN_SYSTEM_ROUTES = [ - "/design-system/", - "/design-system/tokens/", - "/design-system/fonts/", - "/design-system/icons/", - "/design-system/components/", - "/design-system/patterns/", - "/design-system/accessibility/", -]; +const DESIGN_SYSTEM_ROUTES = []; const ICON_PAGE_SCENARIOS = [ { @@ -4054,9 +4045,9 @@ function homepage() { Open docs
-

Review the design-system assets

-

Inspect token roles, typography, icons, component contracts, patterns, and accessibility policy.

- Open design system +

Review the active design source

+

Use JudgmentKit's package default when no external system is supplied, or bring a complete external contract such as Surfaces.

+ Open Surfaces contract

Start installation

@@ -4143,16 +4134,18 @@ function renderValueEvidenceLinks(links) { } function defaultVisualTokenAdapter() { - return createUiImplementationContract().implementation_contract.visual_token_adapter; + return createUiImplementationContract({ + }).implementation_contract.visual_token_adapter; } function defaultDesignSystemContract() { - return createUiImplementationContract().implementation_contract - .default_ai_native_design_system; + return createUiImplementationContract({ + }).implementation_contract.default_ai_native_design_system; } function defaultAccessibilityPolicy() { - return createUiImplementationContract().implementation_contract.accessibility_policy; + return createUiImplementationContract({ + }).implementation_contract.accessibility_policy; } function stripIconScenarioForExport(scenario) { @@ -7040,9 +7033,8 @@ async function examplesPage() {

Lucide icon smoke proof

-

Search, retrieve, and render every committed Lucide icon through the MCP catalog tools. The design-system icon page is the reference surface; this HTML remains the deterministic regression proof.

+

Search, retrieve, and render every committed Lucide icon through the MCP catalog tools. This HTML remains the deterministic regression proof.

@@ -7585,7 +7577,7 @@ function siteRebuildLogPage(designSystemModel) {

What changed

-

The rebuild changed the public site from a system-map-heavy homepage into an evidence-first product surface. The homepage now explains the failure JudgmentKit prevents, shows the repair path, and routes visitors into value examples, replayable examples, eval evidence, docs, install, and design-system review.

+

The rebuild changed the public site from a system-map-heavy homepage into an evidence-first product surface. The homepage now explains the failure JudgmentKit prevents, shows the repair path, and routes visitors into value examples, replayable examples, eval evidence, docs, and install.

New homepage structure

@@ -7610,16 +7602,16 @@ function siteRebuildLogPage(designSystemModel) {
  • Activity model reviewThe brief was reviewed as a public product-site rebuild for AI-agent users and evaluators.
  • Candidate repairAn early activity-model candidate exposed raw implementation vocabulary. It was revised before it was trusted.
  • Surface selectionThe homepage was treated as a marketing surface with proof and adoption paths, not a setup/debug tool.
  • -
  • Workflow reviewThe accepted workflow made value, proof, docs, design-system review, examples, evals, install, and MCP setup separate surfaces.
  • +
  • Workflow reviewThe accepted workflow made value, proof, docs, examples, evals, install, and MCP setup separate surfaces.
  • Implementation contractThe generator stayed static and deterministic, with source-controlled routes, semantic HTML, responsive behavior, and explicit tests.
  • Implementation reviewThe final implementation evidence passed after the review evidence was cleaned up and resubmitted.
  • -

    Design-system evidence

    -

    The strongest evidence is in the build and test contract: the same static site generator builds the product pages and the JudgmentKit design-system pages, then exports the manifest, token adapter, component contracts, pattern contracts, specimens, provenance, accessibility policy, and icon scenarios.

    -
    +

    Design-source evidence

    +

    JudgmentKit keeps a package-default design-system contract for no-config use. Complete external sources such as Surfaces can replace that authority, while public JudgmentKit design-system routes are no longer the source of truth.

    +
    ${renderMetricCard("Design-system source", designSystemSource.design_system_contract_id)} ${renderMetricCard("Token roles", tokenRoleCount)} ${renderMetricCard("Component contracts", componentContractCount)} @@ -7628,14 +7620,11 @@ function siteRebuildLogPage(designSystemModel) { ${renderMetricCard("Renderer", DESIGN_SYSTEM_SPECIMEN_RENDERER.id)}
    -

    This page should not be read as a claim that every visual rule on the homepage is mechanically generated from exported token JSON. The defensible claim is narrower: the rebuild is in the same source-controlled static generator, routes users into the JudgmentKit design-system surface, emits the design-system assets in the same build, and has tests that verify those assets, contracts, specimens, and provenance.

    +

    This page should not be read as a claim that every visual rule on the homepage is mechanically generated from exported token JSON. The defensible claim is narrower: the rebuild is in the same source-controlled static generator, and JudgmentKit records the active design-system source in implementation contracts.

    Source and tests

    @@ -7662,7 +7651,7 @@ JudgmentKit review_ui_implementation_candidate: passed

    Design-system checks

    -

    Tests assert the manifest, token adapter, component contracts, pattern contracts, specimens, provenance hashes, accessibility policy, and Lucide icon catalog.

    +

    Tests assert the package-default source metadata, complete external-source validation, retired public routes, and Lucide icon catalog behavior.

    Browser checks

    @@ -7672,7 +7661,7 @@ JudgmentKit review_ui_implementation_candidate: passed

    Review notes

    -

    If you are reviewing whether this is a real rebuild, start with the source diff and tests. If you are reviewing whether it uses the JudgmentKit design system, start with the design-system route, JSON exports, specimen provenance, and the tests that hash those outputs.

    +

    If you are reviewing whether this is a real rebuild, start with the source diff and tests. If you are reviewing design-system authority, start with the package-default source metadata, any supplied external contract, and the tests that preserve those boundaries.

    The remaining judgment call is product-level: whether the public story should expose more of this evidence earlier, or keep the homepage focused on the offer and leave this page in evals.

    @@ -7891,13 +7880,6 @@ export async function buildSite(outDir = DEFAULT_OUT_DIR) { await fs.rm(outDir, { recursive: true, force: true }); await fs.mkdir(path.join(outDir, "assets"), { recursive: true }); await fs.mkdir(path.join(outDir, "docs"), { recursive: true }); - await fs.mkdir(path.join(outDir, "design-system"), { recursive: true }); - await fs.mkdir(path.join(outDir, "design-system", "tokens"), { recursive: true }); - await fs.mkdir(path.join(outDir, "design-system", "fonts"), { recursive: true }); - await fs.mkdir(path.join(outDir, "design-system", "icons"), { recursive: true }); - await fs.mkdir(path.join(outDir, "design-system", "components"), { recursive: true }); - await fs.mkdir(path.join(outDir, "design-system", "patterns"), { recursive: true }); - await fs.mkdir(path.join(outDir, "design-system", "accessibility"), { recursive: true }); await fs.mkdir(path.join(outDir, "evals"), { recursive: true }); await fs.mkdir(path.join(outDir, "evals", "judgmentkit-mcp"), { recursive: true }); await fs.mkdir(path.join(outDir, "evals", "site-rebuild-log"), { recursive: true }); @@ -7923,61 +7905,6 @@ export async function buildSite(outDir = DEFAULT_OUT_DIR) { await fs.writeFile(path.join(outDir, "robots.txt"), "User-agent: *\nAllow: /\n"); await fs.writeFile(path.join(outDir, "value", "index.html"), await valuePage()); await fs.writeFile(path.join(outDir, "docs", "index.html"), docsPage()); - await fs.writeFile(path.join(outDir, "design-system", "index.html"), renderDesignSystemOverviewPage(designSystemModel)); - await fs.writeFile(path.join(outDir, "design-system", "tokens", "index.html"), renderDesignSystemTokensPage(designSystemModel)); - await fs.writeFile(path.join(outDir, "design-system", "fonts", "index.html"), renderDesignSystemFontsPage(designSystemModel)); - await fs.writeFile(path.join(outDir, "design-system", "icons", "index.html"), renderDesignSystemIconsPage(designSystemModel)); - await fs.writeFile(path.join(outDir, "design-system", "components", "index.html"), renderDesignSystemComponentsPage(designSystemModel)); - await fs.writeFile(path.join(outDir, "design-system", "patterns", "index.html"), renderDesignSystemPatternsPage(designSystemModel)); - await fs.writeFile(path.join(outDir, "design-system", "accessibility", "index.html"), renderDesignSystemAccessibilityPage(designSystemModel)); - await fs.writeFile( - path.join(outDir, "design-system", "manifest.json"), - jsonExport(designSystemModel.exports.manifest), - ); - await fs.writeFile( - path.join(outDir, "design-system", "visual-token-adapter.json"), - jsonExport(designSystemModel.exports.visualTokenAdapter), - ); - await fs.writeFile( - path.join(outDir, "design-system", "component-contracts.json"), - jsonExport(designSystemModel.exports.componentContracts), - ); - await fs.writeFile( - path.join(outDir, "design-system", "pattern-contracts.json"), - jsonExport(designSystemModel.exports.patternContracts), - ); - await fs.writeFile( - path.join(outDir, "design-system", "component-specimens.json"), - jsonExport(designSystemModel.exports.componentSpecimens), - ); - await fs.writeFile( - path.join(outDir, "design-system", "pattern-specimens.json"), - jsonExport(designSystemModel.exports.patternSpecimens), - ); - await fs.writeFile( - path.join(outDir, "design-system", "specimen-provenance.json"), - jsonExport(designSystemModel.exports.specimenProvenance), - ); - await fs.writeFile( - path.join(outDir, "design-system", "accessibility-policy.json"), - jsonExport(designSystemModel.exports.accessibilityPolicy), - ); - await fs.writeFile( - path.join(outDir, "design-system", "icon-scenarios.json"), - jsonExport(designSystemModel.exports.iconScenarios), - ); - await fs.writeFile(path.join(outDir, "design-system", "llms.txt"), renderDesignSystemLlms(designSystemModel)); - await fs.writeFile( - path.join(outDir, "design-system", "llms-full.txt"), - renderDesignSystemLlmsFull(designSystemModel), - ); - for (const pageEntry of designSystemModel.pages) { - const markdownPath = pageEntry.markdown_path.replace(/^\/design-system\/?/, ""); - await fs.writeFile( - path.join(outDir, "design-system", markdownPath), - renderDesignSystemPageMarkdown(designSystemModel, pageEntry), - ); - } await fs.writeFile(path.join(outDir, "examples", "index.html"), await examplesPage()); await fs.writeFile(path.join(outDir, "install"), await bootstrapScript(), { mode: 0o755 }); await fs.writeFile( @@ -7989,8 +7916,6 @@ export async function buildSite(outDir = DEFAULT_OUT_DIR) { "", "- /value/", "- /docs/", - "- /design-system/", - "- /design-system/llms.txt", "- /examples/", "- /evals/", "- /evals/judgmentkit-mcp/", diff --git a/src/index.mjs b/src/index.mjs index f91e8c9..9566665 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -5370,23 +5370,30 @@ const DESIGN_SYSTEM_REQUIRED_AUTHORITIES = [ "components", ]; +const CANONICAL_SURFACES_DESIGN_SYSTEM_URL = + "https://surfaces.systems/design-system"; + const DEFAULT_DESIGN_SYSTEM_SOURCE = { id: "judgmentkit.design-system.source-v1", mode: "judgmentkit_default", name: "JudgmentKit", package: "judgmentkit", - definition_point: "implementation_contract", + definition_point: "package_default", required_authorities: DESIGN_SYSTEM_REQUIRED_AUTHORITIES, fallback_policy: "fail_incomplete", provenance_required: true, source_exports: { - overview: "/design-system/", - manifest: "/design-system/manifest.json", - visual_token_adapter: "/design-system/visual-token-adapter.json", - component_contracts: "/design-system/component-contracts.json", - pattern_contracts: "/design-system/pattern-contracts.json", - accessibility_policy: "/design-system/accessibility-policy.json", - icon_catalog: "/design-system/icons/", + overview: "package://judgmentkit/design-system/", + manifest: "package://judgmentkit/design-system/manifest.json", + visual_token_adapter: + "package://judgmentkit/design-system/visual-token-adapter.json", + component_contracts: + "package://judgmentkit/design-system/component-contracts.json", + pattern_contracts: + "package://judgmentkit/design-system/pattern-contracts.json", + accessibility_policy: + "package://judgmentkit/design-system/accessibility-policy.json", + icon_catalog: "package://judgmentkit/design-system/icons/", icon_tools: ICON_CATALOG_TOOL_NAMES, }, token_prefixes: ["--jk-"], @@ -5394,12 +5401,21 @@ const DEFAULT_DESIGN_SYSTEM_SOURCE = { component_contract_source: "implementation_contract.default_ai_native_design_system.component_contracts", provenance_rules: [ - "visual tokens, fonts, icons, and renderer components must come from this active design-system source", + "visual tokens, fonts, icons, and renderer components come from the JudgmentKit package default when no design system is supplied", "local CSS may define layout and UI structure but must not become the source of visual tokens, typography, icon assets, or renderer components", - "external design systems must be supplied as complete contract-time adapters; missing authorities do not fall back to JudgmentKit defaults", + "external design systems must be supplied as complete contract-time adapters or complete design-system sources; missing authorities do not fall back to JudgmentKit defaults", ], }; +function designSystemSourceValidationDetails(missing = []) { + return { + code: "invalid_design_system_source", + canonical_surfaces_url: CANONICAL_SURFACES_DESIGN_SYSTEM_URL, + missing, + valid_modes: ["judgmentkit_default", "external_design_system"], + }; +} + const DEFAULT_ITERATION_POLICY = { owner: "agent", default_max_attempts: 3, @@ -6019,6 +6035,190 @@ function designSystemAdapterFromInput(source) { : null; } +function designSystemSourceFromInput(source) { + return isPlainObject(source) + ? source.design_system_source ?? source.designSystemSource + : null; +} + +function hasDesignSystemSourceInput(source) { + return ( + isPlainObject(source) && + ("design_system_source" in source || "designSystemSource" in source) + ); +} + +function usesJudgmentKitDefaultDesignSystem(source) { + if (!isPlainObject(source)) { + return false; + } + + const designSystemSource = designSystemSourceFromInput(source); + + return ( + source.fixture_design_system === true || + source.fixtureDesignSystem === true || + designSystemSource?.mode === "judgmentkit_default" + ); +} + +function validateExplicitDesignSystemSource(sourceValue) { + if (sourceValue === undefined || sourceValue === null) { + return; + } + + if (!isPlainObject(sourceValue)) { + throw new JudgmentKitInputError( + "design_system_source must be an object when provided.", + { + code: "invalid_design_system_source", + details: designSystemSourceValidationDetails(["object"]), + }, + ); + } + + const missing = []; + for (const field of ["id", "mode", "name", "package", "definition_point"]) { + if (!optionalString(sourceValue[field]).length) { + missing.push(field); + } + } + + const mode = optionalString(sourceValue.mode); + if ( + mode.length > 0 && + !["judgmentkit_default", "external_design_system"].includes(mode) + ) { + missing.push("mode:judgmentkit_default|external_design_system"); + } + + if ( + normalizePrimitiveList( + sourceValue.required_authorities ?? sourceValue.requiredAuthorities, + ).length < DESIGN_SYSTEM_REQUIRED_AUTHORITIES.length + ) { + missing.push("required_authorities"); + } + + if ( + optionalString(sourceValue.fallback_policy ?? sourceValue.fallbackPolicy) !== + "fail_incomplete" + ) { + missing.push("fallback_policy"); + } + + if ( + typeof (sourceValue.provenance_required ?? + sourceValue.provenanceRequired) !== "boolean" + ) { + missing.push("provenance_required"); + } + + if ( + !isPlainObject(sourceValue.source_exports ?? sourceValue.sourceExports) || + Object.keys(sourceValue.source_exports ?? sourceValue.sourceExports).length === 0 + ) { + missing.push("source_exports"); + } + + if ( + normalizePrimitiveList(sourceValue.token_prefixes ?? sourceValue.tokenPrefixes) + .length === 0 + ) { + missing.push("token_prefixes"); + } + + const iconCatalog = sourceValue.icon_catalog ?? sourceValue.iconCatalog; + if (!isPlainObject(iconCatalog)) { + missing.push("icon_catalog"); + } else { + for (const field of [ + "source", + "library", + "package", + "version", + "license", + "notice", + "style_system", + ]) { + if (!optionalString(iconCatalog[field]).length) { + missing.push(`icon_catalog.${field}`); + } + } + + if (numberOrFallback(iconCatalog.icon_count ?? iconCatalog.iconCount, 0) < 1) { + missing.push("icon_catalog.icon_count"); + } + + if ( + !isPlainObject(iconCatalog.style_attributes ?? iconCatalog.styleAttributes) || + Object.keys(iconCatalog.style_attributes ?? iconCatalog.styleAttributes).length === 0 + ) { + missing.push("icon_catalog.style_attributes"); + } + + if ( + normalizePrimitiveList( + iconCatalog.mcp_tools ?? iconCatalog.mcpTools ?? iconCatalog.tools, + ).length === 0 + ) { + missing.push("icon_catalog.mcp_tools"); + } + + if ( + typeof (iconCatalog.default_include_svg ?? + iconCatalog.defaultIncludeSvg) !== "boolean" + ) { + missing.push("icon_catalog.default_include_svg"); + } + } + + if ( + normalizePrimitiveList( + sourceValue.renderer_components ?? sourceValue.rendererComponents, + ).length === 0 + ) { + missing.push("renderer_components"); + } + + if ( + !optionalString( + sourceValue.component_contract_source ?? + sourceValue.componentContractSource, + ).length + ) { + missing.push("component_contract_source"); + } + + if ( + normalizePrimitiveList( + sourceValue.provenance_rules ?? sourceValue.provenanceRules, + ).length === 0 + ) { + missing.push("provenance_rules"); + } + + if (missing.length > 0) { + throw new JudgmentKitInputError( + "design_system_source must be complete when provided. Omit it to use the JudgmentKit package default.", + { + code: "invalid_design_system_source", + details: designSystemSourceValidationDetails(missing), + }, + ); + } +} + +function assertValidDesignSystemInputs(source) { + if (!isPlainObject(source)) { + return; + } + + if (hasDesignSystemSourceInput(source)) { + validateExplicitDesignSystemSource(designSystemSourceFromInput(source)); + } +} + function externalAdapterName(adapter) { return optionalDesignSystemName( adapter.design_system_name, @@ -6260,11 +6460,11 @@ function externalVisualTokenAdapterFallback(adapter, iconSource) { DEFAULT_ICON_SELECTION_POLICY.accessibility_guidance, failure_signals: [ "icons bypass the active external design-system source", - "icons are mixed with JudgmentKit defaults without explicit external authority", + "icons are mixed with JudgmentKit default assets without explicit external authority", ], }, icon_rules: [ - "default JudgmentKit icon assets are not used while an external design system is active", + "JudgmentKit default icon assets are not used while an external design system is active", "meaningful icons still require adjacent text or an accessible name", ], adapter_rules: [ @@ -6486,10 +6686,14 @@ function resolveImplementationDesignSystem(source, base) { source.visual_token_adapter ?? source.visualTokenAdapter, base.visual_token_adapter, ); + const explicitDesignSystemSource = designSystemSourceFromInput(source); + const designSystemSourceValue = usesJudgmentKitDefaultDesignSystem(source) + ? isPlainObject(explicitDesignSystemSource) + ? explicitDesignSystemSource + : DEFAULT_DESIGN_SYSTEM_SOURCE + : explicitDesignSystemSource; const designSystemSource = normalizeDesignSystemSource( - source.design_system_source ?? - source.designSystemSource ?? - base.design_system_source, + designSystemSourceValue, { visualTokenAdapter, componentContracts: sourceDefaultDesignSystem.component_contracts, @@ -6725,6 +6929,17 @@ function implementationContractSource(input = {}) { return "external_design_system"; } + if (isPlainObject(input) && usesJudgmentKitDefaultDesignSystem(input)) { + return "judgmentkit_default"; + } + + if (isPlainObject(input) && isPlainObject(designSystemSourceFromInput(input))) { + return ( + optionalString(designSystemSourceFromInput(input).mode) || + "explicit_design_system_source" + ); + } + if (isPlainObject(input) && toStringArray(input.repo_evidence).length > 0) { return "repo_evidence"; } @@ -6747,6 +6962,7 @@ export function createUiImplementationContract(input = {}, options = {}) { ); } + assertValidDesignSystemInputs(input ?? {}); const contract = options.contract ?? loadActivityContract(options.contractPath); const normalized = normalizeUiImplementationContract(input ?? {}, { contract }); const packet = { @@ -9790,10 +10006,13 @@ export function createUiGenerationHandoff(workflowReview, options = {}) { const activityCandidate = workflowReview.activity_review.candidate; const workflowCandidate = workflowReview.candidate; const contract = options.contract ?? loadActivityContract(options.contractPath); - const implementationContract = normalizeUiImplementationContract( + const implementationContractInput = options.implementation_contract ?? - options.ui_implementation_contract ?? - contract.implementation_contract, + options.ui_implementation_contract ?? + contract.implementation_contract; + assertValidDesignSystemInputs(implementationContractInput); + const implementationContract = normalizeUiImplementationContract( + implementationContractInput, { contract }, ); const workflowSurfaceSet = toSurfaceSetArray(workflowCandidate.surface_set); @@ -10014,7 +10233,11 @@ function guidanceSourceName(hasSource, designSystemMode) { return "external_design_system"; } - return "judgmentkit_design_system"; + if (designSystemMode === "judgmentkit_default") { + return "judgmentkit_design_system"; + } + + return "explicit_design_system_source"; } function normalizeAdapterTokenGuidance( @@ -10442,8 +10665,18 @@ export function createFrontendGenerationContext({ const normalizedVerification = normalizeVerificationContext(verification); const requiredSurfaces = toSurfaceSetArray(uiGenerationHandoff.surface_set); const requiredSurfaceAggregate = aggregateSurfaceSet(requiredSurfaces); + const sourceImplementationContract = isPlainObject( + uiGenerationHandoff.implementation_contract, + ) + ? uiGenerationHandoff.implementation_contract + : {}; + assertValidDesignSystemInputs(sourceImplementationContract); + const implementationContract = normalizeUiImplementationContract( + sourceImplementationContract, + { contract: resolvedContract }, + ); const designSystemContract = normalizeDefaultAiNativeDesignSystem( - uiGenerationHandoff.implementation_contract?.default_ai_native_design_system, + implementationContract.default_ai_native_design_system, DEFAULT_AI_NATIVE_DESIGN_SYSTEM, ); @@ -10468,7 +10701,7 @@ export function createFrontendGenerationContext({ surface_set: requiredSurfaces, product_terms: toStringArray(uiGenerationHandoff.product_terms), handoff: uiGenerationHandoff.handoff, - implementation_contract: uiGenerationHandoff.implementation_contract, + implementation_contract: implementationContract, disclosure_reminders: uiGenerationHandoff.disclosure_reminders, frontend_context: { target_runtime: optionalString(normalizedFrontendContext.target_runtime), @@ -10492,15 +10725,13 @@ export function createFrontendGenerationContext({ interaction_implications: surfaceGuidance.interaction_implications, disclosure_implications: surfaceGuidance.disclosure_implications, frontend_posture: surfaceGuidance.frontend_posture, - implementation_contract: uiGenerationHandoff.implementation_contract, - design_system_source: - uiGenerationHandoff.implementation_contract?.design_system_source ?? - DEFAULT_DESIGN_SYSTEM_SOURCE, + implementation_contract: implementationContract, + design_system_source: implementationContract.design_system_source, visual_asset_policy: - uiGenerationHandoff.implementation_contract?.visual_asset_policy ?? + implementationContract.visual_asset_policy ?? DEFAULT_VISUAL_ASSET_POLICY, accessibility_policy: - uiGenerationHandoff.implementation_contract?.accessibility_policy ?? + implementationContract.accessibility_policy ?? DEFAULT_ACCESSIBILITY_POLICY, component_contracts: designSystemContract.component_contracts, pattern_contracts: designSystemContract.pattern_contracts, @@ -10521,11 +10752,8 @@ export function createFrontendGenerationContext({ uiGenerationHandoff.disclosure_reminders?.terms_to_keep_out_of_product_ui ?? [], diagnostic_contexts: uiGenerationHandoff.disclosure_reminders?.diagnostic_contexts ?? [], - approved_primitives: - uiGenerationHandoff.implementation_contract?.approved_primitives ?? [], - design_system_source: - uiGenerationHandoff.implementation_contract?.design_system_source ?? - DEFAULT_DESIGN_SYSTEM_SOURCE, + approved_primitives: implementationContract.approved_primitives ?? [], + design_system_source: implementationContract.design_system_source, }, }; } @@ -10574,7 +10802,7 @@ function buildFrontendImplementationInstructionMarkdown({ "- Use numbered wizard or stepper UI only when workflow.stepper_eligibility.allowed is true.", "- Use approved primitives and approved component families before introducing new UI helpers.", "- Use implementation_contract.design_system_source as the active source for visual tokens, typography, icon assets, and renderer components.", - "- Use JudgmentKit design-system exports by default; when external_design_system is active, do not mix in JudgmentKit default assets unless the external adapter explicitly names them.", + "- Do not mix assets from another design system unless the active source or adapter explicitly grants that authority.", "- Verify core accessibility evidence for semantics, landmarks/headings, name/role/value, keyboard navigation, focus order, focus-visible, responsive reflow/no-overflow, and automated checks.", "- Add conditional accessibility evidence for visuals, custom widgets, forms, status messages, overlays, motion, media, dense controls, and hover/focus content when those patterns appear.", "- For text over substantive visuals or rendered backgrounds, verify WCAG AA contrast from browser-rendered output, not screenshots alone.", @@ -10702,6 +10930,8 @@ export function createFrontendImplementationSkillContext({ ); } + const designSystemAdapterWasProvided = + designSystemAdapter !== undefined && designSystemAdapter !== null; const normalizedDesignSystemAdapter = normalizeDesignSystemAdapter(designSystemAdapter); const normalizedTargetClient = optionalString(targetClient); const normalizedInstructionFormat = normalizeInstructionFormat(instructionFormat); @@ -10730,6 +10960,12 @@ export function createFrontendImplementationSkillContext({ implementationContract.default_ai_native_design_system, DEFAULT_AI_NATIVE_DESIGN_SYSTEM, ); + if ( + designSystemAdapterWasProvided && + !hasDesignGuidanceValue(normalizedDesignSystemAdapter) + ) { + validateExternalDesignSystemAdapter(normalizedDesignSystemAdapter); + } let designSystemSource = normalizeDesignSystemSource( implementationContract.design_system_source ?? implementationGuidance.design_system_source, @@ -10861,7 +11097,7 @@ export function createFrontendImplementationSkillContext({ "Use numbered wizard or stepper UI only when workflow.stepper_eligibility.allowed is true.", "Use approved primitives and approved component families before introducing new UI helpers.", "Use implementation_contract.design_system_source as the active source for visual tokens, typography, icon assets, and renderer components.", - "Use JudgmentKit design-system exports by default; when external_design_system is active, do not mix in JudgmentKit default assets unless the external adapter explicitly names them.", + "Do not mix assets from another design system unless the active source or adapter explicitly grants that authority.", "When the spec calls for substantive visuals, use imagegen or premium Three.js/WebGL/D3-style rendering instead of rudimentary deterministic geometry.", "Verify core accessibility evidence: automated checks, semantic content, landmarks/headings, name-role-value, keyboard navigation, focus order, focus-visible, and responsive reflow/no-overflow.", "Add conditional accessibility evidence for visuals, custom widgets, forms, status messages, overlays, motion, media, dense controls, and hover/focus content when those patterns appear.", diff --git a/src/mcp.mjs b/src/mcp.mjs index 28a59d7..7f2558b 100644 --- a/src/mcp.mjs +++ b/src/mcp.mjs @@ -234,7 +234,7 @@ const UI_GENERATION_HANDOFF_TOOL = { const UI_IMPLEMENTATION_CONTRACT_TOOL = { name: "create_ui_implementation_contract", description: - "Create an implementation contract for generated UI, using JudgmentKit design-system authority by default or a complete external design-system adapter when supplied.", + "Create an implementation contract for generated UI. When no design system is supplied, JudgmentKit uses its package default; explicit design_system_source and design_system_adapter inputs must be complete.", inputSchema: { type: "object", properties: { @@ -249,17 +249,17 @@ const UI_IMPLEMENTATION_CONTRACT_TOOL = { external_authority: { type: "string", description: - "Optional trace metadata for a named UI authority. It does not replace JudgmentKit defaults unless design_system_adapter is also supplied.", + "Optional trace metadata for a named UI authority. It does not replace the JudgmentKit package default unless design_system_source or design_system_adapter is also supplied.", }, design_system_adapter: { type: "object", description: - "Optional complete external design-system authority. Must define token, font, icon, and component authority or the contract fails with incomplete_design_system_authority.", + "Complete external design-system authority. Must define token, font, icon, and component authority or the contract fails with incomplete_design_system_authority.", }, design_system_source: { type: "object", description: - "Optional normalized active design-system source when passing an already-created implementation contract shape.", + "Complete normalized active design-system source. Omit this field to use the JudgmentKit package default.", }, repo_evidence: { type: "array", @@ -303,7 +303,7 @@ const UI_IMPLEMENTATION_CONTRACT_TOOL = { visual_token_adapter: { type: "object", description: - "Optional JudgmentKit-default token, font, and icon metadata. Ignored when design_system_adapter supplies complete external authority.", + "Optional token, font, and icon metadata for the active source. Ignored when design_system_adapter supplies complete external authority.", }, }, additionalProperties: false, diff --git a/tests/demo-model-ui-matrix.test.mjs b/tests/demo-model-ui-matrix.test.mjs index 1631891..dec8a5a 100644 --- a/tests/demo-model-ui-matrix.test.mjs +++ b/tests/demo-model-ui-matrix.test.mjs @@ -41,7 +41,9 @@ function visibleText(html) { function normalizeFrontendSkillSummary(summary) { if (!summary) return summary; const designSystemMode = - /^no_design_system_.*provided$/.test(summary.design_system_mode ?? "") + summary.design_system_mode === "judgmentkit_default" + ? "judgmentkit_default" + : /^no_design_system_.*provided$/.test(summary.design_system_mode ?? "") ? "judgmentkit_default" : /^adapter_after_/.test(summary.design_system_mode ?? "") ? "external_design_system" @@ -51,7 +53,8 @@ function normalizeFrontendSkillSummary(summary) { ...summary, design_system_mode: designSystemMode, design_system_name: - designSystemMode === "judgmentkit_default" && !summary.design_system_name + designSystemMode === "judgmentkit_default" && + (!summary.design_system_name || summary.design_system_name === "JudgmentKit") ? "JudgmentKit" : summary.design_system_name, }; diff --git a/tests/kernel-contract.test.mjs b/tests/kernel-contract.test.mjs index 57e1b7d..aab3ace 100644 --- a/tests/kernel-contract.test.mjs +++ b/tests/kernel-contract.test.mjs @@ -508,8 +508,71 @@ assert.equal(defaultDesignSystemSource.fallback_policy, "fail_incomplete"); assert.equal(defaultDesignSystemSource.provenance_required, true); assert.ok(defaultDesignSystemSource.token_prefixes.includes("--jk-")); assert.ok(defaultDesignSystemSource.source_exports.icon_tools.includes("get_icon_svg")); +assert.equal( + defaultDesignSystemSource.source_exports.manifest, + "package://judgmentkit/design-system/manifest.json", +); assert.ok(defaultDesignSystemSource.renderer_components.includes("action_button")); +const surfacesSourceContract = createUiImplementationContract({ + design_system_source: { + id: "surfaces.design-contract.v1", + mode: "external_design_system", + name: "Surfaces", + package: "@surfaces/ui", + definition_point: "implementation_contract.design_system_source", + source_exports: { + overview: "https://surfaces.systems/design-system", + manifest: "https://surfaces.systems/design-system/manifest.json", + visual_token_adapter: + "https://surfaces.systems/design-system/visual-token-adapter.json", + component_contracts: + "https://surfaces.systems/design-system/component-contracts.json", + pattern_contracts: + "https://surfaces.systems/design-system/pattern-contracts.json", + accessibility_policy: + "https://surfaces.systems/design-system/accessibility-policy.json", + icon_catalog: "https://surfaces.systems/design-system/icons/", + }, + required_authorities: ["tokens", "fonts", "icons", "components"], + fallback_policy: "fail_incomplete", + provenance_required: true, + token_prefixes: ["--surfaces-"], + icon_catalog: { + source: "external_contract", + library: "surfaces", + package: "@surfaces/icons", + version: "1.0.0", + icon_count: 1, + license: "repo-approved", + notice: "Surfaces icon metadata is governed by the external contract.", + style_system: "Surfaces outline icons", + style_attributes: { + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + }, + mcp_tools: ["surfaces.list_icons"], + default_include_svg: false, + }, + renderer_components: ["action_button"], + component_contract_source: + "https://surfaces.systems/design-system/component-contracts.json", + provenance_rules: [ + "visual tokens, fonts, icons, and components must come from Surfaces", + ], + }, +}); +assert.equal( + surfacesSourceContract.implementation_contract.design_system_source.id, + "surfaces.design-contract.v1", +); +assert.equal( + surfacesSourceContract.implementation_contract.design_system_source.source_exports + .manifest, + "https://surfaces.systems/design-system/manifest.json", +); + const externalTraceOnlyContract = createUiImplementationContract({ external_authority: "Material UI", }); @@ -519,6 +582,32 @@ assert.equal( "external_authority is trace metadata only without a complete design_system_adapter.", ); +assert.throws( + () => + createUiImplementationContract({ + design_system_source: {}, + }), + (error) => + error instanceof JudgmentKitInputError && + error.code === "invalid_design_system_source", + "An empty explicit design_system_source must fail instead of falling back.", +); + +assert.throws( + () => + createUiImplementationContract({ + design_system_source: { + ...surfacesSourceContract.implementation_contract.design_system_source, + icon_catalog: {}, + }, + }), + (error) => + error instanceof JudgmentKitInputError && + error.code === "invalid_design_system_source" && + error.details.missing.includes("icon_catalog.library"), + "An explicit design_system_source with an empty icon catalog must fail.", +); + const externalDesignSystemContract = createUiImplementationContract({ design_system_adapter: completeMaterialDesignSystemAdapter(), }); diff --git a/tests/lucide-icon-catalog.test.mjs b/tests/lucide-icon-catalog.test.mjs index 42f2617..ff6d73d 100644 --- a/tests/lucide-icon-catalog.test.mjs +++ b/tests/lucide-icon-catalog.test.mjs @@ -2,6 +2,7 @@ import assert from "node:assert/strict"; import { execFileSync } from "node:child_process"; import { + JudgmentKitInputError, createFrontendGenerationContext, createFrontendImplementationSkillContext, createUiGenerationHandoff, @@ -161,3 +162,32 @@ assert.ok(skillContext.pattern_contracts.some((entry) => entry.id === "workbench assert.ok(skillContext.instruction_markdown.includes("Icon catalog")); assert.ok(skillContext.instruction_markdown.includes("--jk-color-surface")); assert.ok(skillContext.instruction_markdown.includes("Component contracts")); + +const legacyHandoffWithoutSource = { + ...handoff, + implementation_contract: { + ...handoff.implementation_contract, + design_system_source: undefined, + }, +}; +delete legacyHandoffWithoutSource.implementation_contract.design_system_source; + +const defaultedFrontendContext = createFrontendGenerationContext({ + ui_generation_handoff: legacyHandoffWithoutSource, +}); +assert.equal( + defaultedFrontendContext.implementation_contract.design_system_source.mode, + "judgmentkit_default", +); + +assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: defaultedFrontendContext, + design_system_adapter: {}, + }), + (error) => + error instanceof JudgmentKitInputError && + error.code === "incomplete_design_system_authority", + "An explicitly supplied empty frontend design_system_adapter must fail.", +); diff --git a/tests/mcp-http.test.mjs b/tests/mcp-http.test.mjs index 2f3f121..62c01fe 100644 --- a/tests/mcp-http.test.mjs +++ b/tests/mcp-http.test.mjs @@ -136,6 +136,11 @@ async function runMcpClient(endpoint) { .visual_token_adapter.mode, "boundary_only", ); + assert.equal( + implementationContractResponse.structuredContent.implementation_contract + .design_system_source.mode, + "judgmentkit_default", + ); assert.ok( implementationContractResponse.structuredContent.implementation_contract .visual_token_adapter.token_families.includes("color"), diff --git a/tests/mcp.test.mjs b/tests/mcp.test.mjs index 57215cd..b2d5368 100644 --- a/tests/mcp.test.mjs +++ b/tests/mcp.test.mjs @@ -91,6 +91,10 @@ assert.equal(toolByName.create_ui_implementation_contract.inputSchema.properties assert.equal(toolByName.create_ui_implementation_contract.inputSchema.properties.iteration_policy.type, "object"); assert.equal(toolByName.create_ui_implementation_contract.inputSchema.properties.design_system_adapter.type, "object"); assert.equal(toolByName.create_ui_implementation_contract.inputSchema.properties.design_system_source.type, "object"); +assert.equal( + "fixture_design_system" in toolByName.create_ui_implementation_contract.inputSchema.properties, + false, +); assert.equal(toolByName.create_ui_implementation_contract.inputSchema.properties.visual_token_adapter.type, "object"); assert.ok( toolByName.create_ui_implementation_contract.inputSchema.properties.visual_token_adapter.description.includes( diff --git a/tests/site-local-server.test.mjs b/tests/site-local-server.test.mjs index 66de37f..c8d8a11 100644 --- a/tests/site-local-server.test.mjs +++ b/tests/site-local-server.test.mjs @@ -97,10 +97,6 @@ try { "/value/", "/docs/", "/docs", - "/design-system/", - "/design-system/tokens/", - "/design-system/fonts/", - "/design-system/icons/", "/examples/", "/evals/", "/install", @@ -110,6 +106,47 @@ try { assert.equal(response.status, 200, `${route} should return 200`); } + for (const route of [ + "/design-system/", + "/design-system", + "/design-system/index.html", + "/design-system/index.html.md", + "/design-system/llms.txt", + "/design-system/llms-full.txt", + "/design-system/tokens/", + "/design-system/tokens", + "/design-system/tokens/index.html", + "/design-system/tokens/index.html.md", + "/design-system/fonts", + "/design-system/fonts/", + "/design-system/fonts/index.html", + "/design-system/fonts/index.html.md", + "/design-system/icons", + "/design-system/icons/", + "/design-system/icons/index.html", + "/design-system/icons/index.html.md", + "/design-system/components", + "/design-system/components/", + "/design-system/components/index.html", + "/design-system/components/index.html.md", + "/design-system/patterns", + "/design-system/patterns/", + "/design-system/patterns/index.html", + "/design-system/patterns/index.html.md", + "/design-system/accessibility", + "/design-system/accessibility/", + "/design-system/accessibility/index.html", + "/design-system/accessibility/index.html.md", + ]) { + const response = await fetchRoute(url, route, { redirect: "manual" }); + + assert.equal(response.status, 308, `${route} should redirect to Surfaces`); + assert.equal( + response.headers.get("location"), + "https://surfaces.systems/design-system", + ); + } + { const response = await fetchRoute(url, "/install"); @@ -169,36 +206,43 @@ try { const response = await fetchRoute(url, route); const body = await response.json(); - assert.equal(response.status, 200, `${route} should return 200`); + assert.equal(response.status, 410, `${route} should return 410`); assert.equal(response.headers.get("content-type"), "application/json; charset=utf-8"); - assert.equal(typeof body, "object"); + assert.equal(body.code, "judgmentkit_design_system_retired"); + assert.equal(body.canonicalUrl, "https://surfaces.systems/design-system"); + assert.equal(body.requestedPath, route); } - for (const route of [ - "/design-system/index.html.md", - "/design-system/tokens/index.html.md", - "/design-system/fonts/index.html.md", - "/design-system/icons/index.html.md", - "/design-system/components/index.html.md", - "/design-system/patterns/index.html.md", - "/design-system/accessibility/index.html.md", - ]) { - const response = await fetchRoute(url, route); - const body = await response.text(); + { + const response = await fetchRoute(url, "/design-system/manifest.json", { + method: "HEAD", + }); - assert.equal(response.status, 200, `${route} should return 200`); - assert.equal(response.headers.get("content-type"), "text/markdown; charset=utf-8"); - assert.ok(body.startsWith("# JudgmentKit"), `${route} should return Markdown`); - assert.equal(body.includes("')); assert.ok(platformNavMarkup.includes('href="/value/"')); assert.ok(platformNavMarkup.includes('href="/docs/"')); -assert.ok(platformNavMarkup.includes('href="/design-system/"')); +assert.equal(platformNavMarkup.includes('href="/design-system/"'), false); assert.ok(platformNavMarkup.includes('href="/examples/"')); assert.ok(platformNavMarkup.includes('href="/evals/"')); assert.ok(platformNavMarkup.includes('href="/mcp"')); @@ -210,7 +220,6 @@ assert.ok(platformNavMarkup.includes('data-surfaces-primary-menu-list')); for (const [href, label] of [ ["/value/", "Value"], ["/docs/", "Docs"], - ["/design-system/", "Design System"], ["/examples/", "Examples"], ["/evals/", "Evals"], ["/mcp", "MCP"], @@ -346,10 +355,11 @@ assert.ok(homepage.includes("Evaluation evidence")); assert.ok(homepage.includes('class="section adoption-paths" aria-labelledby="adoption-title"')); assert.ok(homepage.includes("Choose the next surface for the work you are doing.")); assert.ok(homepage.includes("Read the docs")); -assert.ok(homepage.includes("Review the design-system assets")); +assert.ok(homepage.includes("Review the active design source")); assert.ok(homepage.includes("Start installation")); assert.ok(homepage.includes('href="/docs/"')); -assert.ok(homepage.includes('href="/design-system/"')); +assert.ok(homepage.includes('href="https://surfaces.systems/design-system"')); +assert.equal(homepage.includes('href="/design-system/"'), false); assert.ok(homepage.includes('href="/install"')); assert.ok(siteCss.includes(".evaluation-panel")); assert.ok(siteCss.includes(".failure-grid")); @@ -406,8 +416,8 @@ assert.ok(homepage.includes('name="twitter:image:alt" content="JudgmentKit. Befo assert.ok(llms.includes("- /evals/judgmentkit-mcp/")); assert.ok(llms.includes("- /evals/site-rebuild-log/")); assert.ok(llms.includes("- /value/")); -assert.ok(llms.includes("- /design-system/")); -assert.ok(llms.includes("- /design-system/llms.txt")); +assert.equal(llms.includes("- /design-system/"), false); +assert.equal(llms.includes("- /design-system/llms.txt"), false); assert.equal(llms.includes("- /design-system/tokens/"), false); assert.equal(llms.includes("- /design-system/fonts/"), false); assert.equal(llms.includes("- /design-system/icons/"), false); @@ -520,520 +530,42 @@ assert.equal(docs.includes("optional styling path"), false); assert.ok(docs.includes("operator-review-ui")); assert.equal(docs.includes("judgmentkit2"), false); -const designSystem = fs.readFileSync(path.join(tempDir, "design-system", "index.html"), "utf8"); -const designSystemTokens = fs.readFileSync( - path.join(tempDir, "design-system", "tokens", "index.html"), - "utf8", -); -const designSystemFonts = fs.readFileSync( - path.join(tempDir, "design-system", "fonts", "index.html"), - "utf8", -); -const designSystemIcons = fs.readFileSync( - path.join(tempDir, "design-system", "icons", "index.html"), - "utf8", -); -const designSystemComponents = fs.readFileSync( - path.join(tempDir, "design-system", "components", "index.html"), - "utf8", -); -const designSystemPatterns = fs.readFileSync( - path.join(tempDir, "design-system", "patterns", "index.html"), - "utf8", -); -const designSystemAccessibility = fs.readFileSync( - path.join(tempDir, "design-system", "accessibility", "index.html"), - "utf8", -); -const designSystemMarkdown = fs.readFileSync( - path.join(tempDir, "design-system", "index.html.md"), - "utf8", -); -const designSystemTokensMarkdown = fs.readFileSync( - path.join(tempDir, "design-system", "tokens", "index.html.md"), - "utf8", -); -const designSystemFontsMarkdown = fs.readFileSync( - path.join(tempDir, "design-system", "fonts", "index.html.md"), - "utf8", -); -const designSystemIconsMarkdown = fs.readFileSync( - path.join(tempDir, "design-system", "icons", "index.html.md"), - "utf8", -); -const designSystemComponentsMarkdown = fs.readFileSync( - path.join(tempDir, "design-system", "components", "index.html.md"), - "utf8", -); -const designSystemPatternsMarkdown = fs.readFileSync( - path.join(tempDir, "design-system", "patterns", "index.html.md"), - "utf8", -); -const designSystemAccessibilityMarkdown = fs.readFileSync( - path.join(tempDir, "design-system", "accessibility", "index.html.md"), - "utf8", -); -const designSystemLlms = fs.readFileSync( - path.join(tempDir, "design-system", "llms.txt"), - "utf8", -); -const designSystemLlmsFull = fs.readFileSync( - path.join(tempDir, "design-system", "llms-full.txt"), - "utf8", -); -const designSystemManifest = JSON.parse( - fs.readFileSync(path.join(tempDir, "design-system", "manifest.json"), "utf8"), -); -assert.ok(designSystemTokens.includes('Design System')); -assert.ok(designSystemTokens.includes('Tokens')); -const visualTokenAdapterExport = JSON.parse( - fs.readFileSync(path.join(tempDir, "design-system", "visual-token-adapter.json"), "utf8"), -); -const componentContractsExport = JSON.parse( - fs.readFileSync(path.join(tempDir, "design-system", "component-contracts.json"), "utf8"), -); -const patternContractsExport = JSON.parse( - fs.readFileSync(path.join(tempDir, "design-system", "pattern-contracts.json"), "utf8"), -); -const componentSpecimensExport = JSON.parse( - fs.readFileSync(path.join(tempDir, "design-system", "component-specimens.json"), "utf8"), -); -const patternSpecimensExport = JSON.parse( - fs.readFileSync(path.join(tempDir, "design-system", "pattern-specimens.json"), "utf8"), -); -const specimenProvenanceExport = JSON.parse( - fs.readFileSync(path.join(tempDir, "design-system", "specimen-provenance.json"), "utf8"), -); -const accessibilityPolicyExport = JSON.parse( - fs.readFileSync(path.join(tempDir, "design-system", "accessibility-policy.json"), "utf8"), -); -const iconScenariosExport = JSON.parse( - fs.readFileSync(path.join(tempDir, "design-system", "icon-scenarios.json"), "utf8"), -); -const implementationContract = createUiImplementationContract().implementation_contract; -const defaultDesignSystem = implementationContract.default_ai_native_design_system; -for (const [label, html] of [ - ["design system overview", designSystem], - ["design system tokens", designSystemTokens], - ["design system fonts", designSystemFonts], - ["design system icons", designSystemIcons], - ["design system components", designSystemComponents], - ["design system patterns", designSystemPatterns], - ["design system accessibility", designSystemAccessibility], -]) { - assertAnalyticsBootstrap(html, label); - assert.ok(html.includes("JudgmentKit"), `${label} should identify JudgmentKit`); - assert.equal(/googleapis|gstatic|unpkg|jsdelivr|fontawesome|icons-material/i.test(html), false); -} -for (const [label, markdown] of [ - ["design system markdown", designSystemMarkdown], - ["design system tokens markdown", designSystemTokensMarkdown], - ["design system fonts markdown", designSystemFontsMarkdown], - ["design system icons markdown", designSystemIconsMarkdown], - ["design system components markdown", designSystemComponentsMarkdown], - ["design system patterns markdown", designSystemPatternsMarkdown], - ["design system accessibility markdown", designSystemAccessibilityMarkdown], -]) { - assert.ok(markdown.startsWith("# JudgmentKit"), `${label} should start with a title`); - assert.equal(markdown.includes("Foundations")); -assert.ok(designSystem.includes("Foundation assets")); -assert.ok(designSystem.includes("How to review")); -assert.ok(designSystem.includes("Principles")); -assert.ok(designSystem.includes("Tokens")); -assert.ok(designSystem.includes("Typography")); -assert.ok(designSystem.includes("Icons")); -assert.ok(designSystem.includes('aria-label="Design system sections"')); -assert.ok(designSystem.includes('aria-label="On this page"')); -assert.ok(designSystem.includes("/design-system/tokens/")); -assert.ok(designSystem.includes("/design-system/fonts/")); -assert.ok(designSystem.includes("/design-system/icons/")); -assert.ok(designSystem.includes("/design-system/components/")); -assert.ok(designSystem.includes("/design-system/patterns/")); -assert.ok(designSystem.includes("/design-system/accessibility/")); -assert.ok(designSystemTokens.includes("

    Tokens

    ")); -assert.ok(designSystemTokens.includes("JudgmentKit token roles")); -assert.ok(designSystemTokens.includes("Portable CSS custom properties")); -assert.ok(designSystemTokens.includes("roles + CSS")); -assert.ok(designSystemTokens.includes("

    Appearance

    ")); -assert.ok(designSystemTokens.includes("system-detected")); -assert.ok(designSystemTokens.includes('data-appearance-default="system"')); -assert.ok(designSystemTokens.includes('data-visible-appearance-toggle="false"')); -assert.ok(designSystemTokens.includes("--jk-color-surface")); -assert.ok(designSystemTokens.includes("#ffffff")); -assert.ok(designSystemTokens.includes("@media (prefers-color-scheme: dark)")); -assert.ok(designSystemTokens.includes("#181d1b")); -assert.ok(designSystemTokens.includes('data-token-value="--jk-color-surface"')); -assert.ok(designSystemTokens.includes('data-token-swatch="--jk-color-surface"')); -assert.ok(designSystemTokens.includes('aria-label="--jk-color-surface color swatch: #ffffff"')); -assert.ok(designSystemTokens.includes("token-value-with-swatch")); -assert.ok(designSystemTokens.includes("role-first layer")); -assert.ok(designSystemTokens.includes("Token roles")); -assert.ok(designSystemTokens.includes("surface")); -assert.ok(designSystemTokens.includes("focus")); -assert.ok(designSystemTokens.includes("receipt")); -assert.ok(designSystemTokens.includes('data-token-role="surface"')); -assert.ok(designSystemTokens.includes('data-token-role="focus"')); -assert.ok(designSystemTokens.includes("JudgmentKit token roles")); -assert.ok(designSystemTokens.includes("Accessibility")); -assert.ok(designSystemTokens.includes("Color cannot be the only way")); -assert.ok(designSystemTokensMarkdown.includes("## Appearance")); -assert.ok(designSystemTokensMarkdown.includes("Default mode: `system`")); -assert.ok(designSystemTokensMarkdown.includes("Visible appearance toggle by default: `false`")); -assert.ok(designSystemTokensMarkdown.includes("Token sets: `light`, `dark`")); -assert.equal(designSystemTokens.includes("Evidence Expectations"), false); -assert.equal(designSystemTokens.includes("Failure Signals"), false); -assert.ok(designSystemFonts.includes("

    Typography

    ")); -assert.ok(designSystemFonts.includes("JudgmentKit typography roles")); -assert.ok(designSystemFonts.includes("body")); -assert.ok(designSystemFonts.includes("heading")); -assert.ok(designSystemFonts.includes("label")); -assert.ok(designSystemFonts.includes("numeric")); -assert.ok(designSystemFonts.includes("diagnostic")); -assert.ok(designSystemFonts.includes('data-font-role="body"')); -assert.ok(designSystemFonts.includes('data-font-role="numeric"')); -assert.ok(designSystemFonts.includes('data-font-role="diagnostic"')); -assert.ok(designSystemFonts.includes("system-ui, -apple-system")); -assert.ok(designSystemFonts.includes("ui-monospace")); -assert.ok(designSystemFonts.includes("No font CDN or bundled font files.")); -assert.ok(designSystemFonts.includes("Respect browser text scaling")); -assert.ok(designSystemIcons.includes("

    Icons

    ")); -assert.ok(designSystemIcons.includes("A complete Lucide icon catalog")); -assert.ok(designSystemIcons.includes("lucide-static@1.21.0")); -assert.ok(designSystemIcons.includes("1737")); -assert.ok(designSystemIcons.includes("Usage")); -assert.ok(designSystemIcons.includes("Icon index")); -assert.ok(designSystemIcons.includes("Accessibility")); -assert.ok(designSystemIcons.includes("Source")); -assert.ok(designSystemIcons.includes("Choose the icon by the meaning")); -assert.ok(designSystemIcons.includes('data-design-icon-search')); -assert.ok(designSystemIcons.includes('class="site-shell doc-layout design-system-layout"')); -assert.ok(designSystemIcons.includes('class="section-rail-menu design-system-section-menu" data-section-rail-menu')); -assert.ok(designSystemIcons.includes('class="section-rail-menu-button"')); -assert.ok(designSystemIcons.includes('aria-controls="design-system-section-menu-icons"')); -assert.ok(designSystemIcons.includes('data-section-rail-menu-button')); -assert.ok(designSystemIcons.includes('data-section-rail-menu-backdrop')); -assert.ok(designSystemIcons.includes('id="design-system-section-menu-icons" hidden data-section-rail-menu-list aria-label="Design system sections"')); -assert.ok(designSystemIcons.includes('data-section-rail-menu-list')); -assert.ok(designSystemIcons.includes('class="section-rail-nav design-system-nav" aria-label="Design system sections"')); -assert.ok(designSystemIcons.includes('Icons')); -assert.equal(designSystemIcons.includes('id="design-system-section-menu-icons" role="menu"'), false); -assert.equal(designSystemIcons.includes('/g, -) ?? []; -assert.equal(designSystemIcons.includes("Icon examples"), false); -assert.equal(designSystemIcons.includes('id="icon-examples"'), false); -assert.equal(designSystemIcons.includes('href="#icon-examples"'), false); -assert.equal(designSystemIcons.includes('data-icon-example='), false); -assert.equal(designSystemIcons.includes("data-selected-icon-id"), false); -assert.ok(designSystemIcons.includes('data-icon-scenario="status-success"')); -assert.ok(designSystemIcons.includes('data-icon-id="check"')); -assert.equal(designSystemIcons.includes("

    Status success

    "), false); -assert.equal(designSystemIcons.includes("

    A Arrow Down

    "), false); -assert.equal(designSystemIcons.includes("Show a completed status beside a visible result label."), false); -assert.ok(designSystemIcons.includes('data-icon-id="receipt-text"')); -assert.ok(designSystemIcons.includes('data-icon-name="Receipt Text"')); -assert.ok(designSystemIcons.includes("Every catalog entry uses the same icon and ID card format.")); +const retiredDesignSystemDir = path.join(tempDir, "design-system"); assert.equal( - designSystemIcons.includes("Every catalog entry uses the same icon, label, and ID card format."), + fs.existsSync(retiredDesignSystemDir), false, + "site build must not emit a public JudgmentKit design-system directory.", ); -assert.equal( - designSystemIcons.includes("Every catalog entry uses the same icon, label, meaning, and ID card format."), - false, -); -assert.equal( - designSystemIcons.includes( - "Lucide catalog icon available for JudgmentKit interface states, actions, navigation, and objects.", - ), - false, -); -assert.equal(designSystemIcons.includes("
    Icon
    "), false); -assert.ok(designSystemIcons.includes('check')); -assert.equal(designSystemIcons.includes("list_icon_catalog"), false); -assert.equal(designSystemIcons.includes("search_icon_catalog"), false); -assert.equal(designSystemIcons.includes("get_icon_svg"), false); -assert.ok(designSystemIcons.includes("/examples/lucide-icon-catalog-smoke.html")); -assert.equal(designSystemIcons.includes("data-catalog-icon"), false); -assert.ok(designSystemIcons.includes(" card.includes("

    ")), false); -assert.equal(iconIndexCards.some((card) => card.includes("

    ")), false); -assert.equal((designSystemIcons.match(/data-icon-scenario=/g) ?? []).length, 16); -assert.equal((designSystemIcons.match(/data-icon-id=/g) ?? []).length, 1737); -assert.equal((designSystemIcons.match(/class="design-icon-id"/g) ?? []).length, 1737); -assert.equal((designSystemIcons.match(/data-catalog-icon=/g) ?? []).length, 0); -assert.equal((designSystemIcons.match(/class="design-icon-scenario(?:\s|")/g) ?? []).length, 1737); -assert.equal(designSystemIcons.includes("without loading the full SVG grid"), false); -assert.equal(siteCss.includes(".design-icon-tile"), false); -assert.equal(siteCss.includes(".design-icon-scenario h3"), false); -assert.equal(siteCss.includes(".design-icon-scenario p"), false); -assert.equal(siteCss.includes("min-height: 178px;"), false); -assert.ok(siteCss.includes(".design-icon-symbol {\n display: grid;\n width: 24px;\n min-height: 24px;\n place-items: center;\n color: inherit;\n}")); -assert.ok(siteCss.includes("grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));")); -assert.ok(siteCss.includes(".design-icon-index-list {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));\n align-items: start;")); -assert.ok(siteCss.includes(".design-icon-index-card[hidden] {\n display: none;\n}")); -assert.ok(Buffer.byteLength(designSystemIcons, "utf8") < 2_500_000); -assert.ok(designSystemComponents.includes("

    Components

    ")); -assert.ok(designSystemComponents.includes("Core UI component contracts")); -assert.ok(designSystemComponents.includes("

    Specimens

    ")); -assert.ok(designSystemComponents.includes('data-specimen-id="component.action_button"')); -assert.ok(designSystemComponents.includes('data-contract-hash="sha256:')); -assert.ok(designSystemComponents.includes('data-component-state="focus-visible"')); -assert.ok(designSystemComponents.includes('data-component-anatomy="visible-label"')); -assert.ok(designSystemComponents.includes('data-token-role="decision"')); -assert.ok(designSystemComponents.includes("Contract hash")); -assert.ok(designSystemComponents.includes("Output hash")); -assert.ok(designSystemComponents.includes('data-component-contract="action_button"')); -assert.ok(designSystemComponents.includes('data-component-contract="dialog"')); -assert.ok(designSystemComponents.includes("required state coverage")); -assert.ok(designSystemPatterns.includes("

    Patterns

    ")); -assert.ok(designSystemPatterns.includes("Surface pattern contracts")); -assert.ok(designSystemPatterns.includes("

    Specimens

    ")); -assert.ok(designSystemPatterns.includes('data-specimen-id="pattern.workbench"')); -assert.ok(designSystemPatterns.includes('data-pattern-region="work-queue"')); -assert.ok(designSystemPatterns.includes('data-pattern-control="decision-action"')); -assert.ok(designSystemPatterns.includes('data-pattern-contract="workbench"')); -assert.ok(designSystemPatterns.includes('data-surface-type="operator_review"')); -assert.ok(designSystemPatterns.includes("required regions")); -assert.ok(designSystemAccessibility.includes("

    Accessibility

    ")); -assert.ok(designSystemAccessibility.includes("WCAG 2.2 AA")); -assert.ok(designSystemAccessibility.includes("Normal text contrast target: 4.5:1.")); -assert.ok(designSystemAccessibility.includes('data-accessibility-contract="keyboard_and_focus"')); -assert.ok(designSystemComponentsMarkdown.includes("## Component Contracts")); -assert.ok(designSystemPatternsMarkdown.includes("## Surface Pattern Contracts")); -assert.ok(designSystemAccessibilityMarkdown.includes("## Evidence Groups")); -assert.ok(designSystemComponentsMarkdown.includes("## Specimens")); -assert.ok(designSystemPatternsMarkdown.includes("## Specimens")); +for (const artifact of [ + "manifest.json", + "visual-token-adapter.json", + "component-contracts.json", + "pattern-contracts.json", + "component-specimens.json", + "pattern-specimens.json", + "specimen-provenance.json", + "accessibility-policy.json", + "icon-scenarios.json", +]) { + assert.equal( + fs.existsSync(path.join(retiredDesignSystemDir, artifact)), + false, + `site build must not emit stale JudgmentKit design-system JSON: ${artifact}`, + ); +} +const implementationContract = createUiImplementationContract().implementation_contract; +const defaultDesignSystem = implementationContract.default_ai_native_design_system; +assert.equal(implementationContract.design_system_source.mode, "judgmentkit_default"); +assert.ok(defaultDesignSystem.component_contracts.length > 0); +assert.ok(defaultDesignSystem.pattern_contracts.length > 0); const lucideSmokeProof = fs.readFileSync( path.join(tempDir, "examples", "lucide-icon-catalog-smoke.html"), "utf8", ); assert.equal((lucideSmokeProof.match(/data-catalog-icon=/g) ?? []).length, 1737); -assert.ok(siteCss.includes(".design-system-page")); -assert.ok(siteCss.includes(".design-system-foundation-list")); -assert.ok(siteCss.includes(".design-system-table")); -assert.ok(siteCss.includes(".design-system-search")); -assert.ok(siteCss.includes(".design-system-example-grid")); -assert.ok(siteCss.includes(".design-system-specimen-list")); -assert.ok(siteCss.includes(".jk-specimen-preview")); assert.ok(siteCss.includes(".design-icon-index-list")); assert.ok(siteCss.includes(".design-icon-index-card")); assert.ok(siteCss.includes(".design-icon-symbol svg")); -assert.ok(designSystemLlms.includes("# JudgmentKit Design System")); -assert.ok(designSystemLlms.includes("/design-system/")); -assert.ok(designSystemLlms.includes("/design-system/index.html.md")); -assert.ok(designSystemLlms.includes("/design-system/manifest.json")); -assert.ok(designSystemLlms.includes("/design-system/component-contracts.json")); -assert.ok(designSystemLlms.includes("/design-system/pattern-contracts.json")); -assert.ok(designSystemLlms.includes("/design-system/component-specimens.json")); -assert.ok(designSystemLlms.includes("/design-system/pattern-specimens.json")); -assert.ok(designSystemLlms.includes("/design-system/specimen-provenance.json")); -assert.ok(designSystemLlms.includes("/design-system/accessibility-policy.json")); -assert.ok(designSystemLlms.includes("/examples/lucide-icon-catalog-smoke.html")); -assert.ok(designSystemLlmsFull.includes("## Principles")); -assert.equal(designSystemLlmsFull.includes("## Icon Examples"), false); -assert.ok(designSystemLlmsFull.includes("Common interface meanings such as status")); -assert.ok(designSystemLlmsFull.includes("## Specimens")); -assert.ok(designSystemLlmsFull.includes("## Component Contracts")); -assert.ok(designSystemLlmsFull.includes("## Surface Pattern Contracts")); -assert.equal(designSystemLlmsFull.includes("data-catalog-icon"), false); -assert.equal(designSystemLlmsFull.includes("Agent Consumption"), false); -assert.equal(designSystemManifest.exports.llms, "/design-system/llms.txt"); -assert.equal(designSystemManifest.exports.visual_token_adapter, "/design-system/visual-token-adapter.json"); -assert.equal(designSystemManifest.exports.component_contracts, "/design-system/component-contracts.json"); -assert.equal(designSystemManifest.exports.pattern_contracts, "/design-system/pattern-contracts.json"); -assert.equal(designSystemManifest.exports.component_specimens, "/design-system/component-specimens.json"); -assert.equal(designSystemManifest.exports.pattern_specimens, "/design-system/pattern-specimens.json"); -assert.equal(designSystemManifest.exports.specimen_provenance, "/design-system/specimen-provenance.json"); -assert.equal(designSystemManifest.exports.accessibility_policy, "/design-system/accessibility-policy.json"); -assert.equal(designSystemManifest.section, "JudgmentKit Design System"); -assert.equal(designSystemManifest.purpose, "Human reference for foundation assets."); -assert.equal( - designSystemManifest.source.design_system_contract_id, - "judgmentkit.ai-native-default.contract-v1", -); -assert.equal(designSystemManifest.source.lucide.package, "lucide-static"); -assert.equal(designSystemManifest.source.lucide.version, "1.21.0"); -assert.equal(designSystemManifest.source.lucide.icon_count, 1737); -assert.ok( - visualTokenAdapterExport.css_custom_properties.some( - (entry) => entry.name === "--jk-color-surface" && entry.value === "#ffffff", - ), -); -assert.equal(visualTokenAdapterExport.appearance_policy.default_mode, "system"); -assert.equal(visualTokenAdapterExport.appearance_policy.visible_toggle_default, false); -assert.deepEqual(visualTokenAdapterExport.appearance_policy.supported_modes, [ - "light", - "dark", - "system", -]); -assert.ok( - visualTokenAdapterExport.appearance_token_sets.some( - (entry) => - entry.mode === "dark" && - entry.color_scheme === "dark" && - entry.css_custom_properties.some( - (token) => token.name === "--jk-color-surface" && token.value === "#181d1b", - ), - ), -); -assert.equal(componentContractsExport.source, "judgmentkit.ai-native-default.contract-v1"); -assert.equal(componentContractsExport.contracts.length, 17); -assert.ok(componentContractsExport.contracts.some((entry) => entry.id === "action_button")); -assert.ok( - componentContractsExport.contracts - .find((entry) => entry.id === "dialog") - .accessibility_checks.includes("focus management"), -); -assert.equal(patternContractsExport.source, "judgmentkit.ai-native-default.contract-v1"); -assert.equal(patternContractsExport.contracts.length, 8); -assert.ok(patternContractsExport.contracts.some((entry) => entry.id === "workbench")); -assert.equal( - patternContractsExport.contracts.find((entry) => entry.id === "operator_review") - .surface_type, - "operator_review", -); -assert.equal(componentSpecimensExport.source, "judgmentkit.ai-native-default.contract-v1"); -assert.equal(componentSpecimensExport.renderer.id, "judgmentkit-static-specimens"); -assert.equal(componentSpecimensExport.specimens.length, componentContractsExport.contracts.length); -assert.equal(patternSpecimensExport.source, "judgmentkit.ai-native-default.contract-v1"); -assert.equal(patternSpecimensExport.renderer.id, "judgmentkit-static-specimens"); -assert.equal(patternSpecimensExport.specimens.length, patternContractsExport.contracts.length); -assert.equal(specimenProvenanceExport.source, "judgmentkit.ai-native-default.contract-v1"); -assert.equal( - specimenProvenanceExport.design_system_contract_hash, - hashCanonical(defaultDesignSystem), -); -assert.equal( - specimenProvenanceExport.token_hash, - hashCanonical(visualTokenAdapterExport.css_custom_properties), -); -assert.equal( - specimenProvenanceExport.icon_catalog_hash, - hashCanonical(visualTokenAdapterExport.icon_catalog), -); - -for (const contract of componentContractsExport.contracts) { - const specimen = componentSpecimensExport.specimens.find( - (entry) => entry.contract_id === contract.id, - ); - assert.ok(specimen, `${contract.id} should have a component specimen`); - assert.equal(specimen.contract_hash, hashCanonical(contract)); - assert.equal(specimen.output_hash, hashText(specimen.rendered_html)); - assert.equal( - specimen.selectors.root, - `[data-specimen-id="component.${contract.id}"]`, - ); - assert.ok( - designSystemComponents.includes(`data-specimen-id="component.${contract.id}"`), - `${contract.id} specimen root should render`, - ); - for (const state of contract.required_states) { - assert.ok(specimen.covered_states.includes(state), `${contract.id} should cover ${state}`); - assert.ok(specimen.selectors.states[state], `${contract.id} should expose selector for ${state}`); - assert.ok( - specimen.rendered_html.includes(`data-component-state="${state}"`), - `${contract.id} should render ${state}`, - ); - } - for (const anatomy of contract.anatomy) { - assert.ok( - specimen.rendered_html.includes(`data-component-anatomy="${anatomy.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "").toLowerCase()}"`), - `${contract.id} should render anatomy ${anatomy}`, - ); - } -} - -for (const contract of patternContractsExport.contracts) { - const specimen = patternSpecimensExport.specimens.find( - (entry) => entry.contract_id === contract.id, - ); - assert.ok(specimen, `${contract.id} should have a pattern specimen`); - assert.equal(specimen.contract_hash, hashCanonical(contract)); - assert.equal(specimen.output_hash, hashText(specimen.rendered_html)); - assert.equal( - specimen.selectors.root, - `[data-specimen-id="pattern.${contract.id}"]`, - ); - assert.ok( - designSystemPatterns.includes(`data-specimen-id="pattern.${contract.id}"`), - `${contract.id} specimen root should render`, - ); - assert.equal(specimen.surface_type, contract.surface_type); - for (const region of contract.required_regions) { - assert.ok(specimen.covered_regions.includes(region), `${contract.id} should cover ${region}`); - assert.ok(specimen.selectors.regions[region], `${contract.id} should expose selector for ${region}`); - assert.ok( - specimen.rendered_html.includes(`data-pattern-region="${region.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "").toLowerCase()}"`), - `${contract.id} should render region ${region}`, - ); - } - for (const control of contract.expected_controls) { - assert.ok(specimen.covered_controls.includes(control), `${contract.id} should cover ${control}`); - assert.ok(specimen.selectors.controls[control], `${contract.id} should expose selector for ${control}`); - assert.ok( - specimen.rendered_html.includes(`data-pattern-control="${control.replace(/[^a-z0-9]+/gi, "-").replace(/^-+|-+$/g, "").toLowerCase()}"`), - `${contract.id} should render control ${control}`, - ); - } -} - -assert.deepEqual( - specimenProvenanceExport.component_specimens.map((entry) => entry.id), - componentSpecimensExport.specimens.map((entry) => entry.id), -); -assert.deepEqual( - specimenProvenanceExport.pattern_specimens.map((entry) => entry.id), - patternSpecimensExport.specimens.map((entry) => entry.id), -); -assert.ok(specimenProvenanceExport.proof_scope.includes("do not replace")); -assert.equal(accessibilityPolicyExport.standards_profile.baseline, "WCAG 2.2 AA"); -assert.equal(accessibilityPolicyExport.contrast_targets.normal_text_min_ratio, 4.5); -assert.equal(visualTokenAdapterExport.icon_catalog.package, "lucide-static"); -assert.equal(visualTokenAdapterExport.icon_catalog.version, "1.21.0"); -assert.equal(visualTokenAdapterExport.icon_catalog.icon_count, 1737); -assert.deepEqual(iconScenariosExport.mcp_tools, [ - "list_icon_catalog", - "search_icon_catalog", - "get_icon_svg", -]); -assert.equal(iconScenariosExport.source.package, "lucide-static"); -assert.equal(iconScenariosExport.source.version, "1.21.0"); -assert.equal(iconScenariosExport.source.icon_count, 1737); -assert.equal(iconScenariosExport.scenarios.length, 16); -assert.equal(iconScenariosExport.scenarios.some((scenario) => "inline_svg" in scenario), false); -assert.ok( - iconScenariosExport.scenarios.some( - (scenario) => scenario.intent === "Show a completed status beside a visible result label.", - ), -); -assert.ok(iconScenariosExport.scenarios.some((scenario) => scenario.selected_icon_id === "receipt-text")); const value = fs.readFileSync(path.join(tempDir, "value", "index.html"), "utf8"); const valuePrimaryStory = value @@ -1114,14 +646,14 @@ assert.ok(examples.includes("AI-native design system")); assert.ok(examples.includes("First-use loop and canonical contract cases")); assert.ok(examples.includes("/examples/ai-native-design-system/first-use.json")); assert.ok(examples.includes("/examples/ai-native-design-system/canonical-examples.json")); -assert.ok(examples.includes("/design-system/icons/")); +assert.equal(examples.includes("/design-system/icons/"), false); assert.ok(examples.includes("/examples/lucide-icon-catalog-smoke.html")); assert.ok(examples.includes("ED flow board MVP")); assert.ok(examples.includes("/examples/er-flow-dashboard/")); assert.ok(examples.includes("room occupancy, waiting acuity, turnover, holds, and charge-team next moves")); assert.ok(examples.includes("Tokens, system font stacks, and Lucide icon catalog policy remain governed metadata")); -assert.ok(examples.includes("The design-system icon page is the reference surface")); -assert.ok(examples.includes("this HTML remains the deterministic regression proof")); +assert.equal(examples.includes("The design-system icon page is the reference surface"), false); +assert.ok(examples.includes("This HTML remains the deterministic regression proof")); assert.ok(examples.includes("Model UI matrix")); assert.ok(examples.includes("These matrix examples compare")); assert.ok(examples.includes('class="model-ui-use-case-select" data-use-case-select aria-label="Use case"')); @@ -1446,17 +978,20 @@ assert.ok(siteRebuildLog.includes("Workflow review")); assert.ok(siteRebuildLog.includes("Implementation contract")); assert.ok(siteRebuildLog.includes("Implementation review")); assert.ok(siteRebuildLog.includes("review_ui_implementation_candidate: passed")); -assert.ok(siteRebuildLog.includes("Design-system source")); +assert.ok(siteRebuildLog.includes("Design-source evidence")); assert.ok(siteRebuildLog.includes("judgmentkit.ai-native-default.contract-v1")); assert.ok(siteRebuildLog.includes("Token roles")); assert.ok(siteRebuildLog.includes("Component contracts")); assert.ok(siteRebuildLog.includes("Surface patterns")); assert.ok(siteRebuildLog.includes("1737 Lucide icons")); assert.ok(siteRebuildLog.includes("judgmentkit-static-specimens")); -assert.ok(siteRebuildLog.includes("/design-system/manifest.json")); -assert.ok(siteRebuildLog.includes("/design-system/specimen-provenance.json")); +assert.ok(siteRebuildLog.includes("https://surfaces.systems/design-system")); +assert.equal(siteRebuildLog.includes("/design-system/manifest.json"), false); +assert.equal(siteRebuildLog.includes("/design-system/specimen-provenance.json"), false); assert.ok(siteRebuildLog.includes("same source-controlled static generator")); -assert.ok(siteRebuildLog.includes("tests that verify those assets, contracts, specimens, and provenance")); +assert.ok(siteRebuildLog.includes("JudgmentKit keeps a package-default design-system contract")); +assert.ok(siteRebuildLog.includes("public JudgmentKit design-system routes are no longer the source of truth")); +assert.ok(siteRebuildLog.includes("package-default source metadata")); assert.ok(siteRebuildLog.includes("site/build-site.mjs")); assert.ok(siteRebuildLog.includes("tests/site.test.mjs")); assert.ok(siteRebuildLog.includes("npm run site:build")); @@ -1465,6 +1000,9 @@ assert.ok(siteRebuildLog.includes("npm test")); assert.ok(siteRebuildLog.includes("Playwright desktop and mobile review")); assert.ok(siteRebuildLog.includes("Homepage rebuild checks")); assert.ok(siteRebuildLog.includes("Design-system checks")); +assert.ok(siteRebuildLog.includes("package-default source metadata")); +assert.ok(siteRebuildLog.includes("complete external-source validation")); +assert.ok(siteRebuildLog.includes("retired public routes")); assert.ok(siteRebuildLog.includes("Browser checks")); assert.equal(siteRebuildLog.includes("judgmentkit2"), false); @@ -1558,6 +1096,24 @@ for (const copiedExamplePath of [ } } +for (const filePath of collectTextFiles(path.join(tempDir, "examples", "model-ui"))) { + const text = fs.readFileSync(filePath, "utf8"); + const relativePath = path.relative(tempDir, filePath); + + for (const forbiddenTerm of [ + "internal_fixture", + "JudgmentKit fixture", + "fixture://judgmentkit", + "fixture_design_system", + ]) { + assert.equal( + text.includes(forbiddenTerm), + false, + `built artifact ${relativePath} must not include retired design-system term ${forbiddenTerm}`, + ); + } +} + const install = fs.readFileSync(path.join(tempDir, "install"), "utf8"); assert.ok(install.startsWith("#!/usr/bin/env bash")); assert.ok(install.includes("node --input-type=module -")); diff --git a/tests/ui-generation-handoff.test.mjs b/tests/ui-generation-handoff.test.mjs index 00b4905..0c6daf5 100644 --- a/tests/ui-generation-handoff.test.mjs +++ b/tests/ui-generation-handoff.test.mjs @@ -99,7 +99,14 @@ function completeMaterialDesignSystemAdapter() { icon_count: 2000, license: "MIT", notice: "Repo-approved Material UI icon adapter.", + style_system: "Material Symbols-compatible outline icons", + style_attributes: { + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + }, mcp_tools: [], + default_include_svg: false, }, }, components: ["Stack", "Button", "Alert"], @@ -456,6 +463,26 @@ function refundOperatorImplementationCandidate(overrides = {}) { "judgmentkit_default", ); assertNoForbiddenHandoffKeys(handoff); + + const defaultHandoff = createUiGenerationHandoff(workflowReview); + assert.equal( + defaultHandoff.implementation_contract.design_system_source.mode, + "judgmentkit_default", + "Omitting implementation_contract should keep the JudgmentKit default design system working.", + ); + + assert.throws( + () => + createUiGenerationHandoff(workflowReview, { + implementation_contract: { + design_system_source: {}, + }, + }), + (error) => + error instanceof JudgmentKitInputError && + error.code === "invalid_design_system_source", + "Explicit malformed design_system_source must fail before handoff creation.", + ); } { @@ -815,8 +842,9 @@ function refundOperatorImplementationCandidate(overrides = {}) { }, design_system_provenance: { source: "judgmentkit_default", - token_source: "/design-system/visual-token-adapter.json", - icon_source: "get_icon_svg('check') from the JudgmentKit icon catalog", + token_source: + "package://judgmentkit/design-system/visual-token-adapter.json", + icon_source: "get_icon_svg('check') from the JudgmentKit default catalog", }, accessibility_evidence: { forced_colors: { diff --git a/vercel.json b/vercel.json index d1933d1..230d5ed 100644 --- a/vercel.json +++ b/vercel.json @@ -17,6 +17,10 @@ { "source": "/mcp", "destination": "/api/mcp" + }, + { + "source": "/design-system/(.*).json", + "destination": "/api/design-system-retired?requestedPath=/design-system/$1.json" } ], "redirects": [ @@ -63,6 +67,156 @@ ], "destination": "https://judgmentkit.ai/$1", "permanent": true + }, + { + "source": "/design-system", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/index.html", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/index.html.md", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/llms.txt", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/llms-full.txt", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/tokens", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/tokens/", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/tokens/index.html", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/tokens/index.html.md", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/fonts", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/fonts/", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/fonts/index.html", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/fonts/index.html.md", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/icons", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/icons/", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/icons/index.html", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/icons/index.html.md", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/components", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/components/", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/components/index.html", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/components/index.html.md", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/patterns", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/patterns/", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/patterns/index.html", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/patterns/index.html.md", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/accessibility", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/accessibility/", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/accessibility/index.html", + "destination": "https://surfaces.systems/design-system", + "permanent": true + }, + { + "source": "/design-system/accessibility/index.html.md", + "destination": "https://surfaces.systems/design-system", + "permanent": true } ] }