diff --git a/scripts/verify-public-release.mjs b/scripts/verify-public-release.mjs index 8345c7c..94b6924 100644 --- a/scripts/verify-public-release.mjs +++ b/scripts/verify-public-release.mjs @@ -1030,12 +1030,36 @@ export async function verifyDesignSystemSurfaceProfiles(baseUrl) { assert.equal(workbenchProfile.authority?.public_contract, true); assert.equal(workbenchProfile.authority?.runtime_renderer, false); + const artifactInspectorProfile = catalog.profiles.find( + (profile) => profile.id === "judgmentkit.artifact-inspector.v1", + ); + assert.ok( + artifactInspectorProfile, + "surface-presentation profile catalog should include the proposed Artifact Inspector profile", + ); + assert.equal(artifactInspectorProfile.status, "proposed"); + assert.equal(artifactInspectorProfile.surface_type, "artifact_inspector"); + assert.equal(artifactInspectorProfile.authority?.public_contract, true); + assert.equal(artifactInspectorProfile.authority?.runtime_renderer, false); + assert.equal( + artifactInspectorProfile.authority?.pattern_contract_id, + "artifact-inspector", + ); + assert.equal( + artifactInspectorProfile.provenance?.external_artifact_review_status, + "external_not_reviewed", + ); + return { checked: [manifestRoute, profileCatalogRoute], manifest_route: manifestRoute, catalog_route: profileCatalogRoute, profile_id: workbenchProfile.id, profile_status: workbenchProfile.status, + profiles: { + [workbenchProfile.id]: workbenchProfile.status, + [artifactInspectorProfile.id]: artifactInspectorProfile.status, + }, }; } @@ -1069,6 +1093,13 @@ async function verifyPublicRoutes(baseUrl, options = {}) { "Use JudgmentKit’s design system—or bring your own.", "A design system can make the wrong interface consistent.", "JudgmentKit prevents that mistake before the components are composed.", + "Artifact Inspector", + "Proposed", + "one rendered artifact stays primary", + "inspector chrome and inspection overlay", + "The artifact keeps its own visual language.", + 'href="/docs/#artifact-inspector"', + `href="https://github.com/mikeylong/judgmentkit/releases/tag/v${expectedPackageVersion}"`, "See a screen repaired", "Explore examples", '', @@ -1138,6 +1169,15 @@ async function verifyPublicRoutes(baseUrl, options = {}) { "create_frontend_implementation_skill_context", "create_slide_deck", "operator-review-ui", + "Artifact Inspector", + "Status: proposed", + "artifact-inspector-ui", + "judgmentkit.artifact-inspector.v1", + "review_required", + "external_not_reviewed", + "inspector chrome and inspection overlay", + "not the artifact itself", + `href="https://github.com/mikeylong/judgmentkit/releases/tag/v${expectedPackageVersion}"`, ], "docs", ); diff --git a/site/build-site.mjs b/site/build-site.mjs index 80e531d..2cc7bfd 100755 --- a/site/build-site.mjs +++ b/site/build-site.mjs @@ -25,6 +25,7 @@ import { listComponentImplementationRegistry, listIconCatalog, listSurfacePresentationProfiles, + loadActivityContract, searchIconCatalog, summarizeComponentReferenceCoverage, } from "../src/index.mjs"; @@ -39,6 +40,7 @@ const DEFAULT_OUT_DIR = path.join(__dirname, "dist"); const require = createRequire(import.meta.url); const ANALYTICS_SDK_VERSION = require("@vercel/analytics/package.json").version; const JUDGMENTKIT_PACKAGE_VERSION = require("../package.json").version; +const ACTIVITY_CONTRACT = loadActivityContract(); const SYSTEM_MAP_FLOW_ASSET_VERSION = "judgmentkit-flow-design-source-authority"; const COMPONENT_SPECIMEN_ASSET_VERSION = "judgmentkit-react-component-candidate-v1"; @@ -1944,6 +1946,7 @@ h2 { .homepage-preview, .homepage-category, .homepage-failure, +.homepage-artifact-inspector, .proof-paths, .adoption-paths { display: block; @@ -2041,6 +2044,7 @@ pre { } .homepage-category .homepage-section-shell > div:first-child, .homepage-failure .homepage-section-shell > div:first-child, +.homepage-artifact-inspector .homepage-section-shell > div:first-child, .proof-paths .homepage-section-shell > div:first-child, .adoption-paths .homepage-section-shell > div:first-child { max-width: 900px; @@ -2498,6 +2502,26 @@ pre { .doc-section { padding-bottom: 28px; } +.surface-type-list { + display: grid; + margin: 18px 0 0; + border-top: 1px solid var(--line); +} +.surface-type-entry { + display: grid; + grid-template-columns: minmax(150px, 0.32fr) minmax(0, 1fr); + gap: 18px; + padding: 13px 0; + border-bottom: 1px solid var(--line); +} +.surface-type-entry dt { + color: var(--accent-strong); + font-weight: 800; +} +.surface-type-entry dd { + margin: 0; + color: var(--muted); +} .docs-page { padding-top: var(--site-page-top); overflow-x: hidden; @@ -4680,6 +4704,10 @@ pre { .homepage-hero-art img { object-position: 50% 43%; } + .surface-type-entry { + grid-template-columns: minmax(0, 1fr); + gap: 5px; + } } @media (max-width: 767px) { .surfaces-navigation-inner { @@ -5001,6 +5029,33 @@ export function renderHomepage({ homepageFilmEnabled = HOMEPAGE_FILM_ENABLED } = +
+
+
+

Artifact Inspector · Proposed

+

Keep the artifact at the center of the review.

+

Artifact Inspector is for work where one rendered artifact stays primary and the person must act on a specific part of it.

+
+
+
+

Artifact first

+

People select the exact locus that matters. Evidence, actions, feedback, and results stay attached to that location.

+
+
+

Scoped chrome

+

JudgmentKit governs the inspector chrome and inspection overlay. The artifact keeps its own visual language.

+
+
+

Current boundary

+

Version ${escapeHtml(JUDGMENTKIT_PACKAGE_VERSION)} can guide the model, but it cannot yet verify the complete working interaction, so review remains required.

+
+
+ +
+
@@ -6129,7 +6184,7 @@ function buildDesignSystemContentModel() { title: "Patterns", href: "/design-system/patterns/", summary: - "Surface contracts for marketing, workbench, review, form, dashboard, report, setup, and conversation work.", + "Surface contracts for marketing, workbench, review, artifact inspection, form, dashboard, report, setup, and conversation work.", meta: `${patternContracts.length} patterns + specimens`, }, { @@ -7785,6 +7840,18 @@ async function valuePage() { ); } +function renderSurfaceTypeEntries() { + return Object.entries(ACTIVITY_CONTRACT.surface_types ?? {}) + .map( + ([surfaceTypeId, surfaceType]) => ` +
+
${escapeHtml(surfaceType.label)}
+
${escapeHtml(surfaceType.purpose)}
+
`, + ) + .join(""); +} + const DOCS_SECTION_ITEMS = [ { href: "#quickstart", label: "Quickstart", current: true, currentValue: "location" }, { href: "#first-use", label: "First 10 Minutes" }, @@ -7795,6 +7862,7 @@ const DOCS_SECTION_ITEMS = [ { href: "#workflow-review", label: "Workflow Review" }, { href: "#cognitive-dimensions", label: "Cognitive Dimensions" }, { href: "#surface-type", label: "Surface Type" }, + { href: "#artifact-inspector", label: "Artifact Inspector" }, { href: "#handoff", label: "Handoff" }, { href: "#implementation-contract", label: "Implementation Contract" }, { href: "#frontend-context", label: "Frontend Context" }, @@ -7870,7 +7938,7 @@ examples/ai-native-design-system/canonical-examples.json

MCP boundary: agents call JudgmentKit tools through MCP; MCP is access and transport, not the LLM.

JudgmentKit kernel: deterministic review, candidate review, disclosure rules, targeted questions, and the handoff gate decide whether UI generation is ready.

LLM / provider seam: a model may propose activity or workflow candidates, but JudgmentKit reviews those candidates before trusting them.

-

Surface type: recommend_surface_types classifies activity purpose as marketing, workbench, operator review, form flow, dashboard monitor, content/report, setup/debug tool, or conversation before frontend implementation guidance.

+

Surface type: recommend_surface_types classifies activity purpose as marketing, workbench, operator review, artifact inspection, form flow, dashboard monitoring, content/report, setup/debug work, or conversation before frontend implementation guidance.

UI generation: the LLM or agent generates the interface outside JudgmentKit from the reviewed handoff.

Implementation contract: create_ui_implementation_contract supplies implementation_contract.design_system_source, implementation_contract.local_component_authority, implementation_contract.visual_token_adapter, implementation_contract.default_ai_native_design_system, approved primitives, required states, static checks, browser QA expectations, implementation_contract.visual_asset_policy, and implementation_contract.accessibility_policy before final handoff. review_ui_implementation_candidate checks generated UI against that contract and marks failed design-system candidates as repair-only diagnostics, not accepted artifacts.

Frontend adapter: create_frontend_generation_context combines a ready handoff, selected surface type, project frontend context, and verification expectations. create_frontend_implementation_skill_context turns that ready context into portable implementation instructions, semantic token roles, system font stacks, Lucide icon catalog policy, design-system provenance expectations, and local component authority without exposing raw skill files. Design-system compliance is not a substitute for activity fit.

@@ -7894,6 +7962,31 @@ examples/ai-native-design-system/canonical-examples.json

Surface Type

Call recommend_surface_types after activity review and before workflow or frontend implementation guidance. Surface type is activity-purpose guidance, not a visual theme.

+
+ ${renderSurfaceTypeEntries()} +
+
+
+

Status: ${escapeHtml(ACTIVITY_CONTRACT.interaction_models.artifact_inspector.status)}

+

Artifact Inspector

+

Artifact Inspector is a proposed interaction model for work centered on one rendered artifact. Use it only when the artifact must remain visible and primary, the person must select a semantic locus within it, and supporting evidence, actions, or results are meaningful in relation to that locus.

+

Keep the existing surface type when a queue, case, collection, report, dashboard, form, setup flow, or conversation is primary. A live artifact keeps its native behavior until the person explicitly enters inspection mode.

+

Identifiers and current status

+
surface_type: artifact_inspector
+workflow_profile: artifact-inspector-ui
+frontend_surface_profile: judgmentkit.artifact-inspector.v1
+topology_kind: artifact_centered
+status: proposed
+implementation_review_status: review_required
+primary_artifact_review_status: external_not_reviewed
+

Authority boundary

+

JudgmentKit governs the inspector chrome and inspection overlay, not the artifact itself. The declared external authority owns the artifact’s typography, components, color, elevation, internal layout, semantics, and native interactions. Reviews report chrome, overlay, artifact preservation, and boundary behavior separately.

+

Current review boundary

+

JudgmentKit ${escapeHtml(JUDGMENTKIT_PACKAGE_VERSION)} can identify and validate the artifact-centered contract and carry it into generation guidance. It does not yet have a trusted interactive-attestation producer or verifier, so an otherwise valid implementation remains review_required.

+

Screenshots, static metadata, caller-authored evidence, or unchanged fingerprints cannot close that gate. Future acceptance must verify real pointer, touch, keyboard, and assistive-technology crossings; focus order and return; overlay obstruction and target drift; style isolation in both directions; artifact preservation; and required states across desktop and narrow viewports.

+

Handoff

@@ -7913,7 +8006,7 @@ examples/ai-native-design-system/canonical-examples.json

Guidance Profiles

-

Call recommend_ui_workflow_profiles when a brief sounds like specialized review work. Pass profile_id: "operator-review-ui" only when the recommendation evidence supports it.

+

Call recommend_ui_workflow_profiles when a brief sounds like specialized review work. Pass profile_id: "operator-review-ui" only when the recommendation evidence supports it. Artifact-centered work may use the proposed artifact-inspector-ui workflow profile with judgmentkit.artifact-inspector.v1; that profile guides generation but does not change its review_required status.

@@ -7921,7 +8014,7 @@ examples/ai-native-design-system/canonical-examples.json `, { description: - "JudgmentKit docs for CLI, MCP, activity review, workflow review, handoff, and guidance profiles.", + "JudgmentKit docs for CLI, MCP, activity review, workflow review, Artifact Inspector, handoff, and guidance profiles.", headExtra: systemMapFlowAssets(), path: "/docs/", }, diff --git a/tests/site-local-server.test.mjs b/tests/site-local-server.test.mjs index 6ad6c8a..03b6043 100644 --- a/tests/site-local-server.test.mjs +++ b/tests/site-local-server.test.mjs @@ -804,6 +804,10 @@ try { "/design-system/manifest.json", "/design-system/surface-presentation-profiles.json", ]); + assert.deepEqual(verification.profiles, { + "judgmentkit.workbench.operational-v1": "supported", + "judgmentkit.artifact-inspector.v1": "proposed", + }); assert.equal( verification.profile_id, "judgmentkit.workbench.operational-v1", diff --git a/tests/site.test.mjs b/tests/site.test.mjs index 54a95a2..f467eff 100644 --- a/tests/site.test.mjs +++ b/tests/site.test.mjs @@ -20,6 +20,7 @@ import { getHostedMcpMetadata } from "../src/mcp-http.mjs"; import { createUiImplementationContract, listSurfacePresentationProfiles, + loadActivityContract, } from "../src/index.mjs"; const EXPECTED_TOOL_NAMES = [ @@ -78,6 +79,7 @@ const PUBLIC_DIAGNOSTIC_CANDIDATE_KEYS = [ "use_case_label", ]; const root = path.resolve("."); +const activityContract = loadActivityContract(); const RAW_COLOR_VALUE_PATTERN = /#[0-9a-f]{3,8}\b|rgba?\(|hsla?\(|hwb\(|(?:ok)?lab\(|(?:ok)?lch\(|color\(|\b(?:white|black)\b/i; const APPEARANCE_INVARIANT_SITE_TOKENS = [ @@ -1737,6 +1739,32 @@ assert.ok(homepage.includes("The problem is not ugly UI. It is the wrong concept assert.ok(homepage.includes("Before judgment")); assert.ok(homepage.includes("With JudgmentKit")); assert.ok(homepage.includes("After repair")); +const homepageFailureIndex = homepage.indexOf('class="section homepage-failure"'); +const homepageArtifactInspectorIndex = homepage.indexOf( + 'class="section homepage-artifact-inspector"', +); +const homepageProofPathsIndex = homepage.indexOf('class="section proof-paths"'); +assert.ok( + homepageFailureIndex < homepageArtifactInspectorIndex && + homepageArtifactInspectorIndex < homepageProofPathsIndex, + "Artifact Inspector should follow failure recognition and precede proof paths", +); +const homepageArtifactInspector = homepage.slice( + homepageArtifactInspectorIndex, + homepageProofPathsIndex, +); +assert.ok(homepageArtifactInspector.includes("Artifact Inspector")); +assert.ok(homepageArtifactInspector.includes("Proposed")); +assert.ok(homepageArtifactInspector.includes("one rendered artifact stays primary")); +assert.ok(homepageArtifactInspector.includes("inspector chrome and inspection overlay")); +assert.ok(homepageArtifactInspector.includes("The artifact keeps its own visual language.")); +assert.ok(homepageArtifactInspector.includes("review remains required")); +assert.ok(homepageArtifactInspector.includes('href="/docs/#artifact-inspector"')); +assert.ok( + homepageArtifactInspector.includes( + `href="https://github.com/mikeylong/judgmentkit/releases/tag/v${packageJson.version}"`, + ), +); assert.ok(homepage.includes('class="section proof-paths" aria-labelledby="proof-paths-title"')); assert.ok(homepage.includes("Inspect the loop from product value to repeatable evidence.")); assert.ok(homepage.includes("What it prevents")); @@ -1961,6 +1989,61 @@ assert.ok(docs.includes("resolve targeted questions or leakage details before ge assert.ok(docs.includes("not the final UI renderer")); assert.equal(docs.includes("optional styling path"), false); assert.ok(docs.includes("operator-review-ui")); +assert.ok( + docs.includes( + 'Artifact Inspector', + ), +); +const surfaceTypeStart = docs.indexOf('
'); +const artifactInspectorStart = docs.indexOf( + '
', +); +const handoffStart = docs.indexOf('
'); +assert.ok(surfaceTypeStart > -1 && artifactInspectorStart > surfaceTypeStart); +assert.ok(handoffStart > artifactInspectorStart); +const surfaceTypeSection = docs.slice(surfaceTypeStart, artifactInspectorStart); +const documentedSurfaceTypeIds = [ + ...surfaceTypeSection.matchAll(/data-surface-type="([^"]+)"/g), +].map((match) => match[1]); +assert.deepEqual( + documentedSurfaceTypeIds, + Object.keys(activityContract.surface_types), + "docs should list every canonical surface type in contract order", +); +for (const [surfaceTypeId, surfaceType] of Object.entries( + activityContract.surface_types, +)) { + assert.ok( + surfaceTypeSection.includes( + `
`, + ), + ); + assert.ok(surfaceTypeSection.includes(`
${surfaceType.label}
`)); + assert.ok(surfaceTypeSection.includes(`
${surfaceType.purpose}
`)); +} +const artifactInspectorSection = docs.slice(artifactInspectorStart, handoffStart); +assert.ok(artifactInspectorSection.includes("Artifact Inspector")); +assert.ok(artifactInspectorSection.includes("Identifiers and current status")); +assert.ok( + artifactInspectorSection.includes( + `Status: ${activityContract.interaction_models.artifact_inspector.status}`, + ), +); +assert.ok(artifactInspectorSection.includes("judgmentkit.artifact-inspector.v1")); +assert.ok(artifactInspectorSection.includes("artifact-inspector-ui")); +assert.ok(artifactInspectorSection.includes("frontend_surface_profile")); +assert.ok(artifactInspectorSection.includes("topology_kind")); +assert.equal(artifactInspectorSection.includes("frontend_profile:"), false); +assert.equal(artifactInspectorSection.includes("surface_status:"), false); +assert.ok(artifactInspectorSection.includes("review_required")); +assert.ok(artifactInspectorSection.includes("external_not_reviewed")); +assert.ok(artifactInspectorSection.includes("inspector chrome and inspection overlay")); +assert.ok(artifactInspectorSection.includes("not the artifact itself")); +assert.ok( + artifactInspectorSection.includes( + `href="https://github.com/mikeylong/judgmentkit/releases/tag/v${packageJson.version}"`, + ), +); assert.equal(docs.includes("judgmentkit2"), false); const designSystem = fs.readFileSync(path.join(tempDir, "design-system", "index.html"), "utf8"); @@ -2403,6 +2486,11 @@ assert.ok( 'data-surface-presentation-profile="judgmentkit.workbench.operational-v1"', ), ); +assert.ok( + designSystemPatterns.includes( + 'data-surface-presentation-profile="judgmentkit.artifact-inspector.v1"', + ), +); assert.ok(designSystemPatterns.includes("Surface presentation profiles")); assert.ok(designSystemPatterns.includes('data-specimen-id="pattern.workbench"')); assert.ok(designSystemPatterns.includes('data-pattern-region="work-queue"'));