From fa489ccfe4d0ce9b85d191ede96613e367814d91 Mon Sep 17 00:00:00 2001 From: Mike Long Date: Sun, 30 Aug 2026 14:07:42 -0700 Subject: [PATCH 1/4] Add fail-closed Artifact Inspector contract --- DESIGN.md | 6 +- README.md | 8 +- .../ai-ui-generation.activity-contract.json | 536 +- contracts/judgmentkit-kernel.schema.json | 664 +++ docs/agent-usage-contract.md | 4 + package.json | 2 +- site/build-site.mjs | 16 +- specs/artifact-inspector.md | 901 +++ src/artifact-inspector-authority.mjs | 983 +++ src/index.mjs | 5265 +++++++++++++++-- src/mcp.mjs | 181 +- src/surface-presentation-profiles.mjs | 285 +- tests/artifact-inspector-authority.test.mjs | 1193 ++++ tests/artifact-inspector-routing.test.mjs | 505 ++ ...rtifact-inspector-surface-profile.test.mjs | 277 + tests/artifact-inspector-workflow.test.mjs | 2562 ++++++++ tests/kernel-contract.test.mjs | 6 +- tests/mcp.test.mjs | 46 + tests/site.test.mjs | 26 +- tests/workbench-surface-profile.test.mjs | 7 +- 20 files changed, 13039 insertions(+), 434 deletions(-) create mode 100644 specs/artifact-inspector.md create mode 100644 src/artifact-inspector-authority.mjs create mode 100644 tests/artifact-inspector-authority.test.mjs create mode 100644 tests/artifact-inspector-routing.test.mjs create mode 100644 tests/artifact-inspector-surface-profile.test.mjs create mode 100644 tests/artifact-inspector-workflow.test.mjs diff --git a/DESIGN.md b/DESIGN.md index 50a0b5c..9944f68 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -21,13 +21,15 @@ The interaction contract translates that activity into a surface: what the user ### Surface Type -The surface type classifies activity purpose before frontend implementation: marketing, workbench, operator review, form flow, dashboard monitor, content/report, setup/debug tool, or conversation. It is interaction guidance, not a visual theme. +The surface type classifies activity purpose before frontend implementation: marketing, workbench, operator review, artifact inspector, form flow, dashboard monitor, content/report, setup/debug tool, or conversation. It is interaction guidance, not a visual theme. Artifact Inspector applies only when one rendered artifact is primary, semantic locus selection is required, and supporting context is meaningful relative to that locus; layout vocabulary or a keyword alone is insufficient. ### Surface Presentation Profile A surface presentation profile applies governed design-system guidance after the surface type is grounded. It can shape density, type hierarchy, region hierarchy, action emphasis, status treatment, and responsive behavior without reclassifying the activity or replacing the interaction contract. -The JudgmentKit default design system selects `judgmentkit.workbench.operational-v1` automatically for a Workbench supplied by the caller or recommended with medium or high confidence. `surface_profile: "none"` opts out, while the exact profile id locks that supported version. The neutral low-confidence Workbench fallback selects no profile. External design systems receive no JudgmentKit profile fallback. +The JudgmentKit default design system selects `judgmentkit.workbench.operational-v1` automatically for a Workbench supplied by the caller or recommended with medium or high confidence. It selects `judgmentkit.artifact-inspector.v1` for a grounded Artifact Inspector. `surface_profile: "none"` opts out, while an exact profile id locks that version. The neutral low-confidence Workbench fallback selects no profile. External design systems receive no JudgmentKit profile fallback. + +Artifact Inspector has scoped visual authority rather than whole-surface JudgmentKit authority. JudgmentKit governs the inspector chrome and inspection overlay; the rendered artifact preserves its declared external authority. Reviews must report owned-scope, artifact-preservation, and boundary results separately and must not describe the external artifact as JudgmentKit-conformant. This contract release has no trusted interactive-attestation producer or verifier, so an otherwise valid implementation remains `review_required`. Profiles remain adapter-layer contracts. JudgmentKit may expose an optional component adapter downstream of the kernel, but a profile does not select it or turn it into kernel authority. Product vocabulary, product geometry, data, runtime state, authorization truth, and side effects stay with the implementing product. diff --git a/README.md b/README.md index 1e82099..b9c6176 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,11 @@ JudgmentKit keeps the core deterministic and lets model assistance enter through 2. Deterministic review packet: turns that evidence into a reviewable activity model candidate with guardrails. 3. Model-assisted candidate review seam: accepts a model-proposed candidate through dependency injection or MCP and runs the same guardrails. 4. Provider-neutral proposer adapter: builds a serializable activity-model request for an injected model caller and returns the proposed candidate to the review seam. -5. Surface-type recommendation: classifies activity purpose as marketing, workbench, operator review, form flow, dashboard monitor, content/report, setup/debug tool, or conversation before workflow or frontend implementation guidance. +5. Surface-type recommendation: classifies activity purpose as marketing, workbench, operator review, artifact inspector, form flow, dashboard monitor, content/report, setup/debug tool, or conversation before workflow or frontend implementation guidance. 6. UI workflow candidate review seam: accepts a model- or agent-proposed workflow candidate and checks grounding, action support, handoff clarity, and disclosure containment before UI implementation. 7. UI implementation contract gate: creates or accepts the repo authority for approved primitives, control semantics, required states, static checks, and browser QA. 8. UI generation handoff gate: turns only ready workflow reviews plus an implementation contract into compact handoffs for the next UI generation pass. -9. Frontend generation context adapter: combines a ready handoff, selected surface type, frontend context, and verification expectations, then applies supported presentation guidance such as the default Workbench operational profile without making styling or component inventory part of the kernel contract. +9. Frontend generation context adapter: combines a ready handoff, selected surface type, frontend context, and verification expectations, then applies governed presentation guidance such as the supported default Workbench operational profile or the proposed Artifact Inspector profile contract without making styling or component inventory part of the kernel contract. 10. Frontend implementation skill context: compiles repo-local frontend skill guidance into a gated MCP packet for agents that cannot read local skills directly, including the active `implementation_contract.design_system_source` for tokens, typography, icons, and component contracts. 11. Optional provider adapters: provider configuration and network calls stay outside the kernel and feed proposed candidates back through the same review contract. @@ -86,7 +86,9 @@ JudgmentKit also contains an unreleased optional React adapter candidate at `jud The Simple Design System (Community) file is JudgmentKit's component-and-variant reference denominator: 122 public families with 336 masters and six hidden families with 18 masters. Standalone icons and Simple Design System styling are excluded. JudgmentKit accounts for all 128 families and 354 masters, classifies every family, normalizes the 304 masters in documented variant sets across 105 semantic axes, and records the remaining 50 as singleton masters. Reference accounting, family disposition, variant semantics, runtime availability, and current evidence are reported separately. -By default, `implementation_contract.design_system_source.mode` is `judgmentkit_default`: tokens, font roles, icon catalog policy, component contracts, the component implementation registry, and supported surface-presentation profiles come from JudgmentKit `/design-system/` exports. A sufficiently grounded or explicitly selected Workbench receives `judgmentkit.workbench.operational-v1` in frontend-generation context by default; `surface_profile: "none"` opts out without changing the Workbench interaction contract. 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, and neither JudgmentKit surface profiles nor the unreleased React adapter candidate cross that boundary implicitly. +By default, `implementation_contract.design_system_source.mode` is `judgmentkit_default`: tokens, font roles, icon catalog policy, component contracts, the component implementation registry, and supported surface-presentation profiles come from JudgmentKit `/design-system/` exports. A sufficiently grounded or explicitly selected Workbench receives `judgmentkit.workbench.operational-v1` in frontend-generation context by default. A grounded Artifact Inspector receives `judgmentkit.artifact-inspector.v1`, which keeps one rendered artifact primary while applying JudgmentKit guidance only to declared chrome and overlay scopes. `surface_profile: "none"` opts out without changing either interaction contract. 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, and neither JudgmentKit surface profiles nor the unreleased React adapter candidate cross that boundary implicitly. + +Artifact Inspector uses an explicit mixed-authority contract: `inspector_chrome` and `inspection_overlay` are JudgmentKit-owned, while `primary_artifact` remains `external_not_reviewed`. Its profile component roles are semantic contract guidance, not implemented component-registry exports. This release has no trusted interactive-attestation producer or verifier; candidate-authored evidence and the existing static browser-composition runtime cannot satisfy the authority gate, so an otherwise valid implementation remains `review_required`. The default field-select composition contract is source-backed and documented in [`docs/select-field-composition.md`](https://github.com/mikeylong/judgmentkit/blob/main/docs/select-field-composition.md). It separates selected-value spacing, the reserved trailing indicator slot, and the indicator's placement inside that slot instead of treating a field's content padding as the chevron's physical edge inset. diff --git a/contracts/ai-ui-generation.activity-contract.json b/contracts/ai-ui-generation.activity-contract.json index 1c0557e..eaaf93f 100644 --- a/contracts/ai-ui-generation.activity-contract.json +++ b/contracts/ai-ui-generation.activity-contract.json @@ -26,7 +26,8 @@ "staged_flow", "dashboard", "report", - "conversation" + "conversation", + "artifact_centered" ], "preferred_default": "workspace", "work_units_guidance": [ @@ -59,6 +60,426 @@ } } }, + "interaction_models": { + "artifact_inspector": { + "id": "artifact_inspector", + "version": "1.0.0", + "status": "proposed", + "canonical_identifiers": { + "surface_type": "artifact_inspector", + "workflow_profile": "artifact-inspector-ui", + "frontend_surface_profile": "judgmentkit.artifact-inspector.v1", + "topology_kind": "artifact_centered" + }, + "recommendation_output": { + "profile_id": "artifact-inspector-ui", + "primary_structure": "persistent artifact, selectable loci, contextual support, local feedback, and artifact-local completion", + "density": "artifact-first contextual", + "navigation_shape": "artifact persistent; supporting context revealed from the active locus" + }, + "activity_evidence": { + "mandatory": [ + "rendered_artifact_is_primary", + "locus_selection_required", + "support_context_is_locus_relative" + ], + "positive": [ + "rendered_artifact_is_primary", + "locus_selection_required", + "support_context_is_locus_relative", + "completion_is_artifact_local", + "direct_or_spatial_interaction_required", + "external_artifact_visual_authority" + ], + "exclusions": [ + "queue_or_case_is_primary", + "many_items_are_primary", + "open_ended_creation_is_primary", + "conversation_turns_are_primary", + "linear_reading_is_completion", + "monitoring_is_completion", + "configuration_is_completion" + ] + }, + "topology": { + "kind": "artifact_centered", + "primary_object_id": "artifact", + "entry_work_unit_id": "orient", + "completion_work_unit_ids": [ + "verify_result", + "orient" + ], + "transitions": [ + { + "from": "orient", + "to": "select_locus" + }, + { + "from": "select_locus", + "to": "inspect_context" + }, + { + "from": "inspect_context", + "to": "preview" + }, + { + "from": "preview", + "to": "validate" + }, + { + "from": "validate", + "to": "complete", + "when": "supported" + }, + { + "from": "validate", + "to": "recover", + "when": "invalid_or_ambiguous" + }, + { + "from": "recover", + "to": "inspect_context", + "when": "retry_or_reconcile" + }, + { + "from": "complete", + "to": "verify_result" + }, + { + "from": "select_locus", + "to": "orient", + "when": "back" + } + ] + }, + "work_units": [ + { + "id": "orient", + "participant_intent": "Understand the artifact's current state.", + "system_responsibility": "Keep the artifact dominant and expose only essential status." + }, + { + "id": "select_locus", + "participant_intent": "Identify the part that matters.", + "system_responsibility": "Provide a visible selected state and equivalent pointer, touch, and keyboard paths." + }, + { + "id": "inspect_context", + "participant_intent": "Understand what supports or constrains the locus.", + "system_responsibility": "Reveal context progressively and keep its relation to the locus visible." + }, + { + "id": "preview", + "participant_intent": "Test a relation or action before commitment.", + "system_responsibility": "Distinguish provisional state from committed state." + }, + { + "id": "validate", + "participant_intent": "Know whether the relation or action is supported.", + "system_responsibility": "Explain valid, invalid, unavailable, stale, and ambiguous conditions locally." + }, + { + "id": "complete", + "participant_intent": "Finish the bounded task or enter an explicit commitment boundary.", + "system_responsibility": "Change only the state authorized by the activity contract." + }, + { + "id": "verify_result", + "participant_intent": "Confirm what changed.", + "system_responsibility": "Attach a stable result or receipt to the artifact when required." + }, + { + "id": "recover", + "participant_intent": "Cancel, go back, retry, or reconcile.", + "system_responsibility": "Reverse only uncommitted state and preserve committed results." + } + ], + "target_model": { + "target_kinds": [ + "whole_artifact", + "element", + "text_range", + "region", + "point" + ], + "target_identity_sources": [ + "artifact_supplied", + "participant_selection" + ], + "geometry_policy": "Geometry is read-only and stable for the current artifact revision; changed geometry must re-anchor to the same semantic target or become stale.", + "label_sources": [ + "artifact_supplied", + "artifact_authorized_proxy", + "Unavailable" + ], + "artifact_interactivity": [ + "static", + "live", + "hybrid" + ], + "native_interaction_precedence": "Live and hybrid artifacts retain native interaction precedence until explicit inspection mode, a declared inspection handle, or a declared keyboard command is active." + }, + "composition_variants": [ + { + "id": "peripheral_anchors", + "use_when": "A small stable set of support objects must remain visible around the artifact." + }, + { + "id": "contextual_tray", + "use_when": "Support objects are numerous, conditional, or need a narrow-viewport home." + }, + { + "id": "inline_annotation", + "use_when": "Short context can remain beside a locus without obscuring it." + }, + { + "id": "inspection_lens", + "use_when": "Temporary magnification or focused context is necessary to understand a dense locus." + }, + { + "id": "responsive_hybrid", + "use_when": "Wide and narrow viewports need different placement while preserving identical states and actions." + } + ], + "state_groups": { + "core": [ + "artifact loading", + "artifact ready", + "artifact unavailable or failed", + "no active locus", + "locus focused or selected", + "context loading", + "context ready", + "relation or action preview", + "supported", + "incompatible", + "unavailable", + "stale", + "ambiguous", + "blocked", + "cancelled or Back", + "local error and retry" + ], + "consequential": [ + "no option preselected", + "outcome pending", + "committing", + "commit succeeded", + "known failure", + "unknown result", + "receipt reconciliation", + "immutable receipt", + "concurrent result", + "superseding action when reversal is allowed" + ], + "reusable_guidance": [ + "inactive draft after the current result exists", + "correcting", + "explicit confirmation with no default affirmative", + "accepting", + "accepted version", + "declined or Back with no active guidance", + "acceptance failure", + "conflict", + "supersession", + "revocation" + ], + "automation": [ + "match preflight", + "exact match", + "near or partial match", + "automatic resolution pending", + "automatic resolution complete", + "inline causal receipt", + "changed authority or evidence", + "failed or uncertain automation", + "exception returned to human review" + ] + }, + "design_system": { + "scopes": [ + { + "scope_id": "inspector_chrome", + "root_selector": "[data-jk-scope='inspector-chrome']", + "authority": "judgmentkit_default", + "enforcement": "required", + "style_isolation": "required" + }, + { + "scope_id": "inspection_overlay", + "root_selector": "[data-jk-scope='inspection-overlay']", + "authority": "judgmentkit_default", + "enforcement": "required", + "style_isolation": "required" + }, + { + "scope_id": "primary_artifact", + "root_selector": "[data-artifact-root]", + "authority": "external_declared", + "enforcement": "external_not_reviewed", + "style_isolation": "required" + } + ], + "boundary_contracts": [ + { + "from_scope": "inspection_overlay", + "to_scope": "primary_artifact", + "allowed_roles": [ + "locus_target", + "annotation_overlay", + "connector_endpoint" + ], + "event_contract_required": true + } + ], + "component_roles": [ + "ArtifactViewport", + "ArtifactBoundary", + "ArtifactStatus", + "ObservationMarker", + "LocusSelection", + "ContextAnchor", + "AuthorityAnchor", + "AnchorRail", + "RelationPreview", + "RelationConnector", + "InlineReason", + "ContextTray", + "CommitBoundary", + "ReceiptMarker", + "BackAction", + "ResetAction", + "ZoomAndPanControls" + ] + }, + "diagnostics": [ + { + "code": "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + "meaning": "No bounded rendered artifact is declared." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING", + "meaning": "The participant cannot select a semantic artifact locus." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_TOPOLOGY_CONTRACT_MISSING", + "meaning": "The artifact-centered workflow has no explicit structured topology contract." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_TOPOLOGY_KIND_INVALID", + "meaning": "The artifact-centered workflow declares an invalid topology kind." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_WORK_UNIT_ID_MISSING", + "meaning": "A structured artifact work unit has no stable identifier." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + "meaning": "A required artifact work unit is duplicated or does not preserve its canonical intent and system responsibility." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_ENTRY_REFERENCE_INVALID", + "meaning": "The topology entry does not reference a declared work unit." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID", + "meaning": "Artifact-local completion does not reference declared work units." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_TRANSITION_REFERENCE_INVALID", + "meaning": "A topology transition does not connect declared work units." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_RECOVERY_PATH_MISSING", + "meaning": "The artifact workflow has no explicit connected recovery work unit." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + "meaning": "The artifact workflow does not declare the canonical active state groups." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_ARTIFACT_NOT_DOMINANT", + "meaning": "Persistent chrome or supporting context visually displaces the artifact." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_CONTEXT_DETACHED", + "meaning": "Evidence, authority, action, or feedback has no visible or semantic relation to the active locus." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_DRAG_ONLY", + "meaning": "A required interaction has no tap, select, and keyboard alternative." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_LOCAL_FEEDBACK_MISSING", + "meaning": "Validation or status appears away from the action that caused it." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_UNCOMMITTED_STATE_AMBIGUOUS", + "meaning": "Preview and committed state are not distinguishable." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_DEFAULT_COMMIT", + "meaning": "A consequential affirmative or outcome is preselected." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_RECEIPT_MISSING", + "meaning": "A consequential result has no inspectable local receipt." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_GUIDANCE_COUPLED", + "meaning": "Current-item commitment and reusable-guidance acceptance occur in one action." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_MOBILE_ARTIFACT_OBSCURED", + "meaning": "Narrow-layout chrome covers the active locus or essential artifact content." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_CHROME_SCOPE_MISSING", + "meaning": "JudgmentKit-owned chrome has no enforceable design-system scope." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_ARTIFACT_SCOPE_MISSING", + "meaning": "The artifact's visual authority is undeclared." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_SCOPE_OVERLAP", + "meaning": "Two authority scopes claim the same visible node without a valid overlay exception." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_STYLE_LEAK", + "meaning": "Styles or tokens cross an authority boundary." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED", + "meaning": "Chrome interacts with an artifact locus without a semantic boundary contract." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_NATIVE_ACTION_INTERCEPTED", + "meaning": "Inspector behavior captures a live artifact action without explicit inspection mode." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_TARGET_DRIFT", + "meaning": "An overlay silently moved to a different artifact target." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_ARTIFACT_MUTATED", + "meaning": "A chrome transition changed artifact content or presentation." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_EXTERNAL_AUTHORITY_OVERCLAIM", + "meaning": "The review describes the external artifact as JudgmentKit-conformant." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_KEYWORD_ROUTING_CONFLICT", + "meaning": "Artifact Inspector routing conflicts with mandatory activity evidence, exclusions, the selected surface, or the workflow profile." + }, + { + "code": "JK_ARTIFACT_INSPECTOR_TRUSTED_RUNTIME_EVIDENCE_MISSING", + "meaning": "The deferred trusted interactive attestation required for Artifact Inspector acceptance is unavailable in this release." + } + ] + } + }, "profiles": { "operator-review-ui": { "pattern_id": "operator-review", @@ -129,6 +550,58 @@ "Selected or focused list item where state must remain visible but restrained.", "False-positive case: simple dashboard or form that should not invoke operator-review." ] + }, + "artifact-inspector-ui": { + "pattern_id": "artifact-inspector", + "applies_when_most_true": [ + "One bounded rendered artifact is the primary work object.", + "The participant must select a semantic locus within the artifact.", + "Supporting context is meaningful only in relation to the active locus.", + "Completion is visible on or directly beside the artifact." + ], + "do_not_use_when": [ + "The participant is primarily creating or freely editing the artifact.", + "A queue, case list, record set, or many-item comparison is primary.", + "The work can be completed without seeing or selecting an artifact locus.", + "Conversation turns, linear reading, monitoring, or configuration are the primary activity." + ], + "guardrails": [ + { + "id": "guardrail.artifact-dominance", + "guidance": "Keep the artifact as the largest and most persistent region." + }, + { + "id": "guardrail.locus-relative-context", + "guidance": "Keep evidence, authority, actions, feedback, and receipts visibly or semantically attached to the active locus." + }, + { + "id": "guardrail.native-interaction-precedence", + "guidance": "Do not intercept a live artifact's native action without explicit inspection mode." + }, + { + "id": "guardrail.scoped-visual-authority", + "guidance": "Apply JudgmentKit authority to inspector chrome and overlay without claiming authority over the external artifact." + }, + { + "id": "guardrail.local-recovery", + "guidance": "Back and cancellation reverse only uncommitted state and preserve committed receipts." + } + ], + "review_criteria": [ + "The artifact remains primary at wide and narrow viewports.", + "Pointer, touch, and keyboard paths express the same state machine.", + "Preview, commitment, result, and recovery states are distinguishable.", + "Chrome, overlay, external artifact, and boundary results are reported separately.", + "Acceptance remains review_required until a separately released trusted interactive attestation proves isolation and artifact preservation." + ], + "test_scenarios": [ + "Rendered interface with a locus-related observation and accepted authority.", + "Document passage with a source-backed correction.", + "Diagram node with rule and evidence context.", + "Externally styled artifact with isolated JudgmentKit chrome and overlay.", + "Narrow layout retaining the artifact, locus, feedback, and recovery action.", + "False-positive queue, conversation, report, form, dashboard, and creation-canvas cases." + ] } }, "surface_types": { @@ -174,6 +647,20 @@ "Raw system mechanics are the primary task rather than diagnostic context." ] }, + "artifact_inspector": { + "label": "Artifact inspector", + "purpose": "Inspect one rendered artifact in place, act on a semantic locus, and leave an explicit artifact-local result.", + "applies_when_most_true": [ + "One bounded rendered artifact remains visible and primary throughout the work.", + "The participant must select a locus within the artifact to complete the work.", + "Supporting evidence, authority, actions, and results are meaningful only in relation to that locus." + ], + "do_not_use_when": [ + "The participant is primarily creating or freely editing the artifact.", + "A queue, case, many-item comparison, conversation, report, dashboard, form, or setup flow is primary.", + "The work can be completed without seeing or selecting anything on the artifact." + ] + }, "form_flow": { "label": "Form flow", "purpose": "Collect or change structured information with validation.", @@ -1280,12 +1767,12 @@ ], "failure_signals": [ "spinner has no status text", - "success state lacks receipt or next action" - ] - } - ], - "pattern_contracts": [ - { + "success state lacks receipt or next action" + ] + } + ], + "pattern_contracts": [ + { "id": "marketing", "label": "Marketing surface", "surface_type": "marketing", @@ -1369,6 +1856,41 @@ "risky action has no approval boundary" ] }, + { + "id": "artifact-inspector", + "label": "Artifact inspector", + "surface_type": "artifact_inspector", + "purpose": "Help a participant orient to a rendered artifact, select a locus, inspect locus-relative context, and complete or verify artifact-local work", + "required_regions": [ + "persistent rendered artifact", + "selectable artifact loci", + "locus-relative context", + "artifact-local feedback", + "artifact-local completion or recovery" + ], + "expected_controls": [ + "locus selection", + "context disclosure", + "preview and validation", + "Back or reset", + "commit and receipt when consequential" + ], + "completion_or_handoff": "participant verifies the result on or immediately beside the artifact locus", + "disclosure_boundary": "the primary artifact remains externally owned while JudgmentKit chrome and overlays use domain language and keep implementation machinery diagnostic-only", + "accessibility_expectations": [ + "loci have stable keyboard-reachable identities", + "artifact-to-context relationships have non-spatial descriptions", + "focus returns to the active locus after contextual work", + "zoom does not require precise pointing or separate feedback from its locus" + ], + "failure_signals": [ + "artifact is secondary to generic panels", + "context is detached from its locus", + "overlay styling leaks into the artifact", + "the external artifact is described as JudgmentKit-conformant", + "native artifact interaction is blocked by an overlay" + ] + }, { "id": "form_flow", "label": "Form flow", diff --git a/contracts/judgmentkit-kernel.schema.json b/contracts/judgmentkit-kernel.schema.json index 5bdb832..ac479c0 100644 --- a/contracts/judgmentkit-kernel.schema.json +++ b/contracts/judgmentkit-kernel.schema.json @@ -8,6 +8,7 @@ "version", "source_model", "quality_order", + "interaction_models", "surface_types", "activity_model", "interaction_contract", @@ -104,6 +105,9 @@ } } }, + "interaction_models": { + "$ref": "#/$defs/interactionModels" + }, "profiles": { "type": "object", "additionalProperties": false, @@ -138,6 +142,9 @@ "review_criteria": { "type": "array", "items": { "type": "string" } }, "test_scenarios": { "type": "array", "items": { "type": "string" } } } + }, + "artifact-inspector-ui": { + "$ref": "#/$defs/artifactInspectorWorkflowProfile" } } }, @@ -148,6 +155,7 @@ "marketing", "workbench", "operator_review", + "artifact_inspector", "form_flow", "dashboard_monitor", "content_report", @@ -158,6 +166,7 @@ "marketing": { "$ref": "#/$defs/surfaceType" }, "workbench": { "$ref": "#/$defs/surfaceType" }, "operator_review": { "$ref": "#/$defs/surfaceType" }, + "artifact_inspector": { "$ref": "#/$defs/surfaceType" }, "form_flow": { "$ref": "#/$defs/surfaceType" }, "dashboard_monitor": { "$ref": "#/$defs/surfaceType" }, "content_report": { "$ref": "#/$defs/surfaceType" }, @@ -296,6 +305,628 @@ "do_not_use_when": { "type": "array", "items": { "type": "string" } } } }, + "nonEmptyStringSet": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "type": "string", "minLength": 1 } + }, + "workflowGuardrail": { + "type": "object", + "additionalProperties": false, + "required": ["id", "guidance"], + "properties": { + "id": { "type": "string", "minLength": 1 }, + "guidance": { "type": "string", "minLength": 1 } + } + }, + "artifactInspectorWorkflowProfile": { + "type": "object", + "additionalProperties": false, + "required": [ + "pattern_id", + "applies_when_most_true", + "do_not_use_when", + "guardrails", + "review_criteria", + "test_scenarios" + ], + "properties": { + "pattern_id": { "const": "artifact-inspector" }, + "applies_when_most_true": { "$ref": "#/$defs/nonEmptyStringSet" }, + "do_not_use_when": { "$ref": "#/$defs/nonEmptyStringSet" }, + "guardrails": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "$ref": "#/$defs/workflowGuardrail" } + }, + "review_criteria": { "$ref": "#/$defs/nonEmptyStringSet" }, + "test_scenarios": { "$ref": "#/$defs/nonEmptyStringSet" } + } + }, + "artifactInspectorCanonicalIdentifiers": { + "type": "object", + "additionalProperties": false, + "required": [ + "surface_type", + "workflow_profile", + "frontend_surface_profile", + "topology_kind" + ], + "properties": { + "surface_type": { "const": "artifact_inspector" }, + "workflow_profile": { "const": "artifact-inspector-ui" }, + "frontend_surface_profile": { "const": "judgmentkit.artifact-inspector.v1" }, + "topology_kind": { "const": "artifact_centered" } + } + }, + "artifactInspectorActivityEvidence": { + "type": "object", + "additionalProperties": false, + "required": ["mandatory", "positive", "exclusions"], + "properties": { + "mandatory": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "uniqueItems": true, + "items": { + "enum": [ + "rendered_artifact_is_primary", + "locus_selection_required", + "support_context_is_locus_relative" + ] + } + }, + "positive": { + "type": "array", + "minItems": 6, + "maxItems": 6, + "uniqueItems": true, + "items": { + "enum": [ + "rendered_artifact_is_primary", + "locus_selection_required", + "support_context_is_locus_relative", + "completion_is_artifact_local", + "direct_or_spatial_interaction_required", + "external_artifact_visual_authority" + ] + } + }, + "exclusions": { + "type": "array", + "minItems": 7, + "maxItems": 7, + "uniqueItems": true, + "items": { + "enum": [ + "queue_or_case_is_primary", + "many_items_are_primary", + "open_ended_creation_is_primary", + "conversation_turns_are_primary", + "linear_reading_is_completion", + "monitoring_is_completion", + "configuration_is_completion" + ] + } + } + } + }, + "artifactInspectorTransition": { + "type": "object", + "additionalProperties": false, + "required": ["from", "to"], + "properties": { + "from": { + "enum": [ + "orient", + "select_locus", + "inspect_context", + "preview", + "validate", + "complete", + "verify_result", + "recover" + ] + }, + "to": { + "enum": [ + "orient", + "select_locus", + "inspect_context", + "preview", + "validate", + "complete", + "verify_result", + "recover" + ] + }, + "when": { "type": "string", "minLength": 1 } + } + }, + "artifactInspectorTopology": { + "type": "object", + "additionalProperties": false, + "required": [ + "kind", + "primary_object_id", + "entry_work_unit_id", + "completion_work_unit_ids", + "transitions" + ], + "properties": { + "kind": { "const": "artifact_centered" }, + "primary_object_id": { "const": "artifact" }, + "entry_work_unit_id": { "const": "orient" }, + "completion_work_unit_ids": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "uniqueItems": true, + "items": { "enum": ["verify_result", "orient"] } + }, + "transitions": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "$ref": "#/$defs/artifactInspectorTransition" }, + "allOf": [ + { + "contains": { + "type": "object", + "properties": { "to": { "const": "recover" } }, + "required": ["to"] + } + }, + { + "contains": { + "type": "object", + "properties": { "from": { "const": "recover" } }, + "required": ["from"] + } + } + ] + } + } + }, + "artifactInspectorWorkUnit": { + "type": "object", + "additionalProperties": false, + "required": ["id", "participant_intent", "system_responsibility"], + "properties": { + "id": { + "enum": [ + "orient", + "select_locus", + "inspect_context", + "preview", + "validate", + "complete", + "verify_result", + "recover" + ] + }, + "participant_intent": { "type": "string", "minLength": 1 }, + "system_responsibility": { "type": "string", "minLength": 1 } + } + }, + "artifactInspectorTargetModel": { + "type": "object", + "additionalProperties": false, + "required": [ + "target_kinds", + "target_identity_sources", + "geometry_policy", + "label_sources", + "artifact_interactivity", + "native_interaction_precedence" + ], + "properties": { + "target_kinds": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "uniqueItems": true, + "items": { "enum": ["whole_artifact", "element", "text_range", "region", "point"] } + }, + "target_identity_sources": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "uniqueItems": true, + "items": { "enum": ["artifact_supplied", "participant_selection"] } + }, + "geometry_policy": { "type": "string", "minLength": 1 }, + "label_sources": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "uniqueItems": true, + "items": { "enum": ["artifact_supplied", "artifact_authorized_proxy", "Unavailable"] } + }, + "artifact_interactivity": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "uniqueItems": true, + "items": { "enum": ["static", "live", "hybrid"] } + }, + "native_interaction_precedence": { "type": "string", "minLength": 1 } + } + }, + "artifactInspectorCompositionVariant": { + "type": "object", + "additionalProperties": false, + "required": ["id", "use_when"], + "properties": { + "id": { + "enum": [ + "peripheral_anchors", + "contextual_tray", + "inline_annotation", + "inspection_lens", + "responsive_hybrid" + ] + }, + "use_when": { "type": "string", "minLength": 1 } + } + }, + "artifactInspectorStateGroups": { + "type": "object", + "additionalProperties": false, + "required": ["core", "consequential", "reusable_guidance", "automation"], + "properties": { + "core": { "$ref": "#/$defs/nonEmptyStringSet" }, + "consequential": { "$ref": "#/$defs/nonEmptyStringSet" }, + "reusable_guidance": { "$ref": "#/$defs/nonEmptyStringSet" }, + "automation": { "$ref": "#/$defs/nonEmptyStringSet" } + } + }, + "designSystemScope": { + "type": "object", + "additionalProperties": false, + "required": ["scope_id", "root_selector", "authority", "enforcement", "style_isolation"], + "properties": { + "scope_id": { + "enum": ["inspector_chrome", "inspection_overlay", "primary_artifact"] + }, + "root_selector": { "type": "string", "minLength": 1 }, + "authority": { + "enum": ["judgmentkit_default", "external_declared"] + }, + "enforcement": { + "enum": ["required", "external_not_reviewed"] + }, + "style_isolation": { "const": "required" } + }, + "allOf": [ + { + "if": { + "properties": { "scope_id": { "const": "inspector_chrome" } }, + "required": ["scope_id"] + }, + "then": { + "properties": { + "root_selector": { "const": "[data-jk-scope='inspector-chrome']" }, + "authority": { "const": "judgmentkit_default" }, + "enforcement": { "const": "required" } + } + } + }, + { + "if": { + "properties": { "scope_id": { "const": "inspection_overlay" } }, + "required": ["scope_id"] + }, + "then": { + "properties": { + "root_selector": { "const": "[data-jk-scope='inspection-overlay']" }, + "authority": { "const": "judgmentkit_default" }, + "enforcement": { "const": "required" } + } + } + }, + { + "if": { + "properties": { "scope_id": { "const": "primary_artifact" } }, + "required": ["scope_id"] + }, + "then": { + "properties": { + "root_selector": { "const": "[data-artifact-root]" }, + "authority": { "const": "external_declared" }, + "enforcement": { "const": "external_not_reviewed" } + } + } + }, + { + "if": { + "properties": { "authority": { "const": "judgmentkit_default" } }, + "required": ["authority"] + }, + "then": { "properties": { "enforcement": { "const": "required" } } } + }, + { + "if": { + "properties": { "authority": { "const": "external_declared" } }, + "required": ["authority"] + }, + "then": { "properties": { "enforcement": { "const": "external_not_reviewed" } } } + } + ] + }, + "artifactInspectorScopeSet": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "uniqueItems": true, + "items": { "$ref": "#/$defs/designSystemScope" }, + "allOf": [ + { "contains": { "type": "object", "properties": { "scope_id": { "const": "inspector_chrome" } }, "required": ["scope_id"] } }, + { "contains": { "type": "object", "properties": { "scope_id": { "const": "inspection_overlay" } }, "required": ["scope_id"] } }, + { "contains": { "type": "object", "properties": { "scope_id": { "const": "primary_artifact" } }, "required": ["scope_id"] } } + ] + }, + "boundaryContract": { + "type": "object", + "additionalProperties": false, + "required": ["from_scope", "to_scope", "allowed_roles", "event_contract_required"], + "properties": { + "from_scope": { "const": "inspection_overlay" }, + "to_scope": { "const": "primary_artifact" }, + "allowed_roles": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "uniqueItems": true, + "items": { "enum": ["locus_target", "annotation_overlay", "connector_endpoint"] } + }, + "event_contract_required": { "const": true } + } + }, + "artifactInspectorDesignSystemRegistry": { + "type": "object", + "additionalProperties": false, + "required": ["scopes", "boundary_contracts", "component_roles"], + "properties": { + "scopes": { "$ref": "#/$defs/artifactInspectorScopeSet" }, + "boundary_contracts": { + "type": "array", + "minItems": 1, + "maxItems": 1, + "uniqueItems": true, + "items": { "$ref": "#/$defs/boundaryContract" } + }, + "component_roles": { + "type": "array", + "minItems": 17, + "maxItems": 17, + "uniqueItems": true, + "items": { + "enum": [ + "ArtifactViewport", + "ArtifactBoundary", + "ArtifactStatus", + "ObservationMarker", + "LocusSelection", + "ContextAnchor", + "AuthorityAnchor", + "AnchorRail", + "RelationPreview", + "RelationConnector", + "InlineReason", + "ContextTray", + "CommitBoundary", + "ReceiptMarker", + "BackAction", + "ResetAction", + "ZoomAndPanControls" + ] + } + } + } + }, + "artifactInspectorDiagnostic": { + "type": "object", + "additionalProperties": false, + "required": ["code", "meaning"], + "properties": { + "code": { + "type": "string", + "pattern": "^JK_ARTIFACT_INSPECTOR_[A-Z0-9_]+$" + }, + "meaning": { "type": "string", "minLength": 1 } + } + }, + "artifactInspectorRecommendationOutput": { + "type": "object", + "additionalProperties": false, + "required": [ + "profile_id", + "primary_structure", + "density", + "navigation_shape" + ], + "properties": { + "profile_id": { "const": "artifact-inspector-ui" }, + "primary_structure": { + "const": "persistent artifact, selectable loci, contextual support, local feedback, and artifact-local completion" + }, + "density": { "const": "artifact-first contextual" }, + "navigation_shape": { + "const": "artifact persistent; supporting context revealed from the active locus" + } + } + }, + "artifactInspectorRegistry": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "version", + "status", + "canonical_identifiers", + "recommendation_output", + "activity_evidence", + "topology", + "work_units", + "target_model", + "composition_variants", + "state_groups", + "design_system", + "diagnostics" + ], + "properties": { + "id": { "const": "artifact_inspector" }, + "version": { "const": "1.0.0" }, + "status": { "const": "proposed" }, + "canonical_identifiers": { "$ref": "#/$defs/artifactInspectorCanonicalIdentifiers" }, + "recommendation_output": { "$ref": "#/$defs/artifactInspectorRecommendationOutput" }, + "activity_evidence": { "$ref": "#/$defs/artifactInspectorActivityEvidence" }, + "topology": { "$ref": "#/$defs/artifactInspectorTopology" }, + "work_units": { + "type": "array", + "minItems": 8, + "maxItems": 8, + "uniqueItems": true, + "items": { "$ref": "#/$defs/artifactInspectorWorkUnit" }, + "allOf": [ + { + "contains": { + "type": "object", + "required": ["id"], + "properties": { "id": { "const": "orient" } } + }, + "minContains": 1, + "maxContains": 1 + }, + { + "contains": { + "type": "object", + "required": ["id"], + "properties": { "id": { "const": "select_locus" } } + }, + "minContains": 1, + "maxContains": 1 + }, + { + "contains": { + "type": "object", + "required": ["id"], + "properties": { "id": { "const": "inspect_context" } } + }, + "minContains": 1, + "maxContains": 1 + }, + { + "contains": { + "type": "object", + "required": ["id"], + "properties": { "id": { "const": "preview" } } + }, + "minContains": 1, + "maxContains": 1 + }, + { + "contains": { + "type": "object", + "required": ["id"], + "properties": { "id": { "const": "validate" } } + }, + "minContains": 1, + "maxContains": 1 + }, + { + "contains": { + "type": "object", + "required": ["id"], + "properties": { "id": { "const": "complete" } } + }, + "minContains": 1, + "maxContains": 1 + }, + { + "contains": { + "type": "object", + "required": ["id"], + "properties": { "id": { "const": "verify_result" } } + }, + "minContains": 1, + "maxContains": 1 + }, + { + "contains": { + "type": "object", + "required": ["id"], + "properties": { "id": { "const": "recover" } } + }, + "minContains": 1, + "maxContains": 1 + } + ] + }, + "target_model": { "$ref": "#/$defs/artifactInspectorTargetModel" }, + "composition_variants": { + "type": "array", + "minItems": 5, + "maxItems": 5, + "uniqueItems": true, + "items": { "$ref": "#/$defs/artifactInspectorCompositionVariant" } + }, + "state_groups": { "$ref": "#/$defs/artifactInspectorStateGroups" }, + "design_system": { "$ref": "#/$defs/artifactInspectorDesignSystemRegistry" }, + "diagnostics": { + "type": "array", + "minItems": 29, + "uniqueItems": true, + "items": { "$ref": "#/$defs/artifactInspectorDiagnostic" } + } + } + }, + "interactionModels": { + "type": "object", + "additionalProperties": false, + "required": ["artifact_inspector"], + "properties": { + "artifact_inspector": { "$ref": "#/$defs/artifactInspectorRegistry" } + } + }, + "artifactInspectorImplementationContract": { + "type": "object", + "additionalProperties": false, + "required": [ + "registry_id", + "registry_version", + "surface_type", + "workflow_profile", + "frontend_surface_profile", + "topology_kind", + "active_state_groups", + "state_groups", + "trusted_runtime_evidence_required", + "external_artifact_review_status" + ], + "properties": { + "registry_id": { "const": "artifact_inspector" }, + "registry_version": { "const": "1.0.0" }, + "surface_type": { "const": "artifact_inspector" }, + "workflow_profile": { "const": "artifact-inspector-ui" }, + "frontend_surface_profile": { "const": "judgmentkit.artifact-inspector.v1" }, + "topology_kind": { "const": "artifact_centered" }, + "active_state_groups": { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { "enum": ["core", "consequential", "reusable_guidance", "automation"] }, + "contains": { "const": "core" } + }, + "state_groups": { "$ref": "#/$defs/artifactInspectorStateGroups" }, + "trusted_runtime_evidence_required": { "const": true }, + "external_artifact_review_status": { "const": "external_not_reviewed" } + } + }, "visualTokenRole": { "type": "object", "additionalProperties": false, @@ -1201,6 +1832,15 @@ } }, "design_system_source": { "$ref": "#/$defs/designSystemSource" }, + "design_system_scopes": { "$ref": "#/$defs/artifactInspectorScopeSet" }, + "boundary_contracts": { + "type": "array", + "minItems": 1, + "maxItems": 1, + "uniqueItems": true, + "items": { "$ref": "#/$defs/boundaryContract" } + }, + "artifact_inspector": { "$ref": "#/$defs/artifactInspectorImplementationContract" }, "local_component_authority": { "type": "object", "additionalProperties": false, @@ -1507,6 +2147,30 @@ } } } + }, + { + "if": { + "anyOf": [ + { "required": ["design_system_scopes"] }, + { "required": ["boundary_contracts"] }, + { "required": ["artifact_inspector"] } + ] + }, + "then": { + "required": ["design_system_scopes", "boundary_contracts", "artifact_inspector"] + } + }, + { + "if": { "required": ["artifact_inspector"] }, + "then": { + "properties": { + "design_system_source": { + "type": "object", + "properties": { "mode": { "const": "judgmentkit_default" } }, + "required": ["mode"] + } + } + } } ] } diff --git a/docs/agent-usage-contract.md b/docs/agent-usage-contract.md index cafb4e2..85a9610 100644 --- a/docs/agent-usage-contract.md +++ b/docs/agent-usage-contract.md @@ -23,8 +23,11 @@ Use JudgmentKit before UI generation, UI critique, implementation planning, or h - Treat `ready_for_review` as permission to proceed with UI concept work, not final product approval. - 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. +- Select `artifact_inspector` only when the rendered artifact is primary, semantic locus selection is required, and support is locus-relative. If those mandatory signals conflict with a queue, creation, conversation, linear-reading, monitoring, or configuration activity, stop at `review_required`; do not break the tie from layout vocabulary. - 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`. +- For Artifact Inspector, preserve `design_system_scopes`, `boundary_contracts`, and `artifact_inspector` as one bundle through workflow review, implementation handoff, frontend context, and implementation review. Apply JudgmentKit conformance only to owned chrome and overlay scopes; keep `primary_artifact` as `external_not_reviewed`. +- Do not accept candidate-authored claims or static browser-composition observations as Artifact Inspector authority proof. This release has no accepting interactive-attestation producer or verifier: retain `review_required`, emit the stable missing-attestation diagnostic, and expose no runnable runtime-review action. - 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,6 +56,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 +- Artifact Inspector handoffs, when applicable, preserve the artifact identity, semantic locus model, `artifact_centered` topology, active state groups, authority scopes, boundary contract, and external artifact status - 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 - 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 diff --git a/package.json b/package.json index fd0faf6..ba71ff7 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "smoke:icons": "node scripts/lucide-icon-catalog-smoke.mjs", "smoke:openai-ui-workflow": "node scripts/smoke-openai-ui-workflow.mjs", "test:presentation-theme": "node tests/presentation-theme.test.mjs && npm run presentation-theme:actual:evidence && npm run presentation-theme:pack:smoke", - "test": "node tests/lucide-icon-catalog.test.mjs && node tests/lucide-icon-catalog-smoke.test.mjs && node tests/kernel-contract.test.mjs && node tests/analyze-implementation-brief.test.mjs && node tests/activity-model-review.test.mjs && node tests/surface-types.test.mjs && node tests/workbench-surface-profile.test.mjs && node tests/ui-generation-handoff.test.mjs && node tests/visual-composition-integration.test.mjs && node tests/visual-composition-browser-runtime.test.mjs && node tests/cognitive-dimensions-review.test.mjs && node tests/openai-responses-provider.test.mjs && node tests/cli.test.mjs && node tests/demo-one-shot.test.mjs && node tests/demo-modal-actions.test.mjs && node tests/demo-comparison.test.mjs && node tests/demo-music-comparison.test.mjs && node tests/demo-model-ui-matrix.test.mjs && node tests/ui-generation-evals.test.mjs && node tests/mcp-pilot-evals.test.mjs && node tests/mcp-pilot-llm-judge.test.mjs && node tests/eval-rerun-guardrails.test.mjs && node tests/mcp.test.mjs && node tests/mcp-stdio.test.mjs && node tests/mcp-http.test.mjs && node tests/install-mcp.test.mjs && node tests/codex-plugin.test.mjs && npm run test:presentation-theme && npm run test:components && node tests/ai-native-design-system-release.test.mjs && node tests/er-flow-dashboard.test.mjs && node tests/site.test.mjs && node tests/site-local-server.test.mjs && node tests/skills.test.mjs && node evals/run-evals.mjs" + "test": "node tests/lucide-icon-catalog.test.mjs && node tests/lucide-icon-catalog-smoke.test.mjs && node tests/kernel-contract.test.mjs && node tests/analyze-implementation-brief.test.mjs && node tests/activity-model-review.test.mjs && node tests/surface-types.test.mjs && node tests/artifact-inspector-routing.test.mjs && node tests/artifact-inspector-workflow.test.mjs && node tests/workbench-surface-profile.test.mjs && node tests/artifact-inspector-surface-profile.test.mjs && node tests/artifact-inspector-authority.test.mjs && node tests/ui-generation-handoff.test.mjs && node tests/visual-composition-integration.test.mjs && node tests/visual-composition-browser-runtime.test.mjs && node tests/cognitive-dimensions-review.test.mjs && node tests/openai-responses-provider.test.mjs && node tests/cli.test.mjs && node tests/demo-one-shot.test.mjs && node tests/demo-modal-actions.test.mjs && node tests/demo-comparison.test.mjs && node tests/demo-music-comparison.test.mjs && node tests/demo-model-ui-matrix.test.mjs && node tests/ui-generation-evals.test.mjs && node tests/mcp-pilot-evals.test.mjs && node tests/mcp-pilot-llm-judge.test.mjs && node tests/eval-rerun-guardrails.test.mjs && node tests/mcp.test.mjs && node tests/mcp-stdio.test.mjs && node tests/mcp-http.test.mjs && node tests/install-mcp.test.mjs && node tests/codex-plugin.test.mjs && npm run test:presentation-theme && npm run test:components && node tests/ai-native-design-system-release.test.mjs && node tests/er-flow-dashboard.test.mjs && node tests/site.test.mjs && node tests/site-local-server.test.mjs && node tests/skills.test.mjs && node evals/run-evals.mjs" }, "dependencies": { "@emotion/cache": "^11.14.0", diff --git a/site/build-site.mjs b/site/build-site.mjs index 986e5e7..80e531d 100755 --- a/site/build-site.mjs +++ b/site/build-site.mjs @@ -7236,15 +7236,20 @@ function renderDesignSystemPatternsPage(model) {

Presentation profiles

-

Presentation profiles specialize a supported surface pattern after the activity, interaction contract, and active design-system source are established. They do not reclassify the activity or select a runtime renderer.

+

Presentation profiles specialize a surface pattern after the activity, interaction contract, and active design-system source are established. Their status identifies whether the profile is supported or still proposed; they do not reclassify the activity or select a runtime renderer.

${renderDesignSystemTable({ - caption: "Supported surface presentation profiles", + caption: "Surface presentation profiles", columns: [ { key: "id", label: "Profile", render: (row) => `${escapeHtml(row.id)}
${escapeHtml(row.name)}`, }, + { + key: "status", + label: "Status", + render: (row) => escapeHtml(row.status ?? "proposed"), + }, { key: "surface_type", label: "Surface", @@ -7266,7 +7271,10 @@ function renderDesignSystemPatternsPage(model) { { key: "responsive", label: "Compact behavior", - render: (row) => escapeHtml(row.responsive?.compact ?? ""), + render: (row) => + escapeHtml( + row.responsive?.compact ?? row.responsive?.narrow ?? "", + ), }, ], rows: profiles, @@ -7594,7 +7602,7 @@ function renderDesignSystemPageMarkdown(model, pageEntry) { markdownList( model.surface_presentation_profiles.map( (entry) => - `\`${entry.id}\` (${entry.surface_type}, ${entry.status}): ${entry.purpose}; pattern: \`${entry.authority?.pattern_contract_id}\`; appearance: ${entry.appearance?.default_mode ?? "system"}; presentation: ${entry.composition?.density ?? "unspecified"}, ${entry.composition?.hierarchy ?? "unspecified"}; compact: ${entry.responsive?.compact ?? "unspecified"}`, + `\`${entry.id}\` (${entry.surface_type}, ${entry.status}): ${entry.purpose}; pattern: \`${entry.authority?.pattern_contract_id}\`; appearance: ${entry.appearance?.default_mode ?? "system"}; presentation: ${entry.composition?.density ?? "unspecified"}, ${entry.composition?.hierarchy ?? "unspecified"}; compact or narrow: ${entry.responsive?.compact ?? entry.responsive?.narrow ?? "unspecified"}`, ), ), "", diff --git a/specs/artifact-inspector.md b/specs/artifact-inspector.md new file mode 100644 index 0000000..07c8a4e --- /dev/null +++ b/specs/artifact-inspector.md @@ -0,0 +1,901 @@ +# JudgmentKit Artifact Inspector Interaction Model + +Status: proposed interaction-model and contract release + +Audience: JudgmentKit product, design, and engineering + +Scope: JudgmentKit interaction-model selection, workflow and implementation +contracts, serialized handoffs, and fail-closed review. This release does not +provide the trusted interactive-attestation runtime required to accept an +Artifact Inspector implementation. + +## Decision + +Add `artifact_inspector` as a first-class JudgmentKit surface type with a +versioned interaction profile and a scoped design-system authority contract. + +The model supports work in which one rendered artifact is the primary object, +the participant acts on a specific locus within it, and supporting evidence, +authority, actions, state changes, and receipts only make sense in relation to +that locus. + +The surrounding product chrome and inspection overlay use JudgmentKit. The +artifact may use an independent design system. JudgmentKit must validate its +two layers without claiming visual authority over the artifact. + +## Why JudgmentKit Needs This Model + +The current taxonomy creates three predictable errors for artifact-centered +work: + +1. Words such as `thread` can route a bounded visual relation to + `conversation`, even when no message exchange exists. +2. `workbench` can recover the operational intent but defaults toward + master-detail, queue-detail, or tool-centric structure. +3. A whole-candidate design-system gate cannot validate quiet product chrome + around an independently styled artifact without either rejecting the + artifact or forcing it into JudgmentKit styling. + +`operator_review` is also insufficient. It tends to make the case, evidence, +risk, and decision controls primary. Artifact inspection reverses that +relationship: the artifact remains primary, and the surrounding context earns +space only through its relation to the artifact. + +## Goals + +- Select `artifact_inspector` from activity evidence rather than keywords. +- Generate an artifact-dominant interaction topology rather than a dashboard, + form, case file, dossier, or conversation. +- Keep observations, evidence, authority, actions, and results spatially or + contextually attached to the artifact. +- Support direct manipulation without requiring drag, hover, or precise + pointing. +- Keep restrained product chrome deliberate, legible, responsive, accessible, + and visibly complete. +- Allow JudgmentKit design-system enforcement for the product chrome while an + embedded artifact retains declared external visual authority. +- Require explicit commitment, recovery, and receipts when the activity has + consequential state changes. +- Preserve the existing surface taxonomy for activities that are not + artifact-centered. + +## Non-Goals + +- Defining the artifact's visual design. +- Turning JudgmentKit into a general-purpose drawing or artifact-authoring + tool. +- Treating every review surface as an artifact inspector. +- Replacing `workbench`, `operator_review`, `content_report`, or + `conversation`. +- Hard-coding one product's authority taxonomy, decision labels, or automation + rules into the base model. +- Waiving accessibility, state coverage, or review evidence because part of + the candidate has external visual authority. +- Treating an externally styled artifact as JudgmentKit-conformant when + JudgmentKit did not review that artifact. + +## Canonical Identifiers + +Use one concept consistently across the current MCP fields: + +| Contract location | Value | +| --- | --- | +| `surface_type` | `artifact_inspector` | +| Workflow profile | `artifact-inspector-ui` | +| Frontend surface profile | `judgmentkit.artifact-inspector.v1` | +| Interaction topology kind | `artifact_centered` | + +The separate identifiers preserve the existing tool interfaces while pointing +to one versioned definition. + +## Terms + +- **Artifact:** The rendered object being inspected. It may be a product UI, + document, composition, diagram, generated result, or another bounded object + that can be meaningfully rendered. +- **Artifact locus:** A selectable region, object, state, or semantic feature + within the artifact. +- **Inspector chrome:** JudgmentKit-owned controls, status, annotations, + connectors, supporting context, and recovery affordances around the + artifact. +- **Inspection overlay:** JudgmentKit-owned selections, pins, connectors, + handles, and local feedback rendered over the artifact without becoming part + of the artifact's visual authority. +- **Support object:** Evidence, authority, rule, comparison, diagnostic, or + another object whose meaning is attached to an artifact locus. +- **Relation:** The visible connection between a locus and a support object or + action. A relation may be provisional or committed. +- **Consequential action:** An action that changes governed state, publishes, + approves, rejects, commits, or creates a reusable rule. +- **Receipt:** A durable, inspectable result of a consequential action. +- **External artifact authority:** A declared visual and component authority + that owns the artifact but not the surrounding inspector chrome. + +## Activity Definition + +### Purpose + +Help a participant inspect one rendered artifact in place, select the part +that matters, bring the right supporting context to that location, and leave +the artifact in an explicit, inspectable state. + +### Primary object + +One current artifact or artifact revision. Observations, evidence, authority, +actions, guidance, and receipts are subordinate objects. + +### Participant completion + +The participant can see what required attention, understand the relevant +supporting context, complete the bounded action when one exists, and verify +the resulting state on or immediately beside the artifact. + +### Applies when most are true + +- The artifact must remain visible for the participant to complete the work. +- The work begins by inspecting or selecting a locus within the artifact. +- Supporting context only becomes meaningful in relation to that locus. +- The participant must compare, relate, validate, decide, or act in place. +- The completion state is legible on or directly beside the artifact. +- Persistent global controls would compete with the object being inspected. +- The artifact may have visual authority independent from the host product. + +The first three conditions are mandatory. A keyword match is never sufficient. + +When mandatory and exclusion evidence are both materially present, +`recommend_surface_types` should return `review_required` with the conflicting +signals. It must not break the tie from layout vocabulary. + +### Do not use when + +- The participant is primarily creating or freely editing the artifact. +- A queue, case list, record set, or many-item comparison is the primary + object. +- The work can be completed without seeing or selecting anything on the + artifact. +- A linear document or report is sufficient. +- The exchange between participants is the primary object. +- The task is primarily monitoring status, trends, or operational health. +- The task is primarily setup, configuration, or debugging. +- The artifact cannot be rendered meaningfully and the supporting dossier must + become primary. + +## Surface-Type Routing + +### Positive evidence + +`recommend_surface_types` should score the following activity evidence: + +- `rendered_artifact_is_primary` +- `locus_selection_required` +- `support_context_is_locus_relative` +- `completion_is_artifact_local` +- `direct_or_spatial_interaction_required` +- `external_artifact_visual_authority` + +### Exclusion evidence + +- `queue_or_case_is_primary` +- `many_items_are_primary` +- `open_ended_creation_is_primary` +- `conversation_turns_are_primary` +- `linear_reading_is_completion` +- `monitoring_is_completion` +- `configuration_is_completion` + +### Tie-break rules + +| Competing type | Choose `artifact_inspector` when | Choose the competing type when | +| --- | --- | --- | +| `workbench` | One artifact stays primary and locus-specific inspection is required. | The participant creates, arranges, or operates across many objects or tools. | +| `operator_review` | The participant must act directly on the produced artifact and context is attached to a locus. | The case, evidence, risk, and bounded decision can be reviewed without artifact-local interaction. | +| `content_report` | Reading leads to locus-specific inspection or state change. | Linear reading, understanding, citation, or sharing is completion. | +| `conversation` | Language is subordinate to a persistent artifact. | Turns, messages, and response continuity are the primary objects. | +| `dashboard_monitor` | The participant investigates one artifact and acts locally. | Status, exceptions, or trends across items are the primary completion. | +| `form_flow` | Structured values are contextual to an artifact locus. | Collecting or changing structured information is the activity. | + +The token `thread` must not independently trigger `conversation`. A visual +connection, causal trace, annotation thread, or authority thread is not a +conversation without message turns, exchange continuity, and a response +activity. + +### Expected recommendation output + +```json +{ + "recommended_surface_type": "artifact_inspector", + "profile_id": "artifact-inspector-ui", + "confidence": "high", + "primary_structure": "persistent artifact, selectable loci, contextual support, local feedback, and artifact-local completion", + "density": "artifact-first contextual", + "navigation_shape": "artifact persistent; supporting context revealed from the active locus" +} +``` + +## Interaction Topology + +### Core loop + +```text +orient to artifact + -> select a locus + -> reveal relevant support or actions + -> preview a relation or change + -> validate locally + -> commit when consequential, or complete when non-consequential + -> show the result on or beside the artifact + -> recover to the last safe state when cancelled or invalid +``` + +### Required work units + +| Work unit | Participant intent | System responsibility | +| --- | --- | --- | +| `orient` | Understand the artifact's current state. | Keep the artifact dominant and expose only essential status. | +| `select_locus` | Identify the part that matters. | Provide a visible selected state and equivalent pointer, touch, and keyboard paths. | +| `inspect_context` | Understand what supports or constrains the locus. | Reveal context progressively and keep its relation to the locus visible. | +| `preview` | Test a relation or action before commitment. | Distinguish provisional state from committed state. | +| `validate` | Know whether the relation or action is supported. | Explain valid, invalid, unavailable, stale, and ambiguous conditions locally. | +| `complete` | Finish the bounded non-consequential task or enter an explicit commit boundary. | Change only the state authorized by the activity contract. | +| `verify_result` | Confirm what changed. | Attach a stable result or receipt to the artifact when required. | +| `recover` | Cancel, go back, retry, or reconcile. | Reverse only uncommitted state and preserve committed results. | + +### Artifact target and interactivity model + +Every workflow declares one artifact boundary and one target model: + +- target kinds: whole artifact, element, text range, region, or point; +- target identity: artifact-supplied or explicit participant selection; +- geometry: read-only and stable for the current artifact revision; +- label: artifact-supplied, artifact-authorized proxy, or `Unavailable`; +- artifact interactivity: `static`, `live`, or `hybrid`. + +Native artifact interaction has precedence for `live` and `hybrid` artifacts. +JudgmentKit may capture a gesture only after the participant enters an explicit +inspection mode, uses a declared inspection handle, or invokes a declared +keyboard command. Artifact inspection cannot silently replace an artifact's +native action. + +If artifact geometry changes, the overlay must re-anchor to the same semantic +target or mark the target stale. It cannot silently drift to another element. + +### Normative topology shape + +`review_ui_workflow_candidate` should accept and validate this explicit shape: + +```json +{ + "workflow": { + "topology": { + "kind": "artifact_centered", + "primary_object_id": "artifact", + "entry_work_unit_id": "orient", + "completion_work_unit_ids": ["verify_result", "orient"], + "transitions": [ + {"from": "orient", "to": "select_locus"}, + {"from": "select_locus", "to": "inspect_context"}, + {"from": "inspect_context", "to": "preview"}, + {"from": "preview", "to": "validate"}, + {"from": "validate", "to": "complete", "when": "supported"}, + {"from": "validate", "to": "recover", "when": "invalid_or_ambiguous"}, + {"from": "recover", "to": "inspect_context", "when": "retry_or_reconcile"}, + {"from": "complete", "to": "verify_result"}, + {"from": "select_locus", "to": "orient", "when": "back"} + ] + }, + "work_units": [] + } +} +``` + +The reviewer should return a field-specific diagnostic when topology is +malformed. It must not collapse all topology errors into `workflow.topology is +required`. + +## Generation Procedure + +JudgmentKit should choose a composition after the activity and topology are +valid. Styling and component selection come later. + +1. Confirm that one rendered artifact is the primary object. +2. Establish whether targets are whole-artifact, element, text-range, region, + or point selections. +3. Establish whether the artifact is static, live, or hybrid and protect its + native interactions. +4. Identify the support objects that must remain related to the active target. +5. Separate reversible preview, consequential commitment, and durable result. +6. Activate only the conditional state groups required by the activity. +7. Choose the least persistent chrome that keeps the target, context, action, + and result understandable together. +8. Project the same state machine to wide and narrow viewports. +9. Declare visual-authority scopes and cross-boundary behavior before frontend + generation. +10. Generate and review the chrome, overlay, artifact-preservation, and boundary + evidence separately. + +### Allowed composition variants + +- **Peripheral anchors:** Use when a small, stable set of support objects must + remain visible around the artifact. +- **Contextual tray:** Use when support objects are numerous, conditional, or + need a narrow-viewport home. +- **Inline annotation:** Use when short context can remain beside a text range, + element, region, or point without obscuring it. +- **Inspection lens:** Use when temporary magnification or focused context is + necessary to understand a dense locus. +- **Responsive hybrid:** Use a peripheral form on wide viewports and a + contextual tray on narrow viewports while preserving identical states and + actions. + +JudgmentKit selects a variant from target density, artifact interactivity, +support-object count, consequence, and viewport evidence. The variant is not a +visual theme and cannot change the participant's completion state. + +## Composition Grammar + +### Required relationships + +- The artifact is the largest and most persistent visual region. +- Inspector chrome surrounds, overlays, or attaches to the artifact without + turning it into a card within a larger case screen. +- The active locus remains visible while its supporting context is open. +- Supporting context is adjacent to the locus, connected to it, or invoked + directly from it. +- Feedback appears at the action or relation that caused it. +- Consequential controls appear only when their preconditions are met. +- Receipts remain visibly connected to the result they describe. +- The participant can return to the previous safe state without searching for + global navigation. +- Host-owned overlay marks remain distinguishable from artifact content. + +### Chrome posture + +The chrome should be reduced but finished: + +- flat or low-elevation surfaces; +- precise alignment and spacing; +- restrained type hierarchy; +- semantic color rather than decorative color; +- sparse labels and domain language; +- contextual controls rather than persistent toolbars; +- clear focus, hover, selected, unavailable, invalid, committing, and complete + states; +- no styling that competes with the artifact. + +Reduced styling is a role distinction. It is not permission for weak hierarchy, +browser-default controls, low contrast, ambiguous targets, or unfinished +states. + +### Artifact posture + +- The artifact preserves its own visual language. +- The artifact may be richer, more dimensional, or more product-like than the + chrome. +- JudgmentKit must not restyle the artifact to make the surrounding chrome + pass. +- Artifact content must not be duplicated into a stack of inspector panels + merely to fit an existing surface pattern. + +### Avoid by default + +- queue-detail and master-detail layouts; +- dashboard summaries; +- persistent evidence dossiers; +- stacked labeled panels; +- form-like step progression; +- a chat composer or message history; +- action bars detached from the selected locus; +- generic approval panels that can be completed without inspecting the + artifact; +- drag-only, hover-only, or color-only interaction. + +## Responsive Model + +### Wide viewports + +- Keep the artifact central and persistent. +- Place sparse support anchors at the periphery or reveal them contextually. +- Route connectors without covering the inspected locus or essential artifact + content. +- Keep global chrome subordinate to artifact-local controls. + +### Narrow viewports + +- Preserve the artifact as the primary viewport content. +- Move supporting context into a temporary edge affordance, anchored popover, + or lightweight selection tray. +- Keep the selected locus, active relation, feedback, and recovery action + visible together. +- Do not require drag; support select-then-target and keyboard-equivalent flows. +- Do not cover the inspected locus with the tray that explains it. +- Preserve zoom, text reflow, and target sizing requirements. + +Responsive adaptation may change placement. It must not change the state +machine or require a different conceptual task. + +## State Coverage + +### Core states + +- artifact loading; +- artifact ready; +- artifact unavailable or failed; +- no active locus; +- locus focused or selected; +- context loading; +- context ready; +- relation or action preview; +- supported; +- incompatible; +- unavailable; +- stale; +- ambiguous; +- blocked; +- cancelled or Back; +- local error and retry. + +### Conditional consequential states + +Require this group when the activity commits a decision or external effect: + +- no option preselected; +- outcome pending; +- committing; +- commit succeeded; +- known failure; +- unknown result; +- receipt reconciliation; +- immutable receipt; +- concurrent result; +- superseding action when reversal is allowed. + +### Conditional reusable-guidance states + +Require this group when one decision can become future guidance: + +- inactive draft after the current result exists; +- correcting; +- explicit confirmation with no default affirmative; +- accepting; +- accepted version; +- declined or Back with no active guidance; +- acceptance failure; +- conflict; +- supersession; +- revocation. + +Current-item commitment and reusable-guidance acceptance are separate +consequential steps. + +### Conditional automation states + +Require this group when accepted guidance can resolve later matches: + +- match preflight; +- exact match; +- near or partial match; +- automatic resolution pending; +- automatic resolution complete; +- inline causal receipt; +- changed authority or evidence; +- failed or uncertain automation; +- exception returned to human review. + +## Mixed Visual Authority + +### Required contract + +`create_ui_implementation_contract` must support more than one declared visual +authority in a single rendered candidate. + +```json +{ + "design_system_scopes": [ + { + "scope_id": "inspector_chrome", + "root_selector": "[data-jk-scope='inspector-chrome']", + "authority": "judgmentkit_default", + "enforcement": "required", + "style_isolation": "required" + }, + { + "scope_id": "inspection_overlay", + "root_selector": "[data-jk-scope='inspection-overlay']", + "authority": "judgmentkit_default", + "enforcement": "required", + "style_isolation": "required" + }, + { + "scope_id": "primary_artifact", + "root_selector": "[data-artifact-root]", + "authority": "external_declared", + "enforcement": "external_not_reviewed", + "style_isolation": "required" + } + ], + "boundary_contracts": [ + { + "from_scope": "inspection_overlay", + "to_scope": "primary_artifact", + "allowed_roles": ["locus_target", "annotation_overlay", "connector_endpoint"], + "event_contract_required": true + } + ] +} +``` + +### Ownership + +| Concern | Owner | +| --- | --- | +| Chrome tokens, components, and interaction states | JudgmentKit | +| Artifact typography, components, color, elevation, and internal layout | Declared external authority | +| Observation markers, connectors, selection handles, and local overlay feedback | JudgmentKit | +| Artifact internal semantics, focus, contrast, and controls | Declared external authority | +| Cross-boundary focus order, overlays, obstruction, labels, and announcements | Host/Inspector contract | +| Artifact target geometry exposed to chrome | Boundary integration contract | + +### Boundary rules + +- Every visible region has one declared authority owner. +- Scope roots cannot overlap unless a named overlay exception declares which + scope owns the overlay. +- JudgmentKit selectors, resets, fonts, and tokens cannot leak into the + artifact scope. +- Artifact styles cannot leak into the chrome scope. +- Chrome annotations that appear over the artifact remain chrome-owned. They + should be rendered through a declared overlay or portal rather than silently + becoming artifact descendants. +- Cross-boundary events use declared semantic locus identifiers. Geometry alone + is insufficient authority. +- A live artifact keeps native gesture precedence until explicit inspection + mode is active. +- Entering and leaving inspection mode must be visible and announced. +- Artifact anchors remain stable for one artifact revision. Changed or missing + targets become stale or unavailable rather than being inferred. +- The artifact cannot be marked external merely to hide nonconforming chrome. +- An external artifact declaration does not count as JudgmentKit artifact + conformance. + +### Review result in this release + +The implementation review reports each scope separately and remains fail-closed: + +```json +{ + "implementation_review_status": "review_required", + "candidate_artifact_status": "review_required", + "design_system_acceptance_status": "review_required", + "next_agent_action": "none", + "design_system_review": { + "inspector_chrome": "review_required", + "inspection_overlay": "review_required", + "primary_artifact": "external_not_reviewed", + "boundary_contract": "review_required" + }, + "trusted_runtime_evidence": { + "status": "unavailable_in_this_release", + "producer_available": false + } +} +``` + +Static or structural violations may still fail with precise diagnostics. An +otherwise valid candidate cannot pass: candidate-authored evidence and the +existing static browser-composition runtime are non-accepting. The +human-facing result must not describe any scope or the whole candidate as +JudgmentKit-conformant. + +### Deferred interactive-attestation evidence + +The following evidence is mandatory for a future accepting runtime, but no +producer or verifier for it exists in this release: + +- exact region and authority map; +- style-isolation proof in both directions; +- artifact render fingerprint before and after every chrome state transition; +- declared pointer, touch, keyboard, and assistive-technology crossings; +- focus-order and focus-return trace; +- overlay occlusion and target-drift checks; +- desktop and narrow views for rest, selection, preview, invalid, supported, + unavailable, and recovery states; +- separate results for chrome conformance, overlay conformance, artifact + preservation, and boundary behavior. + +## JudgmentKit Chrome Components + +The default JudgmentKit design system needs semantic coverage for artifact +inspection. Exact visual treatment remains design-system-owned. + +- `ArtifactViewport` +- `ArtifactBoundary` +- `ArtifactStatus` +- `ObservationMarker` +- `LocusSelection` +- `ContextAnchor` +- `AuthorityAnchor` +- `AnchorRail` +- `RelationPreview` +- `RelationConnector` +- `InlineReason` +- `ContextTray` +- `CommitBoundary` +- `ReceiptMarker` +- `BackAction` +- `ResetAction` +- `ZoomAndPanControls` when the artifact requires them + +The implementation contract may allow semantic HTML and SVG for these roles +until dedicated components exist, but the contract must name the allowed role, +state coverage, token boundary, and accessibility requirements. It must not +fall back to form-field primitives as the only approved component family. + +## Accessibility Contract + +- Every selectable locus has an accessible name, role, and selected state. +- Every connector has a nonvisual relation description. +- Drag has a select-then-target alternative. +- Hover content is also available through focus and activation. +- Focus order follows the participant's activity, not the DOM accident of an + overlay implementation. +- Focus remains stable when contextual chrome appears or disappears. +- Entering and leaving inspection mode is announced, and exiting returns focus + to the initiating target or the nearest valid fallback. +- Invalid, unavailable, stale, committing, complete, and failed states are + announced without stealing focus. +- Color is never the only indicator of relation or state. +- Zoom and reflow do not separate the active locus from its feedback. +- Touch targets and pointer cancellation meet the active accessibility policy. +- The host review verifies cross-boundary behavior. External artifact evidence + verifies the artifact's internal accessibility. +- An artifact-authorized semantic proxy must retain artifact-authority + provenance. JudgmentKit cannot create a semantic description from visual + inference and present it as artifact truth. + +## MCP Behavior Changes + +| Tool | Required change | +| --- | --- | +| `create_activity_model_review` | Ask whether a rendered artifact is primary, whether locus selection is required, what completion looks like, and who owns artifact styling. | +| `recommend_surface_types` | Add `artifact_inspector`, positive and exclusion evidence, and tie-break rules. Remove keyword-only conversation routing. | +| `recommend_ui_workflow_profiles` | Return `artifact-inspector-ui` when the mandatory activity evidence is present. | +| `review_ui_workflow_candidate` | Accept and validate `artifact_centered` topology, work units, transitions, recovery, state groups, and local completion. Return field-specific errors. | +| `create_ui_implementation_contract` | Support `design_system_scopes`, external artifact authority, boundary contracts, and artifact-inspector components. | +| `create_ui_generation_handoff` | Carry the artifact identity, locus model, topology, state groups, authority scopes, and responsive posture without flattening them into workbench defaults. | +| `create_frontend_generation_context` | Accept `judgmentkit.artifact-inspector.v1` and emit the corresponding components, token rules, boundary rules, and browser checks. | +| `review_cognitive_dimensions_candidate` | Check locus-to-action mapping, hidden dependencies, preview versus commitment, progressive evaluation, recovery cost, and disclosure. | +| `review_ui_implementation_candidate` | Enforce structural and static failures; otherwise return `review_required` because the deferred interactive attestation is unavailable. Candidate-authored or static browser evidence cannot satisfy Artifact Inspector authority. | + +No new public MCP tool is required if these existing tools consume the versioned +registry definition. A separate registry resource is acceptable, but the same +definition must drive recommendation, handoff, generation, and review. + +Artifact Inspector review packets carry a private, process-scoped integrity +seal over the complete decision-bearing review packet, including the reviewed +activity, workflow, surface and profile selection, scoped authority, and +active-state ceiling. Each serialized handoff and frontend boundary receives a +stage-specific seal over its complete packet. Handoff, frontend, and skill +boundaries must reject a missing, stale, modified, or cross-packet replayed +seal; after a server restart, callers must rerun workflow review rather than +reuse an old sealed packet. + +## Review Diagnostics + +Diagnostics must be stable, specific, and repairable. + +| Code | Meaning | +| --- | --- | +| `JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING` | No bounded rendered artifact is declared. | +| `JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING` | The participant cannot select a semantic artifact locus. | +| `JK_ARTIFACT_INSPECTOR_TOPOLOGY_CONTRACT_MISSING` | No explicit structured artifact-centered topology is declared. | +| `JK_ARTIFACT_INSPECTOR_TOPOLOGY_KIND_INVALID` | The topology kind is not `artifact_centered`. | +| `JK_ARTIFACT_INSPECTOR_WORK_UNIT_ID_MISSING` | A structured work unit has no stable identifier. | +| `JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID` | A required work unit is duplicated or does not preserve its canonical intent and system responsibility. | +| `JK_ARTIFACT_INSPECTOR_ENTRY_REFERENCE_INVALID` | The topology entry does not reference a declared work unit. | +| `JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID` | Artifact-local completion references an undeclared work unit. | +| `JK_ARTIFACT_INSPECTOR_TRANSITION_REFERENCE_INVALID` | A topology transition references an undeclared work unit. | +| `JK_ARTIFACT_INSPECTOR_RECOVERY_PATH_MISSING` | The topology does not explicitly enter and leave the `recover` work unit. | +| `JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID` | The workflow does not declare the canonical active state groups. | +| `JK_ARTIFACT_INSPECTOR_ARTIFACT_NOT_DOMINANT` | Persistent chrome or supporting context visually displaces the artifact. | +| `JK_ARTIFACT_INSPECTOR_CONTEXT_DETACHED` | Evidence, authority, action, or feedback has no visible or semantic relation to the active locus. | +| `JK_ARTIFACT_INSPECTOR_DRAG_ONLY` | A required interaction has no tap/select and keyboard alternative. | +| `JK_ARTIFACT_INSPECTOR_LOCAL_FEEDBACK_MISSING` | Validation or status appears away from the action that caused it. | +| `JK_ARTIFACT_INSPECTOR_UNCOMMITTED_STATE_AMBIGUOUS` | Preview and committed state are not distinguishable. | +| `JK_ARTIFACT_INSPECTOR_DEFAULT_COMMIT` | A consequential affirmative or outcome is preselected. | +| `JK_ARTIFACT_INSPECTOR_RECEIPT_MISSING` | A consequential result has no inspectable local receipt. | +| `JK_ARTIFACT_INSPECTOR_GUIDANCE_COUPLED` | Current-item commitment and reusable-guidance acceptance occur in one action. | +| `JK_ARTIFACT_INSPECTOR_MOBILE_ARTIFACT_OBSCURED` | Narrow-layout chrome covers the active locus or essential artifact content. | +| `JK_ARTIFACT_INSPECTOR_CHROME_SCOPE_MISSING` | JudgmentKit-owned chrome has no enforceable design-system scope. | +| `JK_ARTIFACT_INSPECTOR_ARTIFACT_SCOPE_MISSING` | The artifact's visual authority is undeclared. | +| `JK_ARTIFACT_INSPECTOR_SCOPE_OVERLAP` | Two authority scopes claim the same visible node without a valid overlay exception. | +| `JK_ARTIFACT_INSPECTOR_STYLE_LEAK` | Styles or tokens cross an authority boundary. | +| `JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED` | Chrome interacts with an artifact locus without a semantic boundary contract. | +| `JK_ARTIFACT_INSPECTOR_NATIVE_ACTION_INTERCEPTED` | Inspector behavior captures a live artifact action without explicit inspection mode. | +| `JK_ARTIFACT_INSPECTOR_TARGET_DRIFT` | An overlay silently moved to a different artifact target. | +| `JK_ARTIFACT_INSPECTOR_ARTIFACT_MUTATED` | A chrome transition changed artifact content or presentation. | +| `JK_ARTIFACT_INSPECTOR_EXTERNAL_AUTHORITY_OVERCLAIM` | The review describes the external artifact as JudgmentKit-conformant. | +| `JK_ARTIFACT_INSPECTOR_KEYWORD_ROUTING_CONFLICT` | Artifact Inspector routing conflicts with mandatory activity evidence, exclusions, the selected surface, or the workflow profile. | + +Every diagnostic should include the failing field or selector, the expected +contract, the observed value, and one bounded repair instruction. + +## Deterministic Fixture Matrix + +### Positive routing fixtures + +1. A rendered interface where the participant selects one visible control and + relates an observation to accepted authority. +2. A document where the participant selects a passage and attaches a + source-backed correction. +3. A diagram where the participant selects one node and inspects the rule and + evidence that produced it. +4. A generated composition where the participant marks one region, previews a + bounded change, and verifies the local result. + +Expected: `artifact_inspector` is primary. The artifact remains the primary +object in every generated workflow. + +### Negative routing fixtures + +1. A queue of generated cases with evidence and approve/reject controls. + Expected: `operator_review`. +2. A multi-object creation canvas with persistent tools. Expected: `workbench`. +3. A linear evidence memo. Expected: `content_report`. +4. A live support exchange with attachments. Expected: `conversation`. +5. A status overview across many items. Expected: `dashboard_monitor`. +6. A structured submission sequence. Expected: `form_flow`. +7. A structured record-entry task with an incidental artifact preview. + Expected: `form_flow`; the preview alone does not trigger + `artifact_inspector`. + +### Ambiguity fixtures + +1. Queue plus artifact detail: choose `operator_review` when the queue and case + decision are primary; choose `artifact_inspector` only when locus-specific + artifact action is required for completion. +2. Whole-artifact approval without locus selection: choose `operator_review`. +3. Read-only artifact with citations but no local action: choose + `content_report`. +4. A visual object called an `authority thread`: do not choose `conversation` + unless message exchange is the activity. +5. Several artifacts compared side by side: choose `workbench` unless one + artifact remains primary and every comparison is subordinate to it. + +### Authority-boundary fixtures + +1. JudgmentKit chrome plus externally styled artifact with isolated scopes. + Expected in this release: chrome, overlay, and boundary remain + `review_required`; the artifact remains `external_not_reviewed`. +2. Global JudgmentKit reset changes artifact typography. Expected: + `JK_ARTIFACT_INSPECTOR_STYLE_LEAK`. +3. Artifact CSS changes chrome buttons. Expected: + `JK_ARTIFACT_INSPECTOR_STYLE_LEAK`. +4. Annotation overlay is visually over the artifact but has no declared owner. + Expected: `JK_ARTIFACT_INSPECTOR_SCOPE_OVERLAP` or missing scope. +5. Chrome is mislabeled as an external artifact to avoid token checks. + Expected: external-authority overclaim or chrome-scope failure. +6. A chrome state transition changes artifact bytes or computed presentation. + Expected: `JK_ARTIFACT_INSPECTOR_ARTIFACT_MUTATED`. +7. A live artifact's native action is intercepted without inspection mode. + Expected: `JK_ARTIFACT_INSPECTOR_NATIVE_ACTION_INTERCEPTED`. +8. An artifact revision changes target geometry and the overlay attaches to a + different target. Expected: `JK_ARTIFACT_INSPECTOR_TARGET_DRIFT`. + +### Interaction fixtures + +- pointer drag succeeds; +- select-then-target succeeds; +- keyboard-only succeeds; +- touch path succeeds without hover; +- invalid target explains itself locally; +- unavailable context cannot become accepted support; +- Back removes only the current preview; +- known failure preserves an uncommitted choice; +- unknown result reconciles before retry; +- narrow layout preserves the artifact, active locus, feedback, and recovery. + +### Compatibility and determinism fixtures + +- Existing surface inputs produce their prior canonical outputs. +- An older schema receiving `artifact_inspector` returns an explicit + unsupported-profile diagnostic with no silent fallback. +- Repeated generation from the same fixture produces byte-identical canonical + contracts, diagnostics, reports, and hashes. + +## Contract release acceptance criteria + +The interaction-model and contract release is ready only when: + +1. Positive, negative, and ambiguity routing fixtures select the expected + surface without keyword-only overrides. +2. Queue-primary, creation, conversation, report, monitoring, configuration, + and explicitly secondary-artifact activities retain their legacy surfaces. +3. Workflow review accepts only the canonical `artifact_centered` topology, + eight work units, participant intent, system responsibility, transitions, + entry, completion, and connected recovery path. +4. Compatible artifact and target aliases canonicalize into `workflow.*`; + conflicting or malformed aliases fail during review. +5. Handoff, frontend context, and skill compilation revalidate the same + surface, profile, topology, work-unit, artifact, target, state-group, and + authority invariants. +6. Only activity-justified state groups can remain active; caller metadata or + packet mutation cannot activate another group. +7. The scoped authority declaration requires exactly the three canonical + scopes and exactly the three canonical boundary roles. +8. The profile serializes its canonical navigation, wide, narrow, and external + artifact ownership guidance while remaining `runtime_renderer: false`. +9. Deterministic contract and static violations fail with bounded diagnostics + and repair instructions. +10. An otherwise valid Artifact Inspector implementation always remains + `review_required`, exposes no runnable attestation action, and emits no + pass or accepted-artifact result. +11. The primary artifact always remains `external_not_reviewed`. +12. Existing routing, Workbench behavior, generic visual-composition review, + component registry, and component specimens remain unchanged. +13. The same versioned registry definition drives recommendation, workflow + review, implementation handoff, frontend context, skill context, and + fail-closed implementation review. + +## Deferred interactive-runtime acceptance criteria + +A later dedicated project must satisfy every item below before an Artifact +Inspector implementation can pass: + +- a runnable, deterministic state driver for every required state, transition, + cancellation, recovery route, and artifact revision; +- real CDP pointer, touch, and keyboard traces with trusted event targets, + paths, locus identifiers, and native behavior; +- accessibility-platform traces for names, roles, relationships, + announcements, and assistive-technology crossings; +- focus order, focus entry, cancellation, recovery, and focus return; +- overlay geometry, obstruction, occlusion, and responsive safe areas; +- semantic target drift and re-anchoring to the same target, or explicit stale + or unavailable behavior; +- native-action precedence outside explicit inspection mode; +- bidirectional style isolation and artifact fingerprints before and after each + governed transition; +- all seven required states in both desktop and narrow viewports; +- separate chrome, overlay, artifact-preservation, and boundary results; and +- an opaque, replay-resistant attestation bound to trusted issuer/verifier + versions, candidate digest, normalized contract digest, state-driver digest, + artifact revision, observation digests, run identity, nonce, and timestamp. + +Static roots, unchanged fingerprints, canonical metadata, or caller-authored +receipts cannot substitute for these observations. + +## Contract release shape + +This release adds: + +- a versioned interaction-model registry entry; +- schemas for `artifact_centered` topology and mixed authority declarations; +- deterministic routing, workflow, serialization, profile, authority, MCP, and + legacy-isolation tests; +- stable structural and missing-attestation diagnostics; and +- a fail-closed implementation-review result. + +It deliberately does not add Artifact Inspector measurement logic to the +static visual-composition browser runtime, a runnable state driver, an +accepting receipt schema, or a public evidence-ingestion API. + +## Compatibility and rollout + +- Add the model as a versioned, additive registry entry. +- Preserve existing surface behavior unless all mandatory Artifact Inspector + activity evidence is present. +- Return `artifact_inspector_profile_unsupported` when a caller cannot consume + the profile; never silently downgrade it. +- Keep `judgmentkit.artifact-inspector.v1` immutable after release. +- Keep the 17 profile component roles conceptual and contract-only; they are + not component-registry implementations or approved runtime primitives. +- Keep every current Artifact Inspector authority result `review_required` + until the deferred interactive-attestation project is separately released. + +## Definition of done for this release + +JudgmentKit can identify an artifact-centered activity, validate and serialize +its canonical workflow, declare scoped authority without claiming the external +artifact, preserve the contract through every downstream boundary, and reject +structural drift. Implementation review remains honestly fail-closed at +`review_required` because trusted interactive attestation is outside this +release. diff --git a/src/artifact-inspector-authority.mjs b/src/artifact-inspector-authority.mjs new file mode 100644 index 0000000..edb2890 --- /dev/null +++ b/src/artifact-inspector-authority.mjs @@ -0,0 +1,983 @@ +const hasOwn = (value, key) => Object.prototype.hasOwnProperty.call(value, key); + +function isPlainObject(value) { + if (value === null || typeof value !== "object" || Array.isArray(value)) { + return false; + } + + const prototype = Object.getPrototypeOf(value); + return prototype === Object.prototype || prototype === null; +} + +function frozenRecord(value) { + return Object.freeze( + Object.fromEntries( + Object.entries(value).map(([key, entry]) => [ + key, + Array.isArray(entry) ? Object.freeze([...entry]) : entry, + ]), + ), + ); +} + +export const ARTIFACT_INSPECTOR_SCOPE_IDS = Object.freeze([ + "inspector_chrome", + "inspection_overlay", + "primary_artifact", +]); + +export const ARTIFACT_INSPECTOR_STATE_GROUP_IDS = Object.freeze([ + "core", + "consequential", + "reusable_guidance", + "automation", +]); + +export const ARTIFACT_INSPECTOR_CANONICAL_SCOPES = Object.freeze([ + Object.freeze({ + scope_id: "inspector_chrome", + root_selector: "[data-jk-scope='inspector-chrome']", + authority: "judgmentkit_default", + enforcement: "required", + style_isolation: "required", + }), + Object.freeze({ + scope_id: "inspection_overlay", + root_selector: "[data-jk-scope='inspection-overlay']", + authority: "judgmentkit_default", + enforcement: "required", + style_isolation: "required", + }), + Object.freeze({ + scope_id: "primary_artifact", + root_selector: "[data-artifact-root]", + authority: "external_declared", + enforcement: "external_not_reviewed", + style_isolation: "required", + }), +]); + +export const ARTIFACT_INSPECTOR_CANONICAL_BOUNDARY_CONTRACTS = Object.freeze([ + Object.freeze({ + from_scope: "inspection_overlay", + to_scope: "primary_artifact", + allowed_roles: Object.freeze([ + "locus_target", + "annotation_overlay", + "connector_endpoint", + ]), + event_contract_required: true, + }), +]); + +export const ARTIFACT_INSPECTOR_CANONICAL_STATE_GROUPS = frozenRecord({ + core: [ + "artifact loading", + "artifact ready", + "artifact unavailable or failed", + "no active locus", + "locus focused or selected", + "context loading", + "context ready", + "relation or action preview", + "supported", + "incompatible", + "unavailable", + "stale", + "ambiguous", + "blocked", + "cancelled or Back", + "local error and retry", + ], + consequential: [ + "no option preselected", + "outcome pending", + "committing", + "commit succeeded", + "known failure", + "unknown result", + "receipt reconciliation", + "immutable receipt", + "concurrent result", + "superseding action when reversal is allowed", + ], + reusable_guidance: [ + "inactive draft after the current result exists", + "correcting", + "explicit confirmation with no default affirmative", + "accepting", + "accepted version", + "declined or Back with no active guidance", + "acceptance failure", + "conflict", + "supersession", + "revocation", + ], + automation: [ + "match preflight", + "exact match", + "near or partial match", + "automatic resolution pending", + "automatic resolution complete", + "inline causal receipt", + "changed authority or evidence", + "failed or uncertain automation", + "exception returned to human review", + ], +}); + +export const ARTIFACT_INSPECTOR_DIAGNOSTIC_CODES = Object.freeze([ + "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + "JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING", + "JK_ARTIFACT_INSPECTOR_TOPOLOGY_CONTRACT_MISSING", + "JK_ARTIFACT_INSPECTOR_TOPOLOGY_KIND_INVALID", + "JK_ARTIFACT_INSPECTOR_WORK_UNIT_ID_MISSING", + "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + "JK_ARTIFACT_INSPECTOR_ENTRY_REFERENCE_INVALID", + "JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID", + "JK_ARTIFACT_INSPECTOR_TRANSITION_REFERENCE_INVALID", + "JK_ARTIFACT_INSPECTOR_RECOVERY_PATH_MISSING", + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + "JK_ARTIFACT_INSPECTOR_ARTIFACT_NOT_DOMINANT", + "JK_ARTIFACT_INSPECTOR_CONTEXT_DETACHED", + "JK_ARTIFACT_INSPECTOR_DRAG_ONLY", + "JK_ARTIFACT_INSPECTOR_LOCAL_FEEDBACK_MISSING", + "JK_ARTIFACT_INSPECTOR_UNCOMMITTED_STATE_AMBIGUOUS", + "JK_ARTIFACT_INSPECTOR_DEFAULT_COMMIT", + "JK_ARTIFACT_INSPECTOR_RECEIPT_MISSING", + "JK_ARTIFACT_INSPECTOR_GUIDANCE_COUPLED", + "JK_ARTIFACT_INSPECTOR_MOBILE_ARTIFACT_OBSCURED", + "JK_ARTIFACT_INSPECTOR_CHROME_SCOPE_MISSING", + "JK_ARTIFACT_INSPECTOR_ARTIFACT_SCOPE_MISSING", + "JK_ARTIFACT_INSPECTOR_SCOPE_OVERLAP", + "JK_ARTIFACT_INSPECTOR_STYLE_LEAK", + "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED", + "JK_ARTIFACT_INSPECTOR_NATIVE_ACTION_INTERCEPTED", + "JK_ARTIFACT_INSPECTOR_TARGET_DRIFT", + "JK_ARTIFACT_INSPECTOR_ARTIFACT_MUTATED", + "JK_ARTIFACT_INSPECTOR_EXTERNAL_AUTHORITY_OVERCLAIM", + "JK_ARTIFACT_INSPECTOR_KEYWORD_ROUTING_CONFLICT", + "JK_ARTIFACT_INSPECTOR_TRUSTED_RUNTIME_EVIDENCE_MISSING", +]); + +const DIAGNOSTIC_DEFAULTS = Object.freeze({ + JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING: Object.freeze({ + message: "No bounded rendered artifact is declared.", + repair_instruction: + "Declare one primary artifact scope with external visual authority.", + }), + JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING: Object.freeze({ + message: "The participant cannot select a semantic artifact locus.", + repair_instruction: + "Expose stable semantic locus identifiers and equivalent pointer, touch, and keyboard paths.", + }), + JK_ARTIFACT_INSPECTOR_TOPOLOGY_CONTRACT_MISSING: Object.freeze({ + message: + "The artifact-centered workflow has no explicit structured topology contract.", + repair_instruction: + "Provide workflow.topology as the explicit artifact_centered topology object instead of a compatibility string.", + }), + JK_ARTIFACT_INSPECTOR_TOPOLOGY_KIND_INVALID: Object.freeze({ + message: "The artifact-centered workflow declares an invalid topology kind.", + repair_instruction: + "Set workflow.topology.kind to artifact_centered and preserve the canonical topology fields.", + }), + JK_ARTIFACT_INSPECTOR_WORK_UNIT_ID_MISSING: Object.freeze({ + message: "A structured artifact work unit has no stable identifier.", + repair_instruction: + "Give every Artifact Inspector work unit its canonical stable id.", + }), + JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID: Object.freeze({ + message: + "A required artifact work unit is duplicated or does not preserve its canonical participant intent or system responsibility.", + repair_instruction: + "Keep exactly one work unit per canonical id and restore it from the versioned Artifact Inspector registry definition.", + }), + JK_ARTIFACT_INSPECTOR_ENTRY_REFERENCE_INVALID: Object.freeze({ + message: "The topology entry does not reference a declared work unit.", + repair_instruction: + "Point entry_work_unit_id at the declared orient work unit.", + }), + JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID: Object.freeze({ + message: "Artifact-local completion does not reference declared work units.", + repair_instruction: + "Use only declared work-unit ids in completion_work_unit_ids and retain artifact-local completion.", + }), + JK_ARTIFACT_INSPECTOR_TRANSITION_REFERENCE_INVALID: Object.freeze({ + message: "A topology transition does not connect declared work units.", + repair_instruction: + "Make every transition from and to reference declared Artifact Inspector work-unit ids.", + }), + JK_ARTIFACT_INSPECTOR_RECOVERY_PATH_MISSING: Object.freeze({ + message: "The artifact workflow has no explicit connected recovery work unit.", + repair_instruction: + "Declare recover and connect both an inbound recovery transition and an outbound return to a safe work unit.", + }), + JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID: Object.freeze({ + message: + "The artifact workflow does not declare the canonical active state groups.", + repair_instruction: + "Declare core and only the conditional groups activated by the activity, using the exact registry state sets.", + }), + JK_ARTIFACT_INSPECTOR_ARTIFACT_NOT_DOMINANT: Object.freeze({ + message: "Persistent chrome or supporting context visually displaces the artifact.", + repair_instruction: + "Keep the artifact as the largest persistent work region at wide and narrow viewports.", + }), + JK_ARTIFACT_INSPECTOR_CONTEXT_DETACHED: Object.freeze({ + message: "Supporting context has no visible or semantic relation to the active locus.", + repair_instruction: + "Attach evidence, authority, actions, and feedback to the active semantic locus.", + }), + JK_ARTIFACT_INSPECTOR_DRAG_ONLY: Object.freeze({ + message: "A required interaction has no tap, select, and keyboard alternative.", + repair_instruction: + "Provide equivalent pointer, touch, and keyboard interaction paths.", + }), + JK_ARTIFACT_INSPECTOR_LOCAL_FEEDBACK_MISSING: Object.freeze({ + message: "Validation or status appears away from the action that caused it.", + repair_instruction: + "Render feedback on or immediately beside the active artifact locus.", + }), + JK_ARTIFACT_INSPECTOR_UNCOMMITTED_STATE_AMBIGUOUS: Object.freeze({ + message: "Preview and committed state are not distinguishable.", + repair_instruction: + "Declare and render distinct preview, validation, commitment, result, and recovery states.", + }), + JK_ARTIFACT_INSPECTOR_DEFAULT_COMMIT: Object.freeze({ + message: "A consequential affirmative or outcome is preselected.", + repair_instruction: + "Remove the default affirmative and require an explicit commitment action.", + }), + JK_ARTIFACT_INSPECTOR_RECEIPT_MISSING: Object.freeze({ + message: "A consequential result has no inspectable local receipt.", + repair_instruction: + "Attach a durable receipt to the artifact locus after commitment.", + }), + JK_ARTIFACT_INSPECTOR_GUIDANCE_COUPLED: Object.freeze({ + message: "Current-item commitment and reusable-guidance acceptance occur in one action.", + repair_instruction: + "Separate the current result from reusable-guidance acceptance and its lifecycle.", + }), + JK_ARTIFACT_INSPECTOR_MOBILE_ARTIFACT_OBSCURED: Object.freeze({ + message: "Narrow-layout chrome covers the active locus or essential artifact content.", + repair_instruction: + "Move contextual chrome without obscuring the active locus at narrow widths.", + }), + JK_ARTIFACT_INSPECTOR_CHROME_SCOPE_MISSING: Object.freeze({ + message: "JudgmentKit-owned chrome has no enforceable design-system scope.", + repair_instruction: + "Declare canonical inspector_chrome and inspection_overlay scopes with required isolation.", + }), + JK_ARTIFACT_INSPECTOR_ARTIFACT_SCOPE_MISSING: Object.freeze({ + message: "The artifact's visual authority is undeclared.", + repair_instruction: + "Declare the canonical primary_artifact external scope and keep it external_not_reviewed.", + }), + JK_ARTIFACT_INSPECTOR_SCOPE_OVERLAP: Object.freeze({ + message: "Authority scopes overlap or duplicate an ownership claim.", + repair_instruction: + "Give every visible region one authority owner and use the declared overlay boundary only.", + }), + JK_ARTIFACT_INSPECTOR_STYLE_LEAK: Object.freeze({ + message: "Styles or tokens cross an authority boundary.", + repair_instruction: + "Isolate JudgmentKit chrome and overlay styles from external artifact styles in both directions.", + }), + JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED: Object.freeze({ + message: "Chrome interacts with an artifact locus without a semantic boundary contract.", + repair_instruction: + "Declare the overlay-to-artifact event contract and use semantic locus identifiers.", + }), + JK_ARTIFACT_INSPECTOR_NATIVE_ACTION_INTERCEPTED: Object.freeze({ + message: "Inspector behavior captures a live artifact action without explicit inspection mode.", + repair_instruction: + "Restore native interaction precedence until inspection mode is explicitly active.", + }), + JK_ARTIFACT_INSPECTOR_TARGET_DRIFT: Object.freeze({ + message: "An overlay silently moved to a different artifact target.", + repair_instruction: + "Re-anchor to the same semantic target or mark the target stale or unavailable.", + }), + JK_ARTIFACT_INSPECTOR_ARTIFACT_MUTATED: Object.freeze({ + message: "A chrome transition changed artifact content or presentation.", + repair_instruction: + "Preserve the artifact render fingerprint across every chrome-only transition.", + }), + JK_ARTIFACT_INSPECTOR_EXTERNAL_AUTHORITY_OVERCLAIM: Object.freeze({ + message: "The review describes the external artifact as JudgmentKit-conformant.", + repair_instruction: + "Report the external artifact as external_not_reviewed and state only which owned scopes passed.", + }), + JK_ARTIFACT_INSPECTOR_KEYWORD_ROUTING_CONFLICT: Object.freeze({ + message: + "Artifact Inspector routing conflicts with mandatory activity evidence, exclusions, the selected surface, or the workflow profile.", + repair_instruction: + "Resolve routing from mandatory activity evidence, exclusions, and canonical surface and profile selections; do not let metadata override grounded evidence.", + }), + JK_ARTIFACT_INSPECTOR_TRUSTED_RUNTIME_EVIDENCE_MISSING: Object.freeze({ + message: + "The deferred trusted interactive attestation required for Artifact Inspector acceptance is unavailable in this release.", + repair_instruction: + "Keep the candidate at review_required until the separately released interactive-attestation contract can supply and verify the complete evidence matrix.", + }), +}); + +const DIAGNOSTIC_CODE_SET = new Set(ARTIFACT_INSPECTOR_DIAGNOSTIC_CODES); +const DIAGNOSTIC_ORDER = new Map( + ARTIFACT_INSPECTOR_DIAGNOSTIC_CODES.map((code, index) => [code, index]), +); +const SCOPE_BY_ID = new Map( + ARTIFACT_INSPECTOR_CANONICAL_SCOPES.map((scope) => [scope.scope_id, scope]), +); +const CANONICAL_BOUNDARY = ARTIFACT_INSPECTOR_CANONICAL_BOUNDARY_CONTRACTS[0]; +const CANONICAL_BOUNDARY_ROLES = new Set(CANONICAL_BOUNDARY.allowed_roles); + +function authorityError(message, details = {}) { + const error = new TypeError(message); + error.name = "ArtifactInspectorAuthorityError"; + error.code = "invalid_artifact_inspector_authority_contract"; + error.details = details; + return error; +} + +function requirePlainObject(value, field) { + if (!isPlainObject(value)) { + throw authorityError(`${field} must be an object.`, { + field, + observed: value, + }); + } +} + +function assertOnlyKeys(value, allowedKeys, field) { + const unexpected = Object.keys(value).filter((key) => !allowedKeys.includes(key)); + if (unexpected.length > 0) { + throw authorityError(`${field} contains unsupported fields: ${unexpected.join(", ")}.`, { + field, + unexpected_fields: unexpected.sort(), + }); + } +} + +function requiredString(value, field) { + if (typeof value !== "string" || value.trim().length === 0) { + throw authorityError(`${field} must be a non-empty string.`, { + field, + observed: value, + }); + } + return value.trim(); +} + +function normalizeStringSet(value, field) { + if (!Array.isArray(value) || value.length === 0) { + throw authorityError(`${field} must be a non-empty array.`, { + field, + observed: value, + }); + } + + const normalized = value.map((entry, index) => + requiredString(entry, `${field}[${index}]`), + ); + if (new Set(normalized).size !== normalized.length) { + throw authorityError(`${field} must not contain duplicates.`, { + field, + observed: normalized, + }); + } + return normalized; +} + +function assertExactSet(actual, expected, field, diagnosticCode) { + const actualSet = new Set(actual); + const missing = expected.filter((entry) => !actualSet.has(entry)); + const unexpected = actual.filter((entry) => !expected.includes(entry)); + if (missing.length > 0 || unexpected.length > 0 || actual.length !== expected.length) { + throw authorityError(`${field} does not match the canonical Artifact Inspector contract.`, { + field, + missing, + unexpected, + diagnostic_code: diagnosticCode, + }); + } +} + +function cloneStateGroups() { + return Object.fromEntries( + ARTIFACT_INSPECTOR_STATE_GROUP_IDS.map((groupId) => [ + groupId, + [...ARTIFACT_INSPECTOR_CANONICAL_STATE_GROUPS[groupId]], + ]), + ); +} + +export function normalizeArtifactInspectorScopes(value, { required = false } = {}) { + if (value === undefined || value === null) { + if (required) { + throw authorityError("design_system_scopes is required for Artifact Inspector.", { + field: "design_system_scopes", + diagnostic_code: "JK_ARTIFACT_INSPECTOR_CHROME_SCOPE_MISSING", + }); + } + return []; + } + + if (!Array.isArray(value)) { + throw authorityError("design_system_scopes must be an array.", { + field: "design_system_scopes", + observed: value, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_CHROME_SCOPE_MISSING", + }); + } + + const byId = new Map(); + for (const [index, entry] of value.entries()) { + const field = `design_system_scopes[${index}]`; + requirePlainObject(entry, field); + assertOnlyKeys( + entry, + ["scope_id", "root_selector", "authority", "enforcement", "style_isolation"], + field, + ); + + const scopeId = requiredString(entry.scope_id, `${field}.scope_id`); + const canonical = SCOPE_BY_ID.get(scopeId); + if (!canonical) { + throw authorityError(`${field}.scope_id is not a canonical Artifact Inspector scope.`, { + field: `${field}.scope_id`, + observed: scopeId, + expected: ARTIFACT_INSPECTOR_SCOPE_IDS, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_SCOPE_OVERLAP", + }); + } + if (byId.has(scopeId)) { + throw authorityError(`design_system_scopes declares ${scopeId} more than once.`, { + field: "design_system_scopes", + scope_id: scopeId, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_SCOPE_OVERLAP", + }); + } + + const normalized = { + scope_id: scopeId, + root_selector: requiredString(entry.root_selector, `${field}.root_selector`), + authority: requiredString(entry.authority, `${field}.authority`), + enforcement: requiredString(entry.enforcement, `${field}.enforcement`), + style_isolation: requiredString(entry.style_isolation, `${field}.style_isolation`), + }; + + for (const key of ["root_selector", "authority", "enforcement", "style_isolation"]) { + if (normalized[key] !== canonical[key]) { + throw authorityError(`${field}.${key} conflicts with the canonical authority boundary.`, { + field: `${field}.${key}`, + scope_id: scopeId, + expected: canonical[key], + observed: normalized[key], + diagnostic_code: + scopeId === "primary_artifact" + ? "JK_ARTIFACT_INSPECTOR_ARTIFACT_SCOPE_MISSING" + : "JK_ARTIFACT_INSPECTOR_CHROME_SCOPE_MISSING", + }); + } + } + byId.set(scopeId, normalized); + } + + if (required) { + const missing = ARTIFACT_INSPECTOR_SCOPE_IDS.filter((scopeId) => !byId.has(scopeId)); + if (missing.length > 0) { + throw authorityError("Artifact Inspector requires all canonical authority scopes.", { + field: "design_system_scopes", + missing, + diagnostic_code: missing.includes("primary_artifact") + ? "JK_ARTIFACT_INSPECTOR_ARTIFACT_SCOPE_MISSING" + : "JK_ARTIFACT_INSPECTOR_CHROME_SCOPE_MISSING", + }); + } + } + + return ARTIFACT_INSPECTOR_SCOPE_IDS.filter((scopeId) => byId.has(scopeId)).map( + (scopeId) => byId.get(scopeId), + ); +} + +export function normalizeArtifactInspectorBoundaryContracts( + value, + { scopes = [], required = false } = {}, +) { + if (value === undefined || value === null) { + if (required) { + throw authorityError("boundary_contracts is required for Artifact Inspector.", { + field: "boundary_contracts", + diagnostic_code: "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED", + }); + } + return []; + } + + if (!Array.isArray(value)) { + throw authorityError("boundary_contracts must be an array.", { + field: "boundary_contracts", + observed: value, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED", + }); + } + if (required && value.length !== 1) { + throw authorityError("Artifact Inspector requires exactly one canonical boundary contract.", { + field: "boundary_contracts", + observed_count: value.length, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED", + }); + } + + const knownScopes = new Set(scopes.map((scope) => scope.scope_id)); + const normalized = value.map((entry, index) => { + const field = `boundary_contracts[${index}]`; + requirePlainObject(entry, field); + assertOnlyKeys( + entry, + ["from_scope", "to_scope", "allowed_roles", "event_contract_required"], + field, + ); + + const fromScope = requiredString(entry.from_scope, `${field}.from_scope`); + const toScope = requiredString(entry.to_scope, `${field}.to_scope`); + if ( + fromScope !== CANONICAL_BOUNDARY.from_scope || + toScope !== CANONICAL_BOUNDARY.to_scope + ) { + throw authorityError(`${field} is not the canonical overlay-to-artifact boundary.`, { + field, + expected: { + from_scope: CANONICAL_BOUNDARY.from_scope, + to_scope: CANONICAL_BOUNDARY.to_scope, + }, + observed: { from_scope: fromScope, to_scope: toScope }, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED", + }); + } + if ( + knownScopes.size > 0 && + (!knownScopes.has(fromScope) || !knownScopes.has(toScope)) + ) { + throw authorityError(`${field} references an undeclared authority scope.`, { + field, + observed: { from_scope: fromScope, to_scope: toScope }, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED", + }); + } + + const roles = normalizeStringSet(entry.allowed_roles, `${field}.allowed_roles`); + const unsupportedRoles = roles.filter((role) => !CANONICAL_BOUNDARY_ROLES.has(role)); + if (unsupportedRoles.length > 0) { + throw authorityError(`${field}.allowed_roles contains unsupported boundary roles.`, { + field: `${field}.allowed_roles`, + unexpected: unsupportedRoles, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED", + }); + } + assertExactSet( + roles, + CANONICAL_BOUNDARY.allowed_roles, + `${field}.allowed_roles`, + "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED", + ); + if (entry.event_contract_required !== true) { + throw authorityError(`${field}.event_contract_required must be true.`, { + field: `${field}.event_contract_required`, + observed: entry.event_contract_required, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED", + }); + } + + return { + from_scope: fromScope, + to_scope: toScope, + allowed_roles: CANONICAL_BOUNDARY.allowed_roles.filter((role) => roles.includes(role)), + event_contract_required: true, + }; + }); + + const identities = normalized.map( + (entry) => `${entry.from_scope}->${entry.to_scope}`, + ); + if (new Set(identities).size !== identities.length) { + throw authorityError("boundary_contracts contains a duplicate authority boundary.", { + field: "boundary_contracts", + diagnostic_code: "JK_ARTIFACT_INSPECTOR_SCOPE_OVERLAP", + }); + } + + return normalized; +} + +function normalizeArtifactInspectorStateConfigUnchecked( + value, + { required = false } = {}, +) { + if (value === undefined || value === null) { + if (required) { + throw authorityError("Artifact Inspector state configuration is required.", { + field: "artifact_inspector.state_groups", + diagnostic_code: "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }); + } + return null; + } + + requirePlainObject(value, "artifact_inspector.state_config"); + assertOnlyKeys( + value, + ["active_state_groups", "state_groups"], + "artifact_inspector.state_config", + ); + + const activeStateGroups = normalizeStringSet( + value.active_state_groups, + "artifact_inspector.active_state_groups", + ); + const unexpectedActiveGroups = activeStateGroups.filter( + (groupId) => !ARTIFACT_INSPECTOR_STATE_GROUP_IDS.includes(groupId), + ); + if (unexpectedActiveGroups.length > 0 || !activeStateGroups.includes("core")) { + throw authorityError( + "active_state_groups must contain core and only canonical conditional groups.", + { + field: "artifact_inspector.active_state_groups", + unexpected: unexpectedActiveGroups, + missing: activeStateGroups.includes("core") ? [] : ["core"], + diagnostic_code: "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }, + ); + } + + requirePlainObject(value.state_groups, "artifact_inspector.state_groups"); + assertOnlyKeys( + value.state_groups, + ARTIFACT_INSPECTOR_STATE_GROUP_IDS, + "artifact_inspector.state_groups", + ); + for (const groupId of ARTIFACT_INSPECTOR_STATE_GROUP_IDS) { + const states = normalizeStringSet( + value.state_groups[groupId], + `artifact_inspector.state_groups.${groupId}`, + ); + assertExactSet( + states, + ARTIFACT_INSPECTOR_CANONICAL_STATE_GROUPS[groupId], + `artifact_inspector.state_groups.${groupId}`, + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + ); + } + + return { + active_state_groups: ARTIFACT_INSPECTOR_STATE_GROUP_IDS.filter((groupId) => + activeStateGroups.includes(groupId), + ), + state_groups: cloneStateGroups(), + }; +} + +export function normalizeArtifactInspectorStateConfig(value, options = {}) { + try { + return normalizeArtifactInspectorStateConfigUnchecked(value, options); + } catch (error) { + if (error?.code === "invalid_artifact_inspector_authority_contract") { + error.details = { + ...(isPlainObject(error.details) ? error.details : {}), + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }; + } + throw error; + } +} + +function normalizeArtifactInspectorContract(value) { + requirePlainObject(value, "artifact_inspector"); + assertOnlyKeys( + value, + [ + "registry_id", + "registry_version", + "surface_type", + "workflow_profile", + "frontend_surface_profile", + "topology_kind", + "active_state_groups", + "state_groups", + "trusted_runtime_evidence_required", + "external_artifact_review_status", + ], + "artifact_inspector", + ); + + const expected = { + registry_id: "artifact_inspector", + registry_version: "1.0.0", + surface_type: "artifact_inspector", + workflow_profile: "artifact-inspector-ui", + frontend_surface_profile: "judgmentkit.artifact-inspector.v1", + topology_kind: "artifact_centered", + }; + for (const [field, expectedValue] of Object.entries(expected)) { + const observed = requiredString(value[field], `artifact_inspector.${field}`); + if (observed !== expectedValue) { + throw authorityError(`artifact_inspector.${field} is not canonical.`, { + field: `artifact_inspector.${field}`, + expected: expectedValue, + observed, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + }); + } + } + if (value.trusted_runtime_evidence_required !== true) { + throw authorityError( + "artifact_inspector.trusted_runtime_evidence_required must be true.", + { + field: "artifact_inspector.trusted_runtime_evidence_required", + observed: value.trusted_runtime_evidence_required, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_TRUSTED_RUNTIME_EVIDENCE_MISSING", + }, + ); + } + if (value.external_artifact_review_status !== "external_not_reviewed") { + throw authorityError( + "artifact_inspector.external_artifact_review_status must remain external_not_reviewed.", + { + field: "artifact_inspector.external_artifact_review_status", + expected: "external_not_reviewed", + observed: value.external_artifact_review_status, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_EXTERNAL_AUTHORITY_OVERCLAIM", + }, + ); + } + + const stateConfig = normalizeArtifactInspectorStateConfig( + { + active_state_groups: value.active_state_groups, + state_groups: value.state_groups, + }, + { required: true }, + ); + + return { + ...expected, + ...stateConfig, + trusted_runtime_evidence_required: true, + external_artifact_review_status: "external_not_reviewed", + }; +} + +export function validateArtifactInspectorAuthorityContract( + implementationContract = {}, +) { + requirePlainObject(implementationContract, "implementation_contract"); + const hasScopes = hasOwn(implementationContract, "design_system_scopes"); + const hasBoundaries = hasOwn(implementationContract, "boundary_contracts"); + const hasArtifactInspector = hasOwn(implementationContract, "artifact_inspector"); + + if (!hasScopes && !hasBoundaries && !hasArtifactInspector) { + return { + active: false, + design_system_scopes: [], + boundary_contracts: [], + artifact_inspector: null, + }; + } + + if (!hasScopes || !hasBoundaries || !hasArtifactInspector) { + throw authorityError( + "Artifact Inspector authority is partial; scopes, boundaries, and artifact_inspector are all required when any one is declared.", + { + field: "implementation_contract", + missing: [ + ...(hasScopes ? [] : ["design_system_scopes"]), + ...(hasBoundaries ? [] : ["boundary_contracts"]), + ...(hasArtifactInspector ? [] : ["artifact_inspector"]), + ], + diagnostic_code: !hasScopes + ? "JK_ARTIFACT_INSPECTOR_CHROME_SCOPE_MISSING" + : !hasBoundaries + ? "JK_ARTIFACT_INSPECTOR_BOUNDARY_EVENT_UNDECLARED" + : "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + }, + ); + } + + const designSystemScopes = normalizeArtifactInspectorScopes( + implementationContract.design_system_scopes, + { required: true }, + ); + const boundaryContracts = normalizeArtifactInspectorBoundaryContracts( + implementationContract.boundary_contracts, + { scopes: designSystemScopes, required: true }, + ); + const artifactInspector = normalizeArtifactInspectorContract( + implementationContract.artifact_inspector, + ); + + return { + active: true, + design_system_scopes: designSystemScopes, + boundary_contracts: boundaryContracts, + artifact_inspector: artifactInspector, + }; +} + +export function createArtifactInspectorFinding({ + code, + severity = "fail", + check = "artifact_inspector_authority", + message, + evidence = {}, + repair_instruction, +}) { + if (!DIAGNOSTIC_CODE_SET.has(code)) { + throw authorityError(`Unknown Artifact Inspector diagnostic code: ${code}.`, { + field: "finding.code", + observed: code, + }); + } + if (!["fail", "warn"].includes(severity)) { + throw authorityError("Artifact Inspector finding severity must be fail or warn.", { + field: "finding.severity", + observed: severity, + }); + } + if (!isPlainObject(evidence)) { + throw authorityError("Artifact Inspector finding evidence must be an object.", { + field: "finding.evidence", + observed: evidence, + }); + } + + const defaults = DIAGNOSTIC_DEFAULTS[code]; + return { + severity, + check: requiredString(check, "finding.check"), + code, + message: message ? requiredString(message, "finding.message") : defaults.message, + evidence: { ...evidence }, + repair_instruction: repair_instruction + ? requiredString(repair_instruction, "finding.repair_instruction") + : defaults.repair_instruction, + }; +} + +function stableFindings(findings) { + return [...findings].sort((left, right) => { + const codeOrder = + (DIAGNOSTIC_ORDER.get(left.code) ?? Number.MAX_SAFE_INTEGER) - + (DIAGNOSTIC_ORDER.get(right.code) ?? Number.MAX_SAFE_INTEGER); + if (codeOrder !== 0) return codeOrder; + const checkOrder = left.check.localeCompare(right.check); + if (checkOrder !== 0) return checkOrder; + return left.message.localeCompare(right.message); + }); +} + +function missingRuntimeFinding(evidence = {}) { + return createArtifactInspectorFinding({ + code: "JK_ARTIFACT_INSPECTOR_TRUSTED_RUNTIME_EVIDENCE_MISSING", + evidence, + }); +} + +function baseDesignSystemReview() { + return { + inspector_chrome: "review_required", + inspection_overlay: "review_required", + primary_artifact: "external_not_reviewed", + boundary_contract: "review_required", + }; +} + +const DEFERRED_INTERACTIVE_ATTESTATION_OBSERVATIONS = Object.freeze([ + "exact_region_and_authority_map", + "bidirectional_style_isolation", + "artifact_fingerprint_for_each_chrome_state_transition", + "pointer_touch_keyboard_and_assistive_technology_crossings", + "focus_order_entry_announcements_and_return", + "overlay_obstruction_occlusion_and_responsive_safe_areas", + "semantic_target_drift_reanchoring_and_stale_handling", + "native_action_precedence_outside_inspection_mode", + "required_state_by_viewport_matrix", + "opaque_candidate_and_contract_bound_attestation", +]); + +// This requirement review is deliberately non-accepting. The current release +// defines the Artifact Inspector authority contract but has no trusted +// interactive-attestation producer or verifier. Extra caller arguments are +// ignored, so candidate-authored or pass-shaped evidence cannot alter the +// result. +export function reviewArtifactInspectorAuthorityEvidence( + implementationContract = {}, +) { + let authorityContract; + try { + authorityContract = validateArtifactInspectorAuthorityContract( + implementationContract, + ); + } catch (error) { + const code = DIAGNOSTIC_CODE_SET.has(error?.details?.diagnostic_code) + ? error.details.diagnostic_code + : "JK_ARTIFACT_INSPECTOR_TRUSTED_RUNTIME_EVIDENCE_MISSING"; + return { + status: "fail", + applicable: true, + design_system_review: baseDesignSystemReview(), + trusted_runtime_evidence: { + status: "not_evaluated", + producer_available: false, + }, + findings: [ + createArtifactInspectorFinding({ + code, + message: error instanceof Error ? error.message : undefined, + evidence: isPlainObject(error?.details) ? error.details : {}, + }), + ], + }; + } + + if (!authorityContract.active) { + return { + status: "not_applicable", + applicable: false, + design_system_review: {}, + trusted_runtime_evidence: { + status: "not_required", + producer_available: false, + }, + findings: [], + }; + } + + return { + status: "review_required", + applicable: true, + design_system_review: baseDesignSystemReview(), + trusted_runtime_evidence: { + status: "unavailable_in_this_release", + producer_available: false, + candidate_authored_evidence_accepted: false, + static_browser_evidence_accepted: false, + missing_observations: [ + ...DEFERRED_INTERACTIVE_ATTESTATION_OBSERVATIONS, + ], + }, + findings: stableFindings([ + missingRuntimeFinding({ + required_source: "deferred_interactive_attestation", + candidate_authored_evidence_accepted: false, + static_browser_evidence_accepted: false, + missing_observations: [ + ...DEFERRED_INTERACTIVE_ATTESTATION_OBSERVATIONS, + ], + }), + ]), + }; +} diff --git a/src/index.mjs b/src/index.mjs index 0276ea2..9aab92f 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -1,6 +1,11 @@ import fs from "node:fs"; import path from "node:path"; -import { createHash } from "node:crypto"; +import { + createHash, + createHmac, + randomBytes, + timingSafeEqual, +} from "node:crypto"; import { createRequire } from "node:module"; import { fileURLToPath } from "node:url"; @@ -10,10 +15,14 @@ import { LUCIDE_ICON_SOURCE, } from "./lucide-icon-catalog.generated.mjs"; import { - WORKBENCH_SURFACE_PROFILE_ID, - cloneWorkbenchSurfaceProfile, + cloneSurfacePresentationProfile, listSurfacePresentationProfiles, } from "./surface-presentation-profiles.mjs"; +import { + ARTIFACT_INSPECTOR_STATE_GROUP_IDS, + reviewArtifactInspectorAuthorityEvidence, + validateArtifactInspectorAuthorityContract, +} from "./artifact-inspector-authority.mjs"; import { COMPONENT_IMPLEMENTATION_REGISTRY, COMPONENT_RUNTIME_ADAPTER, @@ -26,10 +35,29 @@ import { import { deriveFieldValueTrailingIndicatorSlotObservation } from "./visual-composition-observation.mjs"; export { + ARTIFACT_INSPECTOR_SURFACE_PROFILE, + ARTIFACT_INSPECTOR_SURFACE_PROFILE_ID, WORKBENCH_SURFACE_PROFILE, WORKBENCH_SURFACE_PROFILE_ID, + cloneArtifactInspectorSurfaceProfile, + cloneSurfacePresentationProfile, + cloneWorkbenchSurfaceProfile, + getSurfacePresentationProfile, listSurfacePresentationProfiles, } from "./surface-presentation-profiles.mjs"; +export { + ARTIFACT_INSPECTOR_CANONICAL_BOUNDARY_CONTRACTS, + ARTIFACT_INSPECTOR_CANONICAL_SCOPES, + ARTIFACT_INSPECTOR_CANONICAL_STATE_GROUPS, + ARTIFACT_INSPECTOR_DIAGNOSTIC_CODES, + ARTIFACT_INSPECTOR_SCOPE_IDS, + ARTIFACT_INSPECTOR_STATE_GROUP_IDS, + createArtifactInspectorFinding, + normalizeArtifactInspectorBoundaryContracts, + normalizeArtifactInspectorScopes, + normalizeArtifactInspectorStateConfig, + validateArtifactInspectorAuthorityContract, +} from "./artifact-inspector-authority.mjs"; export { COMPONENT_IMPLEMENTATION_REGISTRY, COMPONENT_RUNTIME_ADAPTER, @@ -57,9 +85,10 @@ const KERNEL_SCHEMA_PATH = path.resolve( ); let validateVisualCompositionPolicySchema; const trustedVisualCompositionEvidence = new WeakMap(); +const artifactInspectorReviewIntegrityKey = randomBytes(32); const DEFAULT_WORKFLOW_ID = "workflow.ai-ui-generation"; const OPERATOR_REVIEW_PROFILE_ID = "operator-review-ui"; -const SURFACE_TYPE_IDS = [ +const LEGACY_SURFACE_TYPE_IDS = [ "marketing", "workbench", "operator_review", @@ -69,7 +98,7 @@ const SURFACE_TYPE_IDS = [ "setup_debug_tool", "conversation", ]; -const WORKFLOW_TOPOLOGY_IDS = [ +const LEGACY_WORKFLOW_TOPOLOGY_IDS = [ "workspace", "multi_surface", "staged_flow", @@ -77,6 +106,29 @@ const WORKFLOW_TOPOLOGY_IDS = [ "report", "conversation", ]; +const DEFAULT_ARTIFACT_INSPECTOR_SURFACE_TYPE_ID = "artifact_inspector"; +const DEFAULT_ARTIFACT_INSPECTOR_WORKFLOW_PROFILE_ID = "artifact-inspector-ui"; +const DEFAULT_ARTIFACT_INSPECTOR_TOPOLOGY_KIND = "artifact_centered"; +const DEFAULT_ARTIFACT_INSPECTOR_MANDATORY_EVIDENCE_IDS = [ + "rendered_artifact_is_primary", + "locus_selection_required", + "support_context_is_locus_relative", +]; +const DEFAULT_ARTIFACT_INSPECTOR_POSITIVE_EVIDENCE_IDS = [ + ...DEFAULT_ARTIFACT_INSPECTOR_MANDATORY_EVIDENCE_IDS, + "completion_is_artifact_local", + "direct_or_spatial_interaction_required", + "external_artifact_visual_authority", +]; +const DEFAULT_ARTIFACT_INSPECTOR_EXCLUSION_EVIDENCE_IDS = [ + "queue_or_case_is_primary", + "many_items_are_primary", + "open_ended_creation_is_primary", + "conversation_turns_are_primary", + "linear_reading_is_completion", + "monitoring_is_completion", + "configuration_is_completion", +]; export class JudgmentKitInputError extends Error { constructor(message, options = {}) { @@ -98,18 +150,18 @@ export function loadActivityContract(contractPath = DEFAULT_CONTRACT_PATH) { } function getContractWorkflowId(contract) { - return contract.workflow?.id ?? DEFAULT_WORKFLOW_ID; + return contract?.workflow?.id ?? DEFAULT_WORKFLOW_ID; } function getWorkflowTopologyPolicy(contract) { - const policy = contract.workflow?.topology_policy; + const policy = contract?.workflow?.topology_policy; if (isPlainObject(policy)) { return policy; } return { - allowed_topologies: WORKFLOW_TOPOLOGY_IDS, + allowed_topologies: LEGACY_WORKFLOW_TOPOLOGY_IDS, preferred_default: "workspace", work_units_guidance: [ "Name domain work units without implying a numbered sequence.", @@ -126,16 +178,140 @@ function getWorkflowTopologyPolicy(contract) { }; } +function getArtifactInspectorModel(contract) { + const model = contract?.interaction_models?.artifact_inspector; + + return isPlainObject(model) ? model : null; +} + +function getArtifactInspectorIdentifiers(contract) { + const identifiers = getArtifactInspectorModel(contract)?.canonical_identifiers ?? {}; + + return { + surface_type: + optionalString(identifiers.surface_type) || + DEFAULT_ARTIFACT_INSPECTOR_SURFACE_TYPE_ID, + workflow_profile: + optionalString(identifiers.workflow_profile) || + DEFAULT_ARTIFACT_INSPECTOR_WORKFLOW_PROFILE_ID, + frontend_surface_profile: + optionalString(identifiers.frontend_surface_profile) || + "judgmentkit.artifact-inspector.v1", + topology_kind: + optionalString(identifiers.topology_kind) || + DEFAULT_ARTIFACT_INSPECTOR_TOPOLOGY_KIND, + }; +} + +function hasArtifactInspectorContract(contract) { + const identifiers = getArtifactInspectorIdentifiers(contract); + + return Boolean( + getArtifactInspectorModel(contract) || + contract?.surface_types?.[identifiers.surface_type] || + contract?.profiles?.[identifiers.workflow_profile] || + toStringArray(contract?.workflow?.topology_policy?.allowed_topologies).includes( + identifiers.topology_kind, + ), + ); +} + +function getAllowedWorkflowTopologyIds(contract) { + const configured = toStringArray( + getWorkflowTopologyPolicy(contract).allowed_topologies, + ); + const allowed = configured.length > 0 + ? configured + : [...LEGACY_WORKFLOW_TOPOLOGY_IDS]; + + if (hasArtifactInspectorContract(contract)) { + allowed.push(getArtifactInspectorIdentifiers(contract).topology_kind); + } + + return unique(allowed); +} + function getUiWorkflowProfiles(contract) { - return isPlainObject(contract.profiles) ? contract.profiles : {}; + const profiles = isPlainObject(contract?.profiles) ? contract.profiles : {}; + const model = getArtifactInspectorModel(contract); + + if (!model) { + return profiles; + } + + const identifiers = getArtifactInspectorIdentifiers(contract); + + if (profiles[identifiers.workflow_profile]) { + return profiles; + } + + return { + ...profiles, + [identifiers.workflow_profile]: { + pattern_id: "artifact-inspector", + model_id: optionalString(model.id) || identifiers.surface_type, + model_version: optionalString(model.version) || "1.0.0", + applies_when_most_true: toStringArray( + model.activity_evidence?.positive, + ), + do_not_use_when: toStringArray(model.activity_evidence?.exclusions), + guardrails: [], + review_criteria: [ + "The rendered artifact remains primary while locus-relative context and actions stay attached to it.", + ], + test_scenarios: [], + topology: isPlainObject(model.topology) + ? cloneWorkflowStructuredValue(model.topology) + : {}, + work_units: Array.isArray(model.work_units) + ? cloneWorkflowStructuredValue(model.work_units) + : [], + target_model: isPlainObject(model.target_model) + ? cloneWorkflowStructuredValue(model.target_model) + : {}, + composition_variants: Array.isArray(model.composition_variants) + ? cloneWorkflowStructuredValue(model.composition_variants) + : [], + state_groups: isPlainObject(model.state_groups) + ? cloneWorkflowStructuredValue(model.state_groups) + : {}, + }, + }; } function getSurfaceTypes(contract) { - if (isPlainObject(contract.surface_types)) { - return contract.surface_types; + const surfaceTypes = isPlainObject(contract?.surface_types) + ? contract.surface_types + : {}; + const model = getArtifactInspectorModel(contract); + + if (!model) { + return surfaceTypes; + } + + const identifiers = getArtifactInspectorIdentifiers(contract); + + if (surfaceTypes[identifiers.surface_type]) { + return surfaceTypes; } - return {}; + return { + ...surfaceTypes, + [identifiers.surface_type]: { + label: "Artifact inspector", + purpose: + "Inspect one rendered artifact in place, act on a semantic locus, and verify the local result.", + applies_when_most_true: [ + "One rendered artifact is the primary object.", + "The participant must select a semantic locus within the artifact.", + "Supporting context is meaningful only in relation to that locus.", + ], + do_not_use_when: [ + "A queue, case list, record set, or many-item comparison is primary.", + "Open-ended creation, conversation, monitoring, reading, or configuration is completion.", + ], + }, + }; } function normalizeOptionalSurfaceType(surfaceType) { @@ -164,7 +340,11 @@ function normalizeSurfaceProfileRequest(request) { } const normalized = request.trim(); - const allowed = ["auto", "none", WORKBENCH_SURFACE_PROFILE_ID]; + const allowed = [ + "auto", + "none", + ...listSurfacePresentationProfiles().map((entry) => entry.id), + ]; if (!allowed.includes(normalized)) { throw new JudgmentKitInputError( @@ -197,33 +377,40 @@ function resolveSurfacePresentationProfile({ } const normalizedSurfaceType = normalizeOptionalSurfaceType(surfaceType); - const explicitProfileRequest = - normalizedRequest === WORKBENCH_SURFACE_PROFILE_ID; + const explicitProfileRequest = !["auto", "none"].includes(normalizedRequest); + const explicitlyRequestedProfile = explicitProfileRequest + ? cloneSurfacePresentationProfile(normalizedRequest) + : null; + const eligibleProfile = explicitProfileRequest + ? explicitlyRequestedProfile + : listSurfacePresentationProfiles().find( + (entry) => entry.surface_type === normalizedSurfaceType, + ) ?? null; if ( explicitProfileRequest && - normalizedSurfaceType !== "workbench" + explicitlyRequestedProfile?.surface_type !== normalizedSurfaceType ) { throw new JudgmentKitInputError( - "The Workbench surface profile requires a selected surface_type of \"workbench\".", + `The ${explicitlyRequestedProfile?.name ?? "requested"} surface profile requires a selected surface_type of \"${explicitlyRequestedProfile?.surface_type ?? "unknown"}\".`, { details: { surface_profile: normalizedRequest, selected_surface_type: normalizedSurfaceType, - required_surface_type: "workbench", + required_surface_type: explicitlyRequestedProfile?.surface_type ?? null, }, }, ); } - if (normalizedSurfaceType !== "workbench") { + if (!eligibleProfile) { return null; } if (designSystemMode !== "judgmentkit_default") { if (explicitProfileRequest) { throw new JudgmentKitInputError( - "The JudgmentKit Workbench surface profile is unavailable when an external design system is active.", + "JudgmentKit surface profiles are unavailable when an external design system is active.", { details: { surface_profile: normalizedRequest, @@ -239,12 +426,16 @@ function resolveSurfacePresentationProfile({ const normalizedConfidence = typeof confidence === "string" ? confidence.trim().toLowerCase() : ""; - const acceptedConfidence = new Set(["medium", "high", "provided"]); + const acceptedConfidence = new Set( + Array.isArray(eligibleProfile.activation?.accepted_confidence) + ? eligibleProfile.activation.accepted_confidence + : ["medium", "high", "provided"], + ); if (!acceptedConfidence.has(normalizedConfidence)) { if (explicitProfileRequest) { throw new JudgmentKitInputError( - "The Workbench surface profile requires an explicitly selected or sufficiently grounded Workbench surface.", + `The ${eligibleProfile.name} surface profile requires an explicitly selected or sufficiently grounded ${eligibleProfile.surface_type} surface.`, { details: { surface_profile: normalizedRequest, @@ -261,7 +452,7 @@ function resolveSurfacePresentationProfile({ } return { - ...cloneWorkbenchSurfaceProfile(), + ...cloneSurfacePresentationProfile(eligibleProfile.id), selection: { request: normalizedRequest, surface_type_source: surfaceTypeSource || "unspecified", @@ -340,6 +531,46 @@ function normalizeText(value) { return value.toLowerCase().replace(/\s+/g, " ").trim(); } +function canonicalIntegrityValue(value) { + if (Array.isArray(value)) { + return value.map((entry) => canonicalIntegrityValue(entry)); + } + + if (isPlainObject(value)) { + return Object.fromEntries( + Object.keys(value) + .sort() + .filter((key) => value[key] !== undefined) + .map((key) => [key, canonicalIntegrityValue(value[key])]), + ); + } + + return value === undefined ? null : value; +} + +function createArtifactInspectorIntegritySeal(kind, payload) { + return createHmac("sha256", artifactInspectorReviewIntegrityKey) + .update(kind) + .update("\0") + .update(JSON.stringify(canonicalIntegrityValue(payload))) + .digest("base64url"); +} + +function artifactInspectorIntegritySealMatches(kind, payload, suppliedSeal) { + if (typeof suppliedSeal !== "string" || suppliedSeal.length === 0) { + return false; + } + + const expected = Buffer.from( + createArtifactInspectorIntegritySeal(kind, payload), + ); + const observed = Buffer.from(suppliedSeal); + return ( + expected.length === observed.length && + timingSafeEqual(expected, observed) + ); +} + function toGlobalPattern(pattern) { return pattern.flags.includes("g") ? pattern @@ -767,8 +998,7 @@ export function recommendUiWorkflowProfiles(input, options = {}) { matched_triggers: matchedTriggers.map((entry) => entry.id), matched_exclusions: matchedExclusions.map((entry) => entry.id), }; - - return { + const basePacket = { version: contract.version, contract_id: contract.id, workflow_id: getContractWorkflowId(contract), @@ -783,12 +1013,316 @@ export function recommendUiWorkflowProfiles(input, options = {}) { }, }, }; + const artifactEvidence = buildArtifactInspectorEvidence(input, contract); + + if (!artifactEvidence.should_include) { + return basePacket; + } + + const identifiers = getArtifactInspectorIdentifiers(contract); + const artifactProfile = resolveUiWorkflowGuidanceProfile( + contract, + identifiers.workflow_profile, + ); + const artifactStatus = artifactEvidence.conflict + ? "review_required" + : artifactEvidence.mandatory_satisfied + ? "recommended" + : "not_recommended"; + const artifactSummary = { + profile_id: artifactProfile.profile_id, + workflow_id: artifactProfile.workflow_id, + pattern_id: artifactProfile.pattern_id, + model_id: + optionalString(artifactProfile.model_id) || artifactEvidence.model_id, + model_version: + optionalString(artifactProfile.model_version) || artifactEvidence.model_version, + status: artifactStatus, + trigger_threshold: artifactEvidence.mandatory_evidence_ids.length, + trigger_match_count: artifactEvidence.matched_mandatory_evidence.length, + matched_triggers: artifactEvidence.matched_positive_evidence, + matched_exclusions: artifactEvidence.matched_exclusion_evidence, + }; + + return { + ...basePacket, + recommended_profile_ids: + artifactStatus === "recommended" + ? [artifactProfile.profile_id] + : basePacket.recommended_profile_ids, + ...(artifactStatus === "review_required" + ? { review_required_profile_ids: [artifactProfile.profile_id] } + : {}), + recommendations: [ + ...basePacket.recommendations, + artifactSummary, + ], + evidence: { + ...basePacket.evidence, + [artifactProfile.profile_id]: { + mandatory_evidence_ids: artifactEvidence.mandatory_evidence_ids, + positives: artifactEvidence.positives, + exclusions: artifactEvidence.exclusions, + matched_mandatory_evidence: + artifactEvidence.matched_mandatory_evidence, + missing_mandatory_evidence: + artifactEvidence.missing_mandatory_evidence, + matched_exclusion_evidence: + artifactEvidence.matched_exclusion_evidence, + conflict: artifactEvidence.conflict, + }, + }, + }; } function surfaceEvidence(id, label, matched, reason) { return matchedEvidence(id, label, matched, reason); } +function hasConversationTurnActivity(input) { + const text = normalizeText(input); + const hasConversationObject = hasAffirmedAny(text, [ + /\b(?:chat|conversation|message exchange|message thread|live chat|assistant exchange)\b/, + /\bthread\b/, + ]); + const hasTurnBehavior = hasAffirmedAny(text, [ + /\b(?:message turns?|messages?|composer|send(?:s|ing)?|reply|replies|replying|respond|responds|responding|back and forth)\b/, + /\bask(?:s|ing)? (?:a |the )?(?:question|questions)\b/, + /\b(?:participant|participants|people|teammates?|agents?|customers?|users?)\s+(?:exchange|reply|respond|message)\b/, + ]); + const hasExchangeContinuity = hasAffirmedAny(text, [ + /\b(?:open-ended|open ended|continue|continues|continuing|keep(?:s|ing)? (?:the )?(?:thread|conversation|chat)|close(?:s|d|ing)? (?:the )?(?:thread|conversation|chat)|response continuity|conversation continuity|exchange continuity)\b/, + /\b(?:message exchange|back and forth)\b/, + ]); + + return hasConversationObject && hasTurnBehavior && hasExchangeContinuity; +} + +function artifactInspectorEvidenceDefinition(input) { + const text = normalizeText(input); + const explicitStructuredCollectionPrimary = hasAffirmedAny(text, [ + /\b(?:structured\s+)?(?:intake|submission|record-entry|record entry|data-entry|data entry)?\s*form\s+(?:is|remains|stays)\s+(?:the\s+)?primary\b/, + /\bprimary (?:activity|work|surface|object)\s+(?:is|remains|stays)\s+(?:required\s+)?(?:field entry|data entry|record entry|structured collection|intake|form completion|validation|submission)\b/, + /\bcompletion\s+(?:is|means)\s+(?:required\s+)?(?:field entry|data entry|record entry|structured collection|form validation|validation and submission|submitting (?:the\s+)?(?:form|record))\b/, + ]); + const explicitRenderedArtifactPrimarySignal = hasAffirmedAny(text, [ + /\b(?:artifact|interface|document|composition|diagram|result|prototype|screen)\s+(?:that\s+)?(?:is|remains|stays|must remain|must stay)\s+(?:visible\s+and\s+)?(?:the\s+)?(?:primary|central|dominant)\b/, + /\bprimary (?:object|artifact)\s+(?:is|remains|stays|must remain|must stay)\s+(?:an?\s+|the\s+)?(?:rendered\s+)?(?:artifact|interface|document|composition|diagram|result|prototype|screen)\b/, + ]); + const explicitRenderedArtifactSecondarySignal = hasAffirmedAny(text, [ + /\b(?:a|an|the|one)\s+(?:secondary|supporting)\s+(?:rendered\s+)?(?:artifact|interface|document|composition|diagram|result|prototype|screen)\b/, + ]); + const queueOrCaseIsPrimary = hasAffirmedAny(text, [ + /\b(?:queue|case list|record set|work queue|review queue)\s+(?:is|remains|stays|as)\s+(?:the\s+)?primary\b/, + /\bprimary (?:object|work|surface)\s+(?:is|remains|stays)\s+(?:a\s+|the\s+)?(?:queue|case|case list|record set|work queue)\b/, + /\b(?:work through|review|triage|handle)\s+(?:a\s+|the\s+)?(?:queue|case list|record set)\b/, + ]); + const renderedArtifactIsDetailLocal = hasAffirmedAny(text, [ + /\b(?:artifact|interface|document|composition|diagram|result|prototype|screen)\s+(?:that\s+)?(?:is|remains|stays|must remain|must stay)\s+(?:visible\s+and\s+)?(?:the\s+)?(?:primary|central|dominant)\b[^.]{0,100}\b(?:inside|within|in)\s+(?:the\s+)?selected[- ]case detail\b/, + /\b(?:inside|within|in)\s+(?:the\s+)?selected[- ]case detail\b[^.]{0,100}\b(?:artifact|interface|document|composition|diagram|result|prototype|screen)\s+(?:that\s+)?(?:is|remains|stays|must remain|must stay)\s+(?:visible\s+and\s+)?(?:the\s+)?(?:primary|central|dominant)\b/, + /\b(?:artifact|interface|document|composition|diagram|result|prototype|screen)\s+(?:that\s+)?(?:is|remains|stays|must remain|must stay)\s+(?:visible\s+and\s+)?(?:the\s+)?(?:primary|central|dominant)\b[^.]{0,100}\b(?:inside|within|in)\s+(?:the\s+)?detail (?:pane|panel|view) for (?:the\s+)?selected case\b/, + /\b(?:inside|within|in)\s+(?:the\s+)?detail (?:pane|panel|view) for (?:the\s+)?selected case\b[^.]{0,100}\b(?:artifact|interface|document|composition|diagram|result|prototype|screen)\s+(?:that\s+)?(?:is|remains|stays|must remain|must stay)\s+(?:visible\s+and\s+)?(?:the\s+)?(?:primary|central|dominant)\b/, + ]); + const renderedArtifactIsPrimary = + !explicitStructuredCollectionPrimary && + explicitRenderedArtifactPrimarySignal && + !explicitRenderedArtifactSecondarySignal && + !(queueOrCaseIsPrimary && renderedArtifactIsDetailLocal); + const locusSelectionRequired = hasAffirmedAny(text, [ + /\b(?:select|selects|selecting|focus|focuses|focusing|mark|marks|marking|inspect|inspects|inspecting|activate|activates|activating|choose|chooses|choosing|target|targets|targeting)\s+(?:an?\s+|the\s+|one\s+|a specific\s+|specific\s+|that\s+|this\s+)?(?:artifact\s+)?(?:locus|control|element|passage|text range|range|region|node|point|object|feature|part)\b/, + /\b(?:locus|control|element|passage|text range|region|node|point|feature)\s+(?:selection|is selected|must be selected|needs? to be selected)\b/, + /\bselect(?:ion)?\s+(?:within|inside|on)\s+(?:an?\s+|the\s+)?(?:artifact|interface|document|composition|diagram|result|prototype|screen)\b/, + ]); + const supportContextIsLocusRelative = hasAffirmedAny(text, [ + /\b(?:context|evidence|authority|rule|source|observation|correction|comparison|diagnostic|action|feedback|reason|receipt|support)\b[^.]{0,120}\b(?:attach(?:es|ed|ing)?|relat(?:e|es|ed|ing)|link(?:s|ed|ing)?|anchor(?:s|ed|ing)?|connect(?:s|ed|ing)?|belong(?:s|ed|ing)?|apply|applies|applied)\b[^.]{0,80}\b(?:locus|selected (?:control|element|passage|range|region|node|point|object|feature|part)|that (?:control|element|passage|range|region|node|point|object|feature|part|location))\b/, + /\b(?:bring|brings|bringing|attach|attaches|attaching|relate|relates|relating|show|shows|showing|reveal|reveals|revealing)\b[^.]{0,100}\b(?:context|evidence|authority|rule|source|observation|correction|comparison|diagnostic|action|feedback|reason|receipt|support)\b[^.]{0,80}\b(?:to|at|beside|for|in relation to)\s+(?:the\s+|that\s+|this\s+|selected\s+|active\s+)?(?:locus|control|element|passage|range|region|node|point|object|feature|part|location)\b/, + /\b(?:context|evidence|authority|rule|source|observation|correction|comparison|diagnostic|action|feedback|reason|receipt|support)\s+(?:is|only becomes|becomes|remains)\s+(?:meaningful|relevant|available|visible)\s+(?:in relation to|for|at|beside)\s+(?:the\s+|that\s+|this\s+|selected\s+|active\s+)?(?:locus|control|element|passage|range|region|node|point|object|feature|part|location)\b/, + ]); + const completionIsArtifactLocal = hasAffirmedAny(text, [ + /\b(?:completion|result|resulting state|verified state|receipt|feedback|outcome)\b[^.]{0,100}\b(?:on|beside|next to|attached to|at|within)\s+(?:the\s+|that\s+|this\s+|selected\s+|active\s+)?(?:artifact|locus|control|element|passage|range|region|node|point|object|feature|part|location)\b/, + /\b(?:verify|verifies|verifying|confirm|confirms|confirming|show|shows|showing)\s+(?:the\s+|a\s+)?(?:local\s+)?(?:result|state|change|receipt|outcome)\s+(?:on|beside|next to|at|within)\s+(?:the\s+|that\s+|this\s+|selected\s+|active\s+)?(?:artifact|locus|control|element|passage|range|region|node|point|object|feature|part|location)\b/, + /\bartifact-local (?:completion|result|state|feedback|receipt)\b/, + ]); + const directOrSpatialInteractionRequired = hasAffirmedAny(text, [ + /\b(?:direct manipulation|directly on|in place|spatial interaction|select-then-target|drag|touch|tap|pointer|keyboard)\b/, + /\b(?:select|mark|target|pin|connect|attach|preview)\b[^.]{0,80}\b(?:locus|control|element|passage|range|region|node|point|artifact)\b/, + ]); + const externalArtifactVisualAuthority = hasAffirmedAny(text, [ + /\b(?:external|independent|separate|declared)\s+(?:artifact\s+)?(?:visual authority|design system|styling authority|style authority)\b/, + /\b(?:artifact|interface|document|composition|diagram)\s+(?:keeps|retains|uses|has|owns)\s+(?:its\s+|an?\s+)?(?:own|independent|external|separate)\s+(?:visual language|design system|styling|style)\b/, + /\b(?:who|which system)\s+owns\s+(?:the\s+)?artifact(?:'s)?\s+(?:styling|visual design|design system)\b/, + ]); + const manyItemsArePrimary = hasAffirmedAny(text, [ + /\b(?:many|multiple|several|a set of|a list of|a queue of|side by side)\b[^.]{0,60}\b(?:artifacts?|items?|cases?|records?|objects?|documents?|interfaces?|results?)\b/, + /\b(?:compare|review|inspect)\s+(?:many|multiple|several|a set of|a list of)\b[^.]{0,60}\b(?:artifacts?|items?|cases?|records?|objects?|documents?|interfaces?|results?)\b/, + ]); + const openEndedCreationIsPrimary = hasAffirmedAny(text, [ + /\b(?:primarily|primary activity is|activity is)\s+(?:freely\s+|open-endedly\s+)?(?:creating|authoring|drawing|designing|composing|editing)\b/, + /\b(?:open-ended|open ended|freeform|free-form)\s+(?:creation|authoring|drawing|design|composition|editing)\b/, + /\b(?:create|author|draw|design|compose|edit)\s+(?:the\s+)?artifact\s+freely\b/, + ]); + const linearReadingIsCompletion = hasAffirmedAny(text, [ + /\b(?:linear reading|reading only|read-only report|only for reading)\b/, + /\bcompletion\s+(?:is|means)\s+(?:reading|understanding|citing|sharing)\b/, + /\b(?:primary activity is|activity is)\s+(?:reading|understanding|citing|sharing)\s+(?:a\s+|the\s+)?(?:document|report|memo|article|guide)\b/, + ]); + const monitoringIsCompletion = hasAffirmedAny(text, [ + /\bcompletion\s+(?:is|means)\s+(?:monitoring|knowing current status|status awareness|tracking trends)\b/, + /\b(?:primary activity is|activity is)\s+(?:monitoring|tracking|watching)\b/, + /\b(?:dashboard|monitor)\s+(?:is|remains|stays)\s+(?:the\s+)?primary\b/, + ]); + const configurationIsCompletion = hasAffirmedAny(text, [ + /\bcompletion\s+(?:is|means)\s+(?:a\s+)?(?:valid setup|configuration|configured integration|working integration)\b/, + /\b(?:primary activity is|activity is)\s+(?:setup|configuration|configuring|debugging|troubleshooting)\b/, + /\b(?:setup|configuration|debugging)\s+(?:is|remains|stays)\s+(?:the\s+)?primary\b/, + ]); + + return { + rendered_artifact_is_primary: surfaceEvidence( + "rendered_artifact_is_primary", + "One rendered artifact is the primary object.", + renderedArtifactIsPrimary, + "Looked for one bounded rendered artifact that remains the primary visible object.", + ), + locus_selection_required: surfaceEvidence( + "locus_selection_required", + "The participant must select a semantic locus within the artifact.", + locusSelectionRequired, + "Looked for required selection of a control, element, passage, range, region, node, point, or other artifact locus.", + ), + support_context_is_locus_relative: surfaceEvidence( + "support_context_is_locus_relative", + "Supporting context is meaningful in relation to the selected locus.", + supportContextIsLocusRelative, + "Looked for evidence, authority, corrections, actions, feedback, or receipts attached to the active locus.", + ), + completion_is_artifact_local: surfaceEvidence( + "completion_is_artifact_local", + "Completion is visible on or directly beside the artifact.", + completionIsArtifactLocal, + "Looked for a verified result, state, feedback, or receipt local to the artifact or locus.", + ), + direct_or_spatial_interaction_required: surfaceEvidence( + "direct_or_spatial_interaction_required", + "The activity requires direct or spatial interaction with the artifact.", + directOrSpatialInteractionRequired, + "Looked for in-place selection, targeting, preview, touch, pointer, drag, or keyboard-equivalent interaction.", + ), + external_artifact_visual_authority: surfaceEvidence( + "external_artifact_visual_authority", + "The artifact may retain declared visual authority independent from the inspector chrome.", + externalArtifactVisualAuthority, + "Looked for an external or independent artifact design system, visual language, or styling authority.", + ), + queue_or_case_is_primary: surfaceEvidence( + "queue_or_case_is_primary", + "A queue, case list, or record set is primary.", + queueOrCaseIsPrimary, + "Looked for queue, case-list, record-set, or repeated case work as the primary object.", + ), + many_items_are_primary: surfaceEvidence( + "many_items_are_primary", + "Many items or artifacts are primary.", + manyItemsArePrimary, + "Looked for multiple or side-by-side artifacts, items, cases, records, or results as peers.", + ), + open_ended_creation_is_primary: surfaceEvidence( + "open_ended_creation_is_primary", + "Open-ended creation or editing is primary.", + openEndedCreationIsPrimary, + "Looked for freeform authoring, drawing, designing, composing, or editing as completion.", + ), + conversation_turns_are_primary: surfaceEvidence( + "conversation_turns_are_primary", + "Conversation turns and response continuity are primary.", + hasConversationTurnActivity(text), + "Required a conversation object, message-turn behavior, and exchange continuity; the word thread alone is insufficient.", + ), + linear_reading_is_completion: surfaceEvidence( + "linear_reading_is_completion", + "Linear reading, understanding, citing, or sharing is completion.", + linearReadingIsCompletion, + "Looked for reading-only or linear report completion.", + ), + monitoring_is_completion: surfaceEvidence( + "monitoring_is_completion", + "Monitoring status, trends, or operational health is completion.", + monitoringIsCompletion, + "Looked for monitoring or status awareness as the primary completion.", + ), + configuration_is_completion: surfaceEvidence( + "configuration_is_completion", + "Setup, configuration, or debugging is completion.", + configurationIsCompletion, + "Looked for valid setup, configuration, debugging, or troubleshooting as completion.", + ), + }; +} + +function buildArtifactInspectorEvidence(input, contract) { + const model = getArtifactInspectorModel(contract); + const configuredEvidence = model?.activity_evidence ?? {}; + const mandatoryIds = toStringArray(configuredEvidence.mandatory); + const positiveIds = toStringArray(configuredEvidence.positive); + const exclusionIds = toStringArray(configuredEvidence.exclusions); + const resolvedMandatoryIds = mandatoryIds.length > 0 + ? mandatoryIds + : DEFAULT_ARTIFACT_INSPECTOR_MANDATORY_EVIDENCE_IDS; + const resolvedPositiveIds = positiveIds.length > 0 + ? positiveIds + : DEFAULT_ARTIFACT_INSPECTOR_POSITIVE_EVIDENCE_IDS; + const resolvedExclusionIds = exclusionIds.length > 0 + ? exclusionIds + : DEFAULT_ARTIFACT_INSPECTOR_EXCLUSION_EVIDENCE_IDS; + const definitions = artifactInspectorEvidenceDefinition(input); + const evidenceFor = (id) => definitions[id] ?? surfaceEvidence( + id, + id.replaceAll("_", " "), + false, + `No deterministic detector is registered for ${id}.`, + ); + const positives = resolvedPositiveIds.map(evidenceFor); + const exclusions = resolvedExclusionIds.map(evidenceFor); + const matchedPositiveIds = positives + .filter((entry) => entry.matched) + .map((entry) => entry.id); + const matchedExclusionIds = exclusions + .filter((entry) => entry.matched) + .map((entry) => entry.id); + const matchedMandatoryIds = resolvedMandatoryIds.filter((id) => + matchedPositiveIds.includes(id)); + const missingMandatoryIds = resolvedMandatoryIds.filter((id) => + !matchedPositiveIds.includes(id)); + const mandatorySatisfied = missingMandatoryIds.length === 0; + const explicitInspectorIntent = /\b(?:artifact inspector|artifact inspection|artifact-centered|artifact centered)\b/i.test(input); + const shouldInclude = + hasArtifactInspectorContract(contract) && + (mandatorySatisfied || matchedMandatoryIds.length >= 2 || explicitInspectorIntent); + const conflict = mandatorySatisfied && matchedExclusionIds.length > 0; + + return { + model_id: optionalString(model?.id) || DEFAULT_ARTIFACT_INSPECTOR_SURFACE_TYPE_ID, + model_version: optionalString(model?.version) || "1.0.0", + mandatory_evidence_ids: resolvedMandatoryIds, + matched_mandatory_evidence: matchedMandatoryIds, + missing_mandatory_evidence: missingMandatoryIds, + matched_positive_evidence: matchedPositiveIds, + matched_exclusion_evidence: matchedExclusionIds, + mandatory_satisfied: mandatorySatisfied, + conflict, + should_include: shouldInclude, + status: conflict + ? "review_required" + : mandatorySatisfied + ? "matched" + : shouldInclude + ? "partial" + : "not_matched", + positives, + exclusions, + }; +} + function buildSurfaceTypeInputs(input, activityReview, contract, options = {}) { const reviewCandidate = activityReview?.candidate ?? {}; const activityModel = reviewCandidate.activity_model ?? {}; @@ -842,6 +1376,10 @@ function buildSurfaceTypeInputs(input, activityReview, contract, options = {}) { implementationTermsDetected, { directActionSource }, ); + const artifactInspectorEvidence = buildArtifactInspectorEvidence( + sourceText, + contract, + ); return { source_text: sourceText, @@ -850,6 +1388,7 @@ function buildSurfaceTypeInputs(input, activityReview, contract, options = {}) { normalized: normalizeText(sourceText), implementation_terms_detected: implementationTermsDetected, purpose_evidence: purposeEvidence, + artifact_inspector_evidence: artifactInspectorEvidence, }; } @@ -1133,9 +1672,7 @@ function buildSurfaceTypeScore(surfaceType, inputContext, contract) { hasAffirmedAny(text, [ /\b(?:schema change|prompt template|api endpoint|tool call trace|raw system mechanics|mcp server|json schema)\b/, ])); - const hasConversationPrimary = hasAffirmedAny(text, [ - /\b(?:chat|conversation|thread|message composer|assistant exchange|live chat|open-ended|open ended|reply|respond|back and forth)\b/, - ]); + const hasConversationPrimary = hasConversationTurnActivity(text); const hasReadingOrReportPrimary = hasAffirmedAny(text, [ /\b(?:content page|report|memo|article|doc|docs|documentation|guide|read|reads|reading|understand|understanding|learn|cite|citing|share|sharing|reference|summary|narrative)\b/, @@ -1156,12 +1693,40 @@ function buildSurfaceTypeScore(surfaceType, inputContext, contract) { const hasSetupDebug = hasRawSetupDebugIntent || (hasSetupDebugActivityContext && hasImplementationMachineryCue); - const hasConversation = - hasAffirmedAny(text, [ - /\b(?:chat|conversation|thread|message composer|assistant exchange|live chat|open-ended|open ended)\b/, - ]); + const hasConversation = hasConversationTurnActivity(text); const definitions = getSurfaceTypes(contract); const definition = definitions[surfaceType] ?? {}; + const artifactIdentifiers = getArtifactInspectorIdentifiers(contract); + + if (surfaceType === artifactIdentifiers.surface_type) { + const artifactEvidence = inputContext.artifact_inspector_evidence ?? + buildArtifactInspectorEvidence(inputContext.source_text, contract); + const baseScore = makeSurfaceScore( + surfaceType, + artifactEvidence.positives, + artifactEvidence.exclusions, + definition, + ); + + return { + ...baseScore, + score: artifactEvidence.mandatory_satisfied && !artifactEvidence.conflict + ? Math.max(baseScore.score, artifactEvidence.mandatory_evidence_ids.length) + : 0, + profile_id: artifactIdentifiers.workflow_profile, + profile_status: artifactEvidence.conflict + ? "review_required" + : artifactEvidence.mandatory_satisfied + ? "recommended" + : "not_recommended", + mandatory_evidence_ids: artifactEvidence.mandatory_evidence_ids, + matched_mandatory_evidence: + artifactEvidence.matched_mandatory_evidence, + missing_mandatory_evidence: + artifactEvidence.missing_mandatory_evidence, + routing_conflict: artifactEvidence.conflict, + }; + } if (surfaceType === "marketing") { const triggers = [ @@ -1521,13 +2086,14 @@ function buildSurfaceTypeScore(surfaceType, inputContext, contract) { "thread_is_product_surface", "The thread or message exchange is the product surface.", hasConversation, - "Looked for chat, conversation, thread, message composer, live chat, or open-ended exchange language.", + "Required a conversation object, message-turn behavior, and exchange continuity; the word thread alone is insufficient.", ), surfaceEvidence( "open_ended_exchange", "The activity is open-ended exchange rather than a bounded handoff.", - /\b(?:open-ended|open ended|back and forth|ask questions|respond|reply)\b/.test(text), - "Looked for open-ended exchange language.", + hasConversation && + /\b(?:open-ended|open ended|back and forth|ask questions|respond|reply|continue|continuing)\b/.test(text), + "Looked for open-ended exchange language after confirming message turns and response continuity.", ), ]; const exclusions = [ @@ -1555,6 +2121,7 @@ function buildSurfaceTypeScore(surfaceType, inputContext, contract) { function chooseSurfaceType(scores) { const positivePriority = [ + DEFAULT_ARTIFACT_INSPECTOR_SURFACE_TYPE_ID, "setup_debug_tool", "operator_review", "workbench", @@ -1573,6 +2140,7 @@ function chooseSurfaceType(scores) { "conversation", "marketing", "setup_debug_tool", + DEFAULT_ARTIFACT_INSPECTOR_SURFACE_TYPE_ID, ]; return [...scores].sort((left, right) => { @@ -1621,6 +2189,66 @@ function surfaceConfidence(activityReview, bestScore) { function buildSurfaceImplications(surfaceType) { const implications = { + artifact_inspector: { + interaction_implications: { + primary_structure: + "Persistent artifact, selectable loci, contextual support, local feedback, and artifact-local completion.", + make_easy: [ + "Orient to the artifact", + "Select the locus that matters", + "Inspect locus-relative context", + "Preview and validate locally", + "Verify the result beside the artifact", + ], + make_harder: [ + "Displace the artifact with persistent chrome", + "Detach evidence or actions from the active locus", + "Intercept native artifact interaction without explicit inspection mode", + ], + completion_focus: + "The participant can verify the bounded result on or directly beside the artifact and recover to the last safe state.", + }, + disclosure_implications: { + product_ui_rule: + "Use artifact and domain terms; keep implementation machinery diagnostic while naming visual-authority boundaries only when they affect inspection or audit.", + reveal_implementation_terms: false, + diagnostic_contexts: [ + "auditing", + "debugging", + "explicit source inspection", + "boundary inspection", + ], + }, + frontend_posture: { + density: "artifact-first contextual", + navigation_shape: + "artifact persistent; supporting context revealed from the active locus", + state_coverage: [ + "artifact loading", + "artifact ready", + "no active locus", + "locus selected", + "context loading", + "preview", + "supported", + "invalid or ambiguous", + "stale or unavailable", + "local result", + "recovery", + ], + responsive_expectations: + "Wide and narrow layouts must preserve the artifact, active locus, local feedback, and recovery path without obscuring the inspected target.", + component_families: [ + "artifact viewport", + "locus selection", + "context anchor or tray", + "relation preview", + "local feedback", + "receipt marker", + "back or reset action", + ], + }, + }, marketing: { interaction_implications: { primary_structure: "Audience need, offer, proof, and primary action.", @@ -1804,29 +2432,134 @@ export function recommendSurfaceTypes(input, options = {}) { const inputContext = buildSurfaceTypeInputs(input.trim(), activityReview, contract, { hasExplicitActivityReview, }); - const scores = SURFACE_TYPE_IDS.map((surfaceType) => + const artifactIdentifiers = getArtifactInspectorIdentifiers(contract); + const artifactEvidence = inputContext.artifact_inspector_evidence; + const surfaceTypeIds = [ + ...LEGACY_SURFACE_TYPE_IDS, + ...(artifactEvidence.should_include && + getSurfaceTypes(contract)[artifactIdentifiers.surface_type] + ? [artifactIdentifiers.surface_type] + : []), + ]; + const scores = surfaceTypeIds.map((surfaceType) => buildSurfaceTypeScore(surfaceType, inputContext, contract), ); - const recommended = chooseSurfaceType(scores); - const confidence = surfaceConfidence(activityReview, recommended.score); + const scoredRecommendation = chooseSurfaceType(scores); + const artifactScore = scores.find( + (entry) => entry.surface_type === artifactIdentifiers.surface_type, + ); + const routingConflict = artifactEvidence.conflict + ? { + status: "review_required", + surface_type: artifactIdentifiers.surface_type, + matched_mandatory_evidence: + artifactEvidence.matched_mandatory_evidence, + matched_exclusion_evidence: + artifactEvidence.matched_exclusion_evidence, + conflicting_signals: [ + ...artifactEvidence.matched_mandatory_evidence.map((id) => ({ + kind: "mandatory", + id, + })), + ...artifactEvidence.matched_exclusion_evidence.map((id) => ({ + kind: "exclusion", + id, + })), + ], + competing_surface_types: scores + .filter((entry) => + entry.surface_type !== artifactIdentifiers.surface_type && + (entry.score > 0 || entry.exclusion_match_count > 0)) + .map((entry) => ({ + surface_type: entry.surface_type, + score: entry.score, + matched_triggers: entry.matched_triggers, + matched_exclusions: entry.matched_exclusions, + })), + } + : null; + const recommended = + artifactEvidence.mandatory_satisfied && !routingConflict && artifactScore + ? artifactScore + : scoredRecommendation; + const recommendedSurfaceType = routingConflict + ? null + : recommended.surface_type; + const confidence = routingConflict + ? "low" + : surfaceConfidence(activityReview, recommended.score); const blockedSurfaceTypes = scores - .filter((entry) => entry.surface_type !== recommended.surface_type) + .filter((entry) => entry.surface_type !== recommendedSurfaceType) .filter((entry) => entry.exclusion_match_count > 0 || entry.profile_status === "blocked") .map((entry) => entry.surface_type); - const implications = buildSurfaceImplications(recommended.surface_type); + const implications = recommendedSurfaceType + ? buildSurfaceImplications(recommendedSurfaceType) + : { + interaction_implications: {}, + disclosure_implications: {}, + frontend_posture: {}, + }; + const artifactRecommendationOutput = isPlainObject( + getArtifactInspectorModel(contract)?.recommendation_output, + ) + ? getArtifactInspectorModel(contract).recommendation_output + : {}; const packet = { version: contract.version, contract_id: contract.id, workflow_id: getContractWorkflowId(contract), - status: activityReview.review_status === "ready_for_review" ? "ready" : "needs_source_context", - recommended_surface_type: recommended.surface_type, + status: routingConflict + ? "review_required" + : activityReview.review_status === "ready_for_review" + ? "ready" + : "needs_source_context", + recommended_surface_type: recommendedSurfaceType, + ...(recommendedSurfaceType === artifactIdentifiers.surface_type + ? { + profile_id: + optionalString(artifactRecommendationOutput.profile_id) || + artifactIdentifiers.workflow_profile, + primary_structure: + optionalString(artifactRecommendationOutput.primary_structure) || + "persistent artifact, selectable loci, contextual support, local feedback, and artifact-local completion", + density: + optionalString(artifactRecommendationOutput.density) || + "artifact-first contextual", + navigation_shape: + optionalString(artifactRecommendationOutput.navigation_shape) || + "artifact persistent; supporting context revealed from the active locus", + } + : {}), blocked_surface_types: unique(blockedSurfaceTypes), confidence, + ...(routingConflict ? { routing_conflict: routingConflict } : {}), evidence: { activity_review_status: activityReview.review_status, input_excerpt: input.trim().slice(0, 240), implementation_terms_detected: inputContext.implementation_terms_detected, purpose_evidence: inputContext.purpose_evidence, + ...(artifactEvidence.should_include + ? { + artifact_inspector: { + model_id: artifactEvidence.model_id, + model_version: artifactEvidence.model_version, + status: artifactEvidence.status, + mandatory_evidence_ids: + artifactEvidence.mandatory_evidence_ids, + matched_mandatory_evidence: + artifactEvidence.matched_mandatory_evidence, + missing_mandatory_evidence: + artifactEvidence.missing_mandatory_evidence, + matched_positive_evidence: + artifactEvidence.matched_positive_evidence, + matched_exclusion_evidence: + artifactEvidence.matched_exclusion_evidence, + positives: artifactEvidence.positives, + exclusions: artifactEvidence.exclusions, + conflict: artifactEvidence.conflict, + }, + } + : {}), surface_type_scores: scores.map((entry) => ({ surface_type: entry.surface_type, label: entry.label, @@ -1843,7 +2576,9 @@ export function recommendSurfaceTypes(input, options = {}) { } : {}), })), - selected_definition: resolveSurfaceType(contract, recommended.surface_type), + selected_definition: recommendedSurfaceType + ? resolveSurfaceType(contract, recommendedSurfaceType) + : null, }, interaction_implications: implications.interaction_implications, disclosure_implications: implications.disclosure_implications, @@ -1868,6 +2603,16 @@ function summarizeSurfaceReview(surfaceReview, { includeFrontendPosture = false disclosure_implications: isPlainObject(surfaceReview.disclosure_implications) ? surfaceReview.disclosure_implications : {}, + ...(optionalString(surfaceReview.status) === "review_required" + ? { status: "review_required" } + : {}), + ...(isPlainObject(surfaceReview.routing_conflict) + ? { + routing_conflict: cloneWorkflowStructuredValue( + surfaceReview.routing_conflict, + ), + } + : {}), }; if (includeFrontendPosture) { @@ -1879,36 +2624,176 @@ function summarizeSurfaceReview(surfaceReview, { includeFrontendPosture = false return summary; } -function selectedSurfaceTypeFromImplementationReviewOptions(options = {}) { +function implementationCandidateSurfaceSignals(candidate, contract) { + if (!isPlainObject(candidate) && typeof candidate !== "string") { + return []; + } + + const identifiers = getArtifactInspectorIdentifiers(contract); + const signals = []; + if (isPlainObject(candidate)) { + signals.push( + ["candidate.surface_type", candidate.surface_type], + ["candidate.surfaceType", candidate.surfaceType], + [ + "candidate.pattern_contract_evidence.surface_type", + candidate.pattern_contract_evidence?.surface_type, + ], + [ + "candidate.patternContractEvidence.surfaceType", + candidate.patternContractEvidence?.surfaceType, + ], + ); + const patternId = optionalString( + candidate.pattern_contract_evidence?.pattern_id ?? + candidate.patternContractEvidence?.patternId, + ); + if ( + [ + "artifact-inspector", + identifiers.surface_type, + identifiers.workflow_profile, + identifiers.frontend_surface_profile, + ].includes(patternId) + ) { + signals.push([ + "candidate.pattern_contract_evidence.pattern_id", + identifiers.surface_type, + ]); + } + } + + const markupText = ( + typeof candidate === "string" + ? [candidate] + : collectStringValues({ + implementation_source: + candidateImplementationSourceText(candidate), + code: candidate.code, + markup: candidate.markup, + rendered_html: candidate.rendered_html, + renderedHtml: candidate.renderedHtml, + rendered_markup: candidate.rendered_markup, + renderedMarkup: candidate.renderedMarkup, + primary_artifact: candidate.primary_artifact, + primaryArtifact: candidate.primaryArtifact, + }) + ).join(" "); + const hasArtifactRoot = + /\bdata-artifact-root(?:\s|=|>)/i.test(markupText) || + /\bdata-jk-scope\s*=\s*["']primary[-_]artifact["']/i.test( + markupText, + ); + const hasInspectorChrome = + /\bdata-jk-scope\s*=\s*["']inspector[-_]chrome["']/i.test( + markupText, + ); + const hasInspectionOverlay = + /\bdata-jk-scope\s*=\s*["']inspection[-_]overlay["']/i.test( + markupText, + ); + if (hasArtifactRoot && hasInspectorChrome && hasInspectionOverlay) { + signals.push([ + "candidate.canonical_artifact_inspector_roots", + identifiers.surface_type, + ]); + } + + return signals; +} + +function selectedSurfaceTypeFromImplementationReviewOptions( + options = {}, + contract, + candidate, +) { const surfaceReview = options.surface_review ?? options.surfaceReview; const frontendGenerationContext = options.frontend_generation_context ?? options.frontendGenerationContext; const candidates = [ - options.surface_type, - options.surfaceType, - surfaceReview?.recommended_surface_type, - surfaceReview?.recommendedSurfaceType, - surfaceReview?.surface_type, - surfaceReview?.surfaceType, - frontendGenerationContext?.surface_type, - frontendGenerationContext?.surfaceType, - frontendGenerationContext?.surface_guidance?.recommended_surface_type, - frontendGenerationContext?.surfaceGuidance?.recommendedSurfaceType, - frontendGenerationContext?.implementation_guidance?.surface_type, - frontendGenerationContext?.implementationGuidance?.surfaceType, - frontendGenerationContext?.surface_review?.recommended_surface_type, - frontendGenerationContext?.surfaceReview?.recommendedSurfaceType, - ]; - const selected = candidates.find( - (candidate) => typeof candidate === "string" && candidate.trim().length > 0, + ["surface_type", options.surface_type], + ["surfaceType", options.surfaceType], + [ + "surface_review.recommended_surface_type", + surfaceReview?.recommended_surface_type, + ], + [ + "surfaceReview.recommendedSurfaceType", + surfaceReview?.recommendedSurfaceType, + ], + ["surface_review.surface_type", surfaceReview?.surface_type], + ["surfaceReview.surfaceType", surfaceReview?.surfaceType], + [ + "frontend_generation_context.surface_type", + frontendGenerationContext?.surface_type, + ], + [ + "frontendGenerationContext.surfaceType", + frontendGenerationContext?.surfaceType, + ], + [ + "frontend_generation_context.surface_guidance.recommended_surface_type", + frontendGenerationContext?.surface_guidance?.recommended_surface_type, + ], + [ + "frontendGenerationContext.surfaceGuidance.recommendedSurfaceType", + frontendGenerationContext?.surfaceGuidance?.recommendedSurfaceType, + ], + [ + "frontend_generation_context.implementation_guidance.surface_type", + frontendGenerationContext?.implementation_guidance?.surface_type, + ], + [ + "frontendGenerationContext.implementationGuidance.surfaceType", + frontendGenerationContext?.implementationGuidance?.surfaceType, + ], + [ + "frontend_generation_context.surface_review.recommended_surface_type", + frontendGenerationContext?.surface_review?.recommended_surface_type, + ], + [ + "frontendGenerationContext.surfaceReview.recommendedSurfaceType", + frontendGenerationContext?.surfaceReview?.recommendedSurfaceType, + ], + ...implementationCandidateSurfaceSignals(candidate, contract), + ].filter( + ([, candidate]) => + typeof candidate === "string" && candidate.trim().length > 0, ); - - return selected ? normalizeOptionalSurfaceType(selected) : null; -} - -function inferActivityEvidence(input) { - return { - hasActivity: hasAny(input, [ + const normalizedCandidates = candidates.map(([field, candidate]) => [ + field, + normalizeOptionalSurfaceType(candidate), + ]); + const distinctSurfaceTypes = unique( + normalizedCandidates.map(([, candidate]) => candidate), + ); + const artifactInspectorSurfaceType = + getArtifactInspectorIdentifiers(contract).surface_type; + if ( + distinctSurfaceTypes.includes(artifactInspectorSurfaceType) && + distinctSurfaceTypes.some( + (surfaceType) => surfaceType !== artifactInspectorSurfaceType, + ) + ) { + throw new JudgmentKitInputError( + "Implementation review received conflicting Artifact Inspector and legacy surface signals.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "surface_type", + surface_type_candidates: Object.fromEntries(normalizedCandidates), + }, + }, + ); + } + const selected = normalizedCandidates[0]?.[1] ?? null; + + return selected; +} + +function inferActivityEvidence(input) { + return { + hasActivity: hasAny(input, [ "activity", "workflow", "reviewing", @@ -2183,7 +3068,11 @@ function extractObservedBriefDetails(input, contract, implementationTermsDetecte }; } -function buildReviewQuestions(evidence, implementationTermsDetected) { +function buildReviewQuestions( + evidence, + implementationTermsDetected, + artifactInspectorEvidence = null, +) { const questions = []; if (!evidence.hasActivity) { @@ -2208,6 +3097,50 @@ function buildReviewQuestions(evidence, implementationTermsDetected) { ); } + if (artifactInspectorEvidence?.should_include) { + const missing = new Set( + artifactInspectorEvidence.missing_mandatory_evidence, + ); + + if (missing.has("rendered_artifact_is_primary")) { + questions.push( + "Is one bounded rendered artifact the primary object that must remain visible throughout the work?", + ); + } + + if (missing.has("locus_selection_required")) { + questions.push( + "Must the participant select a specific semantic locus within the artifact to complete the work?", + ); + } + + if (missing.has("support_context_is_locus_relative")) { + questions.push( + "Does the supporting context only become meaningful in relation to the active artifact locus?", + ); + } + + if ( + !artifactInspectorEvidence.matched_positive_evidence.includes( + "completion_is_artifact_local", + ) + ) { + questions.push( + "What completion state or result must remain visible on or directly beside the artifact?", + ); + } + + if ( + !artifactInspectorEvidence.matched_positive_evidence.includes( + "external_artifact_visual_authority", + ) + ) { + questions.push( + "Who owns the artifact's visual styling, and is that authority independent from the inspector chrome?", + ); + } + } + return questions; } @@ -2423,6 +3356,11 @@ function buildCandidateDisclosurePolicy(analyzerPacket) { function selectTargetedQuestions(reviewQuestions) { const priorities = [ + /bounded rendered artifact|primary object/i, + /semantic locus|artifact locus/i, + /supporting context|active artifact locus/i, + /completion state|result.*artifact/i, + /owns.*artifact.*visual styling|authority independent/i, /activity/i, /decision|next action/i, /leave the surface|knowing|done|outcome/i, @@ -2561,8 +3499,12 @@ function buildCandidatePrimaryTermsDetected(candidate, contract) { } function buildCandidateMissingFields(candidate) { - const activityModel = candidate.activity_model; - const interactionContract = candidate.interaction_contract; + const activityModel = isPlainObject(candidate?.activity_model) + ? candidate.activity_model + : {}; + const interactionContract = isPlainObject(candidate?.interaction_contract) + ? candidate.interaction_contract + : {}; const participants = toStringArray(activityModel.participants); const vocabulary = toStringArray(activityModel.domain_vocabulary); const outcomes = toStringArray(activityModel.outcomes); @@ -2720,6 +3662,7 @@ function buildActivityModelReviewPacket(analyzerPacket, candidate, source, contr candidateGuardrails.candidate_primary_terms_detected.length === 0; const sourceQuestions = selectTargetedQuestions(analyzerPacket.review_questions); const candidateQuestions = buildCandidateQuestions(candidateGuardrails); + const artifactInspectorEvidence = analyzerPacket.artifact_inspector_evidence; const packet = { version: analyzerPacket.version, contract_id: analyzerPacket.contract_id, @@ -2739,6 +3682,9 @@ function buildActivityModelReviewPacket(analyzerPacket, candidate, source, contr decision: evidence.decision, outcome: evidence.outcome, implementation_terms_detected: analyzerPacket.implementation_terms_detected, + ...(artifactInspectorEvidence?.should_include + ? { artifact_inspector: artifactInspectorEvidence } + : {}), }, assumptions: buildReviewAssumptions(analyzerPacket, source), confidence: buildReviewConfidence( @@ -2762,6 +3708,9 @@ function buildActivityModelReviewPacket(analyzerPacket, candidate, source, contr disclosure_translation_candidates: analyzerPacket.disclosure_policy.translation_candidates, original_review_questions: analyzerPacket.review_questions, + ...(artifactInspectorEvidence?.should_include + ? { artifact_inspector: artifactInspectorEvidence } + : {}), }, }; @@ -2815,7 +3764,12 @@ export function analyzeImplementationBrief(input, options = {}) { const implementationTermsDetected = detectImplementationTerms(input, contract); const observed = extractObservedBriefDetails(input, contract, implementationTermsDetected); const evidence = inferActivityEvidence(input); - const reviewQuestions = buildReviewQuestions(evidence, implementationTermsDetected); + const artifactInspectorEvidence = buildArtifactInspectorEvidence(input, contract); + const reviewQuestions = buildReviewQuestions( + evidence, + implementationTermsDetected, + artifactInspectorEvidence, + ); const status = reviewQuestions.length === 0 ? "ready" : "needs_review"; const packet = { version: contract.version, @@ -2827,6 +3781,9 @@ export function analyzeImplementationBrief(input, options = {}) { implementation_terms_detected: implementationTermsDetected, review_questions: reviewQuestions, ui_brief: buildUiBrief(contract, evidence, status, observed, implementationTermsDetected), + ...(artifactInspectorEvidence.should_include + ? { artifact_inspector_evidence: artifactInspectorEvidence } + : {}), }; assertNoStyleFields(packet); @@ -3045,6 +4002,9 @@ const REVIEW_PACKET_LABEL_TERMS = [ "Primary user", "Review status", ]; +const REVIEW_PACKET_ALLOWED_DOMAIN_PHRASES = new Set([ + "outcome pending", +]); function collectStringValues(value, values = []) { if (typeof value === "string") { @@ -3079,6 +4039,10 @@ function uiWorkflowPrimaryFields(candidate) { function textContainsReviewPacketMetaTerm(value) { const normalized = normalizeText(value); + if (REVIEW_PACKET_ALLOWED_DOMAIN_PHRASES.has(normalized)) { + return false; + } + if ( REVIEW_PACKET_MACHINE_TERMS.some((term) => normalized.includes(normalizeText(term)), @@ -3104,6 +4068,10 @@ function buildCandidatePrimaryMetaTermsDetected(candidate) { for (const value of collectStringValues(uiWorkflowPrimaryFields(candidate))) { const normalized = normalizeText(value); + if (REVIEW_PACKET_ALLOWED_DOMAIN_PHRASES.has(normalized)) { + continue; + } + for (const term of REVIEW_PACKET_MACHINE_TERMS) { if (normalized.includes(normalizeText(term))) { counts.set(term, (counts.get(term) ?? 0) + 1); @@ -3186,227 +4154,1638 @@ function toSurfaceSetArray(value) { return value.filter(isPlainObject); } -function rawWorkflowTopology(value) { - const topology = optionalString(value); - - return WORKFLOW_TOPOLOGY_IDS.includes(topology) ? topology : ""; -} - -function inferWorkflowTopology(candidate, surfaceGuidance, contract) { - const explicitTopology = rawWorkflowTopology(candidate.workflow?.topology); - - if (explicitTopology) { - return explicitTopology; +function cloneWorkflowStructuredValue(value) { + if (Array.isArray(value)) { + return value.map((entry) => cloneWorkflowStructuredValue(entry)); } - const surfaceSet = toSurfaceSetArray(candidate.surface_set); - - if (surfaceSet.length > 1) { - return "multi_surface"; + if (isPlainObject(value)) { + return Object.fromEntries( + Object.entries(value).map(([key, entry]) => [ + key, + cloneWorkflowStructuredValue(entry), + ]), + ); } - const surfaceType = optionalString(surfaceGuidance?.recommended_surface_type); + return value; +} - if (surfaceType === "dashboard_monitor") { - return "dashboard"; +function toWorkflowWorkUnitArray(value) { + if (!Array.isArray(value)) { + return []; } - if (surfaceType === "content_report") { - return "report"; - } + return value.filter((entry) => + (typeof entry === "string" && cleanClause(entry).length > 0) || + isPlainObject(entry)); +} - if (surfaceType === "conversation") { - return "conversation"; +function workflowWorkUnitId(entry) { + if (isPlainObject(entry)) { + return optionalString(entry.id); } - const policy = getWorkflowTopologyPolicy(contract); - const preferredDefault = optionalString(policy.preferred_default); + const value = optionalString(entry); - return WORKFLOW_TOPOLOGY_IDS.includes(preferredDefault) - ? preferredDefault - : "workspace"; + return value + .toLowerCase() + .replace(/[^a-z0-9]+/g, "_") + .replace(/^_+|_+$/g, ""); } -function aggregateSurfaceSet(surfaceSet) { - const sections = []; - const controls = []; - - for (const surface of surfaceSet) { - sections.push(...toStringArray(surface.sections)); - controls.push(...toStringArray(surface.controls)); - } - - return { - sections: unique(sections), - controls: unique(controls), - }; +function workflowWorkUnitIds(value) { + return unique(toWorkflowWorkUnitArray(value).map(workflowWorkUnitId)); } -function normalizeUiWorkflowSurfaceSet(candidate, implementationTermsDetected) { - const providedSurfaceSet = toSurfaceSetArray(candidate.surface_set); +function duplicateWorkflowWorkUnitIds(value) { + const counts = new Map(); + for (const workUnit of toWorkflowWorkUnitArray(value)) { + const workUnitId = workflowWorkUnitId(workUnit); + if (!workUnitId) continue; + counts.set(workUnitId, (counts.get(workUnitId) ?? 0) + 1); + } - return providedSurfaceSet.map((surface, index) => ({ - name: sanitizeUiWorkflowString( - surface.name, - implementationTermsDetected, - `Surface ${index + 1}`, - ), - purpose: sanitizeUiWorkflowString( - surface.purpose, - implementationTermsDetected, - "Support a coordinated part of the workflow.", - ), - sections: sanitizeUiWorkflowList(surface.sections, implementationTermsDetected), - controls: sanitizeUiWorkflowList(surface.controls, implementationTermsDetected), - relationship_to_workflow: sanitizeUiWorkflowString( - surface.relationship_to_workflow, - implementationTermsDetected, - "Coordinates with the rest of the workflow.", - ), - })); + return [...counts.entries()] + .filter(([, count]) => count > 1) + .map(([workUnitId]) => workUnitId); } -function collectStepperEligibilityText(activityReview, candidate, surfaceGuidance) { - const activityCandidate = activityReview?.candidate ?? {}; - const workflow = candidate.workflow ?? {}; +function rawWorkflowTopology(value, contract) { + const topology = isPlainObject(value) + ? optionalString(value.kind) + : optionalString(value); - return [ - activityReview?.source?.input_excerpt, - activityCandidate.activity_model?.activity, - activityCandidate.activity_model?.objective, - ...(toStringArray(activityCandidate.activity_model?.participants)), - ...(toStringArray(activityCandidate.activity_model?.outcomes)), - ...(toStringArray(activityCandidate.activity_model?.domain_vocabulary)), - activityCandidate.interaction_contract?.primary_decision, - ...(toStringArray(activityCandidate.interaction_contract?.next_actions)), - activityCandidate.interaction_contract?.completion, - surfaceGuidance?.recommended_surface_type, - workflow.surface_name, - workflow.topology, - ...(toStringArray(workflow.work_units)), - ...(toSurfaceSetArray(candidate.surface_set).flatMap((surface) => [ - surface.name, - surface.purpose, - surface.relationship_to_workflow, - ...(toStringArray(surface.sections)), - ...(toStringArray(surface.controls)), - ])), - ].filter(Boolean).join(" "); + return getAllowedWorkflowTopologyIds(contract).includes(topology) + ? topology + : ""; } -function buildStepperEligibility(activityReview, candidate, surfaceGuidance, contract) { - const topology = rawWorkflowTopology(candidate.workflow?.topology); - const surfaceType = optionalString(surfaceGuidance?.recommended_surface_type); - const text = normalizeText( - collectStepperEligibilityText(activityReview, candidate, surfaceGuidance), +function assertConsistentWorkflowTopology( + workflow, + { + code = "invalid_input", + message = + "Workflow topology and topology_contract.kind must agree when both are provided.", + } = {}, +) { + const topology = isPlainObject(workflow?.topology) + ? optionalString(workflow.topology.kind) + : optionalString(workflow?.topology); + const topologyContractKind = optionalString( + workflow?.topology_contract?.kind, ); - const explicitStagedRequest = - /\b(?:wizard|stepper|stepped|step by step|step-by-step|multi-step|multistep|staged flow|guided flow|guided setup|setup wizard|onboarding sequence)\b/.test(text); - const stagedDependencyOrder = - /\b(?:strict dependency|dependency order|ordered stages|must complete|complete .* before|before continuing|after completing|prerequisite|sequential|sequence|previous stage|next stage|first .* then)\b/.test(text); - const formOrSetupSequence = - ["form_flow", "setup_debug_tool"].includes(surfaceType) && - /\b(?:form|submit|submission|validation|required|invalid|confirmation|checkout|application|intake|onboarding|setup|configure|configuration|install|installation|test connection|verification)\b/.test(text); - const blockedSurfaceType = [ - "workbench", - "operator_review", - "dashboard_monitor", - "content_report", - "conversation", - ].includes(surfaceType); - const allowed = - explicitStagedRequest || - (formOrSetupSequence && stagedDependencyOrder) || - (formOrSetupSequence && !blockedSurfaceType); - const requested = topology === "staged_flow"; - const blocked = requested && !allowed; - const policy = getWorkflowTopologyPolicy(contract).stepper_eligibility ?? {}; - - return { - policy: optionalString(policy.policy) || "strong_intent", - allowed, - requested, - blocked, - surface_type: surfaceType, - reason: allowed - ? "Source evidence supports staged progression." - : requested - ? "Staged-flow topology needs explicit wizard intent, setup/form sequence, or strict dependency order." - : "No staged-flow intent detected; use topology, work units, and coordinated surfaces instead.", - evidence: { - explicit_staged_request: explicitStagedRequest, - staged_dependency_order: stagedDependencyOrder, - form_or_setup_sequence: formOrSetupSequence, - blocked_surface_type: blockedSurfaceType, - }, - }; -} -function assertUiWorkflowCandidateShape(candidate) { - if (!isPlainObject(candidate)) { - throw new JudgmentKitInputError("UI workflow candidate must be an object."); + if ( + topology && + topologyContractKind && + topology !== topologyContractKind + ) { + throw new JudgmentKitInputError(message, { + code, + details: { + field: "workflow.topology", + topology, + topology_contract_kind: topologyContractKind, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_TOPOLOGY_KIND_INVALID", + }, + }); } - if (!isPlainObject(candidate.workflow)) { - throw new JudgmentKitInputError("UI workflow candidate requires workflow."); - } + return topology || topologyContractKind; +} - if (Object.prototype.hasOwnProperty.call(candidate.workflow, "steps")) { - throw new JudgmentKitInputError( - "UI workflow candidate no longer accepts workflow.steps. Use workflow.work_units.", - ); - } +function artifactInspectorAuthorityCandidate(implementationContract) { + const source = isPlainObject(implementationContract) + ? implementationContract + : {}; + const fieldAliases = { + design_system_scopes: ["design_system_scopes", "designSystemScopes"], + boundary_contracts: ["boundary_contracts", "boundaryContracts"], + artifact_inspector: ["artifact_inspector", "artifactInspector"], + }; + const candidate = {}; + let present = false; - if (Object.prototype.hasOwnProperty.call(candidate, "primary_ui")) { - throw new JudgmentKitInputError( - "UI workflow candidate no longer accepts primary_ui. Use surface_set.", + for (const [canonicalField, aliases] of Object.entries(fieldAliases)) { + const suppliedAlias = aliases.find((field) => + Object.prototype.hasOwnProperty.call(source, field), ); + if (!suppliedAlias) continue; + present = true; + candidate[canonicalField] = source[suppliedAlias]; } - if (!rawWorkflowTopology(candidate.workflow.topology)) { - throw new JudgmentKitInputError( - "UI workflow candidate requires workflow.topology.", - ); + return { candidate, present }; +} + +function artifactInspectorRequiredStructureIssue({ + workflow, + contract, + activeStateGroupIds, +}) { + const model = getArtifactInspectorModel(contract) ?? {}; + const topologyContract = isPlainObject(workflow?.topology_contract) + ? workflow.topology_contract + : {}; + const canonicalTopology = isPlainObject(model.topology) + ? model.topology + : {}; + const workUnits = toWorkflowWorkUnitArray(workflow?.work_units); + const observedWorkUnitIds = workUnits.map(workflowWorkUnitId); + const canonicalWorkUnits = Array.isArray(model.work_units) + ? model.work_units.filter(isPlainObject) + : []; + const canonicalWorkUnitIds = canonicalWorkUnits + .map(workflowWorkUnitId) + .filter(Boolean); + const duplicateWorkUnitIds = duplicateWorkflowWorkUnitIds(workUnits); + const missingWorkUnitIds = canonicalWorkUnitIds.filter( + (workUnitId) => !observedWorkUnitIds.includes(workUnitId), + ); + const unexpectedWorkUnitIds = observedWorkUnitIds.filter( + (workUnitId) => !canonicalWorkUnitIds.includes(workUnitId), + ); + + if ( + duplicateWorkUnitIds.length > 0 || + missingWorkUnitIds.length > 0 || + unexpectedWorkUnitIds.length > 0 || + observedWorkUnitIds.length !== canonicalWorkUnitIds.length + ) { + return { + field: "workflow.work_units", + expected: canonicalWorkUnitIds, + observed: observedWorkUnitIds, + duplicate_work_unit_ids: duplicateWorkUnitIds, + missing_work_unit_ids: missingWorkUnitIds, + unexpected_work_unit_ids: unexpectedWorkUnitIds, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + }; } - if (toStringArray(candidate.workflow.work_units).length === 0) { - throw new JudgmentKitInputError( - "UI workflow candidate requires workflow.work_units.", + for (const canonicalWorkUnit of canonicalWorkUnits) { + const workUnitId = workflowWorkUnitId(canonicalWorkUnit); + const observedWorkUnit = workUnits.find( + (workUnit) => workflowWorkUnitId(workUnit) === workUnitId, ); + for (const fieldName of [ + "participant_intent", + "system_responsibility", + ]) { + if ( + optionalString(observedWorkUnit?.[fieldName]) !== + optionalString(canonicalWorkUnit[fieldName]) + ) { + return { + field: `workflow.work_units.${workUnitId}.${fieldName}`, + expected: optionalString(canonicalWorkUnit[fieldName]), + observed: optionalString(observedWorkUnit?.[fieldName]) || null, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + }; + } + } } - if (toSurfaceSetArray(candidate.surface_set).length === 0) { - throw new JudgmentKitInputError("UI workflow candidate requires surface_set."); + const entryWorkUnitId = optionalString(topologyContract.entry_work_unit_id); + if ( + !entryWorkUnitId || + entryWorkUnitId !== optionalString(canonicalTopology.entry_work_unit_id) || + !observedWorkUnitIds.includes(entryWorkUnitId) + ) { + return { + field: "workflow.topology_contract.entry_work_unit_id", + expected: optionalString(canonicalTopology.entry_work_unit_id), + observed: entryWorkUnitId || null, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_ENTRY_REFERENCE_INVALID", + }; } - if (!isPlainObject(candidate.handoff)) { + const completionWorkUnitIds = toStringArray( + topologyContract.completion_work_unit_ids, + ); + const canonicalCompletionWorkUnitIds = toStringArray( + canonicalTopology.completion_work_unit_ids, + ); + if ( + completionWorkUnitIds.length !== canonicalCompletionWorkUnitIds.length || + canonicalCompletionWorkUnitIds.some( + (workUnitId, index) => completionWorkUnitIds[index] !== workUnitId, + ) || + completionWorkUnitIds.some( + (workUnitId) => !observedWorkUnitIds.includes(workUnitId), + ) + ) { + return { + field: "workflow.topology_contract.completion_work_unit_ids", + expected: canonicalCompletionWorkUnitIds, + observed: completionWorkUnitIds, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID", + }; + } + + const transitions = Array.isArray(topologyContract.transitions) + ? topologyContract.transitions + : []; + const canonicalTransitions = Array.isArray(canonicalTopology.transitions) + ? canonicalTopology.transitions + : []; + const hasRecoveryEntry = transitions.some( + (transition) => + optionalString(transition?.to) === "recover" && + observedWorkUnitIds.includes(optionalString(transition?.from)), + ); + const hasRecoveryExit = transitions.some( + (transition) => + optionalString(transition?.from) === "recover" && + observedWorkUnitIds.includes(optionalString(transition?.to)), + ); + if ( + !observedWorkUnitIds.includes("recover") || + !hasRecoveryEntry || + !hasRecoveryExit + ) { + return { + field: "workflow.topology_contract.transitions", + expected: "Canonical inbound and outbound recovery transitions.", + observed: transitions, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_RECOVERY_PATH_MISSING", + }; + } + + const transitionsMatch = + transitions.length === canonicalTransitions.length && + canonicalTransitions.every((canonicalTransition, index) => { + const transition = transitions[index]; + return Boolean( + isPlainObject(transition) && + optionalString(transition.from) === + optionalString(canonicalTransition.from) && + optionalString(transition.to) === + optionalString(canonicalTransition.to) && + optionalString(transition.when) === + optionalString(canonicalTransition.when) && + observedWorkUnitIds.includes(optionalString(transition.from)) && + observedWorkUnitIds.includes(optionalString(transition.to)), + ); + }); + if (!transitionsMatch) { + return { + field: "workflow.topology_contract.transitions", + expected: cloneWorkflowStructuredValue(canonicalTransitions), + observed: transitions, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_TRANSITION_REFERENCE_INVALID", + }; + } + + const primaryObjectId = optionalString( + topologyContract.primary_object_id, + ); + const canonicalPrimaryObjectId = + optionalString(canonicalTopology.primary_object_id) || "artifact"; + if (primaryObjectId !== canonicalPrimaryObjectId) { + return { + field: "workflow.topology_contract.primary_object_id", + expected: canonicalPrimaryObjectId, + observed: primaryObjectId || null, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + }; + } + const artifact = isPlainObject(workflow?.artifact) + ? workflow.artifact + : null; + const artifactId = optionalString( + artifact?.id ?? artifact?.artifact_id, + ); + + if ( + !artifact || + !artifactId || + !optionalString(artifact.boundary) || + !primaryObjectId || + artifactId !== primaryObjectId + ) { + return { + field: "workflow.artifact", + expected: { + id: primaryObjectId || "artifact", + boundary: "A non-empty rendered artifact boundary description.", + }, + observed: artifact, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + }; + } + + const targetModel = isPlainObject(workflow?.target_model) + ? workflow.target_model + : null; + const canonicalTargetModel = isPlainObject(model.target_model) + ? model.target_model + : {}; + const targetArtifactId = optionalString( + targetModel?.artifact_id ?? targetModel?.primary_object_id, + ); + const canonicalArrayField = (field) => { + const observed = toStringArray(targetModel?.[field]); + const allowed = toStringArray(canonicalTargetModel[field]); + return ( + observed.length > 0 && + observed.every((entry) => allowed.includes(entry)) + ); + }; + const targetModelValid = Boolean( + targetModel && + targetArtifactId === primaryObjectId && + canonicalArrayField("target_kinds") && + canonicalArrayField("target_identity_sources") && + canonicalArrayField("label_sources") && + canonicalArrayField("artifact_interactivity") && + optionalString(targetModel.geometry_policy) === + optionalString(canonicalTargetModel.geometry_policy) && + optionalString(targetModel.native_interaction_precedence) === + optionalString(canonicalTargetModel.native_interaction_precedence) + ); + + if (!targetModelValid) { + return { + field: "workflow.target_model", + expected: { + ...cloneWorkflowStructuredValue(canonicalTargetModel), + artifact_id: primaryObjectId, + }, + observed: targetModel, + diagnostic_code: "JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING", + }; + } + + const workflowStateGroups = isPlainObject(workflow?.state_groups) + ? workflow.state_groups + : null; + const canonicalStateGroups = isPlainObject(model.state_groups) + ? model.state_groups + : {}; + const expectedActiveStateGroupIds = toStringArray(activeStateGroupIds); + const observedStateGroupIds = workflowStateGroups + ? Object.keys(workflowStateGroups) + : []; + const activeGroupsMatch = + expectedActiveStateGroupIds.length > 0 && + expectedActiveStateGroupIds.length === observedStateGroupIds.length && + expectedActiveStateGroupIds.every((groupId) => + observedStateGroupIds.includes(groupId), + ); + const activeStatesMatch = + workflowStateGroups && + expectedActiveStateGroupIds.every((groupId) => { + const expectedStates = toStringArray(canonicalStateGroups[groupId]); + const observedStates = toStringArray(workflowStateGroups[groupId]); + return ( + expectedStates.length > 0 && + observedStates.length === expectedStates.length && + expectedStates.every((state) => observedStates.includes(state)) + ); + }); + + if (!activeGroupsMatch || !activeStatesMatch) { + return { + field: "workflow.state_groups", + expected: Object.fromEntries( + expectedActiveStateGroupIds.map((groupId) => [ + groupId, + cloneWorkflowStructuredValue(canonicalStateGroups[groupId] ?? []), + ]), + ), + observed: workflowStateGroups, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }; + } + + return null; +} + +function assertArtifactInspectorBoundaryConsistency({ + workflow, + surfaceTypes = [], + profileIds = [], + implementationContract, + additionalAuthoritySignals = [], + activityModel, + interactionContract, + reviewedActiveStateGroups: reviewedActiveStateGroupsInput, + contract, + code = "invalid_artifact_inspector_authority_contract", + message = + "Artifact Inspector surface, topology, profile, and scoped authority must agree.", +} = {}) { + const resolvedContract = contract ?? loadActivityContract(); + const identifiers = getArtifactInspectorIdentifiers(resolvedContract); + const topology = assertConsistentWorkflowTopology(workflow, { + code, + message, + }); + const normalizedSurfaceTypes = unique( + [ + ...surfaceTypes, + implementationContract?.surface_type, + implementationContract?.surfaceType, + ] + .map((value) => optionalString(value)) + .filter(Boolean), + ); + const normalizedProfileIds = unique( + profileIds.map(optionalString).filter(Boolean), + ); + const topologyString = + typeof workflow?.topology === "string" + ? optionalString(workflow.topology) + : ""; + const topologyContractKind = optionalString( + workflow?.topology_contract?.kind, + ); + const topologyIsArtifact = topology === identifiers.topology_kind; + const canonicalArtifactTopologyShape = Boolean( + topologyString === identifiers.topology_kind && + isPlainObject(workflow?.topology_contract) && + topologyContractKind === identifiers.topology_kind, + ); + const surfaceSignalsArtifact = normalizedSurfaceTypes.includes( + identifiers.surface_type, + ); + const profileSignalsArtifact = normalizedProfileIds.includes( + identifiers.workflow_profile, + ); + const { candidate: authorityCandidate, present: authorityBundlePresent } = + artifactInspectorAuthorityCandidate(implementationContract); + const additionalAuthoritySignalPresent = additionalAuthoritySignals.some( + (value) => Boolean(value), + ); + let authorityBundleActive = false; + let normalizedAuthority = null; + let authorityError = null; + + if (authorityBundlePresent) { + try { + normalizedAuthority = + validateArtifactInspectorAuthorityContract(authorityCandidate); + authorityBundleActive = normalizedAuthority.active; + } catch (error) { + authorityError = error; + } + } + + const anyArtifactSignal = Boolean( + topologyIsArtifact || + surfaceSignalsArtifact || + profileSignalsArtifact || + authorityBundlePresent || + additionalAuthoritySignalPresent, + ); + const surfaceAligned = + normalizedSurfaceTypes.length > 0 && + normalizedSurfaceTypes.every( + (surfaceType) => surfaceType === identifiers.surface_type, + ); + const profileAligned = normalizedProfileIds.every( + (profileId) => profileId === identifiers.workflow_profile, + ); + const allArtifactSignalsAgree = Boolean( + surfaceAligned && + canonicalArtifactTopologyShape && + authorityBundleActive && + profileAligned, + ); + const reviewedActiveStateGroups = Array.isArray( + reviewedActiveStateGroupsInput, + ) + ? ARTIFACT_INSPECTOR_STATE_GROUP_IDS.filter((groupId) => + reviewedActiveStateGroupsInput.includes(groupId), + ) + : deriveArtifactInspectorActiveStateGroups({ + workflow: isPlainObject(workflow) ? workflow : {}, + activity_model: activityModel, + interaction_contract: interactionContract, + }); + const authorityActiveStateGroups = toStringArray( + normalizedAuthority?.artifact_inspector?.active_state_groups, + ); + + if (anyArtifactSignal && !allArtifactSignalsAgree) { + throw new JudgmentKitInputError(message, { + code, + details: { + field: "artifact_inspector.boundary_consistency", + expected: { + surface_type: identifiers.surface_type, + topology: identifiers.topology_kind, + topology_contract_kind: identifiers.topology_kind, + workflow_profile: identifiers.workflow_profile, + authority_bundle_active: true, + }, + observed: { + surface_types: normalizedSurfaceTypes, + topology: isPlainObject(workflow?.topology) + ? optionalString(workflow.topology.kind) || null + : optionalString(workflow?.topology) || null, + topology_representation: isPlainObject(workflow?.topology) + ? "object" + : typeof workflow?.topology, + topology_contract_kind: topologyContractKind || null, + canonical_topology_shape: canonicalArtifactTopologyShape, + workflow_profile_ids: normalizedProfileIds, + authority_bundle_present: authorityBundlePresent, + authority_bundle_active: authorityBundleActive, + additional_authority_signal_present: + additionalAuthoritySignalPresent, + ...(authorityError + ? { + authority_error: + optionalString(authorityError.message) || + "invalid_artifact_inspector_authority_contract", + } + : {}), + }, + reason: "artifact_inspector_boundary_signal_mismatch", + }, + }); + } + + if (allArtifactSignalsAgree) { + if ( + !artifactInspectorStateGroupsMatch( + authorityActiveStateGroups, + reviewedActiveStateGroups, + ) + ) { + throw new JudgmentKitInputError( + "Artifact Inspector authority cannot activate state groups absent from the reviewed activity and workflow.", + { + code, + details: { + field: "artifact_inspector.active_state_groups", + expected: reviewedActiveStateGroups, + observed: authorityActiveStateGroups, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }, + }, + ); + } + const requiredStructureIssue = artifactInspectorRequiredStructureIssue({ + workflow, + contract: resolvedContract, + activeStateGroupIds: reviewedActiveStateGroups, + }); + if (requiredStructureIssue) { + throw new JudgmentKitInputError( + "Artifact Inspector packets must preserve the reviewed artifact, locus model, and active state structures across every boundary.", + { + code, + details: { + ...requiredStructureIssue, + reason: "artifact_inspector_required_structure_invalid", + }, + }, + ); + } + } + + return { + artifactInspectorActive: anyArtifactSignal, + artifactSurfaceSelected: surfaceSignalsArtifact, + artifactTopologySelected: topologyIsArtifact, + authorityBundleActive, + }; +} + +function normalizeArtifactTopologyContract(candidate, contract, { force = false } = {}) { + const identifiers = getArtifactInspectorIdentifiers(contract); + const workflow = candidate.workflow ?? {}; + const supplied = isPlainObject(workflow.topology) + ? workflow.topology + : isPlainObject(workflow.topology_contract) + ? workflow.topology_contract + : null; + const source = supplied; + + if (!source) { + return null; + } + + if ( + !force && + rawWorkflowTopology(workflow.topology, contract) !== + identifiers.topology_kind && + optionalString(source.kind) !== identifiers.topology_kind + ) { + return null; + } + + return { + ...cloneWorkflowStructuredValue(source), + kind: optionalString(source.kind) || identifiers.topology_kind, + primary_object_id: optionalString(source.primary_object_id), + entry_work_unit_id: optionalString(source.entry_work_unit_id), + completion_work_unit_ids: toStringArray(source.completion_work_unit_ids), + transitions: Array.isArray(source.transitions) + ? source.transitions.filter(isPlainObject).map((transition) => ({ + ...cloneWorkflowStructuredValue(transition), + from: optionalString(transition.from), + to: optionalString(transition.to), + ...(optionalString(transition.when) + ? { when: optionalString(transition.when) } + : {}), + })) + : [], + }; +} + +function inferWorkflowTopology(candidate, surfaceGuidance, contract) { + const explicitTopology = rawWorkflowTopology( + candidate.workflow?.topology, + contract, + ); + + if (explicitTopology) { + return explicitTopology; + } + + const surfaceSet = toSurfaceSetArray(candidate.surface_set); + + if (surfaceSet.length > 1) { + return "multi_surface"; + } + + const surfaceType = optionalString(surfaceGuidance?.recommended_surface_type); + + if (surfaceType === "dashboard_monitor") { + return "dashboard"; + } + + if (surfaceType === "content_report") { + return "report"; + } + + if (surfaceType === "conversation") { + return "conversation"; + } + + const policy = getWorkflowTopologyPolicy(contract); + const preferredDefault = optionalString(policy.preferred_default); + + return getAllowedWorkflowTopologyIds(contract).includes(preferredDefault) + ? preferredDefault + : "workspace"; +} + +function aggregateSurfaceSet(surfaceSet) { + const sections = []; + const controls = []; + + for (const surface of surfaceSet) { + sections.push(...toStringArray(surface.sections)); + controls.push(...toStringArray(surface.controls)); + } + + return { + sections: unique(sections), + controls: unique(controls), + }; +} + +function normalizeUiWorkflowSurfaceSet(candidate, implementationTermsDetected) { + const providedSurfaceSet = toSurfaceSetArray(candidate.surface_set); + + return providedSurfaceSet.map((surface, index) => ({ + name: sanitizeUiWorkflowString( + surface.name, + implementationTermsDetected, + `Surface ${index + 1}`, + ), + purpose: sanitizeUiWorkflowString( + surface.purpose, + implementationTermsDetected, + "Support a coordinated part of the workflow.", + ), + sections: sanitizeUiWorkflowList(surface.sections, implementationTermsDetected), + controls: sanitizeUiWorkflowList(surface.controls, implementationTermsDetected), + relationship_to_workflow: sanitizeUiWorkflowString( + surface.relationship_to_workflow, + implementationTermsDetected, + "Coordinates with the rest of the workflow.", + ), + })); +} + +function collectStepperEligibilityText( + activityReview, + candidate, + surfaceGuidance, + contract, +) { + const activityCandidate = activityReview?.candidate ?? {}; + const workflow = candidate.workflow ?? {}; + const topology = rawWorkflowTopology(workflow.topology, contract); + const workUnitText = toWorkflowWorkUnitArray(workflow.work_units).flatMap( + (workUnit) => + isPlainObject(workUnit) + ? [ + workUnit.id, + workUnit.participant_intent, + workUnit.system_responsibility, + ] + : [workUnit], + ); + + return [ + activityReview?.source?.input_excerpt, + activityCandidate.activity_model?.activity, + activityCandidate.activity_model?.objective, + ...(toStringArray(activityCandidate.activity_model?.participants)), + ...(toStringArray(activityCandidate.activity_model?.outcomes)), + ...(toStringArray(activityCandidate.activity_model?.domain_vocabulary)), + activityCandidate.interaction_contract?.primary_decision, + ...(toStringArray(activityCandidate.interaction_contract?.next_actions)), + activityCandidate.interaction_contract?.completion, + surfaceGuidance?.recommended_surface_type, + workflow.surface_name, + topology, + ...workUnitText, + ...(toSurfaceSetArray(candidate.surface_set).flatMap((surface) => [ + surface.name, + surface.purpose, + surface.relationship_to_workflow, + ...(toStringArray(surface.sections)), + ...(toStringArray(surface.controls)), + ])), + ].filter(Boolean).join(" "); +} + +function buildStepperEligibility(activityReview, candidate, surfaceGuidance, contract) { + const topology = rawWorkflowTopology(candidate.workflow?.topology, contract); + const surfaceType = optionalString(surfaceGuidance?.recommended_surface_type); + const text = normalizeText( + collectStepperEligibilityText( + activityReview, + candidate, + surfaceGuidance, + contract, + ), + ); + const explicitStagedRequest = + /\b(?:wizard|stepper|stepped|step by step|step-by-step|multi-step|multistep|staged flow|guided flow|guided setup|setup wizard|onboarding sequence)\b/.test(text); + const stagedDependencyOrder = + /\b(?:strict dependency|dependency order|ordered stages|must complete|complete .* before|before continuing|after completing|prerequisite|sequential|sequence|previous stage|next stage|first .* then)\b/.test(text); + const formOrSetupSequence = + ["form_flow", "setup_debug_tool"].includes(surfaceType) && + /\b(?:form|submit|submission|validation|required|invalid|confirmation|checkout|application|intake|onboarding|setup|configure|configuration|install|installation|test connection|verification)\b/.test(text); + const blockedSurfaceType = [ + "workbench", + "operator_review", + "dashboard_monitor", + "content_report", + "conversation", + getArtifactInspectorIdentifiers(contract).surface_type, + ].includes(surfaceType); + const allowed = + explicitStagedRequest || + (formOrSetupSequence && stagedDependencyOrder) || + (formOrSetupSequence && !blockedSurfaceType); + const requested = topology === "staged_flow"; + const blocked = requested && !allowed; + const policy = getWorkflowTopologyPolicy(contract).stepper_eligibility ?? {}; + + return { + policy: optionalString(policy.policy) || "strong_intent", + allowed, + requested, + blocked, + surface_type: surfaceType, + reason: allowed + ? "Source evidence supports staged progression." + : requested + ? "Staged-flow topology needs explicit wizard intent, setup/form sequence, or strict dependency order." + : "No staged-flow intent detected; use topology, work units, and coordinated surfaces instead.", + evidence: { + explicit_staged_request: explicitStagedRequest, + staged_dependency_order: stagedDependencyOrder, + form_or_setup_sequence: formOrSetupSequence, + blocked_surface_type: blockedSurfaceType, + }, + }; +} + +function assertUiWorkflowCandidateShape(candidate, contract) { + if (!isPlainObject(candidate)) { + throw new JudgmentKitInputError("UI workflow candidate must be an object."); + } + + if (!isPlainObject(candidate.workflow)) { + throw new JudgmentKitInputError("UI workflow candidate requires workflow."); + } + + if (Object.prototype.hasOwnProperty.call(candidate.workflow, "steps")) { + throw new JudgmentKitInputError( + "UI workflow candidate no longer accepts workflow.steps. Use workflow.work_units.", + ); + } + + if (Object.prototype.hasOwnProperty.call(candidate, "primary_ui")) { + throw new JudgmentKitInputError( + "UI workflow candidate no longer accepts primary_ui. Use surface_set.", + ); + } + + const suppliedTopology = candidate.workflow.topology; + const artifactTopologyCandidate = isArtifactTopologyCandidate(candidate, contract); + + if (!rawWorkflowTopology(suppliedTopology, contract) && !artifactTopologyCandidate) { + throw new JudgmentKitInputError( + "UI workflow candidate requires workflow.topology.", + ); + } + + if (toWorkflowWorkUnitArray(candidate.workflow.work_units).length === 0) { + throw new JudgmentKitInputError( + "UI workflow candidate requires workflow.work_units.", + ); + } + + if (toSurfaceSetArray(candidate.surface_set).length === 0) { + throw new JudgmentKitInputError("UI workflow candidate requires surface_set."); + } + + if (!isPlainObject(candidate.handoff)) { throw new JudgmentKitInputError("UI workflow candidate requires handoff."); } - if (!isPlainObject(candidate.diagnostics)) { - throw new JudgmentKitInputError("UI workflow candidate requires diagnostics."); + if (!isPlainObject(candidate.diagnostics)) { + throw new JudgmentKitInputError("UI workflow candidate requires diagnostics."); + } +} + +function buildUiWorkflowCandidateMissingFields(candidate) { + const workflow = candidate.workflow; + const handoff = candidate.handoff; + const completionState = optionalString(workflow.completion_state); + const handoffCompletion = + optionalString(handoff.next_action).length > 0 && + optionalString(handoff.reason).length > 0; + const workUnits = toWorkflowWorkUnitArray(workflow.work_units); + const surfaceSet = toSurfaceSetArray(candidate.surface_set); + const hasSurfaceStructure = + surfaceSet.some((surface) => toStringArray(surface.sections).length > 0); + + return { + workflow_structure: workUnits.length === 0 && !hasSurfaceStructure, + primary_actions: toStringArray(workflow.primary_actions).length === 0, + decision_support: toStringArray(workflow.decision_points).length === 0, + surface_sections: !hasSurfaceStructure, + completion_or_handoff: + completionState.length === 0 && !handoffCompletion, + }; +} + +function isArtifactTopologyCandidate(candidate, contract) { + if (!hasArtifactInspectorContract(contract)) { + return false; + } + + const workflow = candidate?.workflow ?? {}; + const identifiers = getArtifactInspectorIdentifiers(contract); + const suppliedTopology = isPlainObject(workflow.topology) + ? workflow.topology + : isPlainObject(workflow.topology_contract) + ? workflow.topology_contract + : null; + + return Boolean( + rawWorkflowTopology(workflow.topology, contract) === + identifiers.topology_kind || + optionalString(workflow.topology_contract?.kind) === + identifiers.topology_kind || + (suppliedTopology && + [ + "primary_object_id", + "entry_work_unit_id", + "completion_work_unit_ids", + "transitions", + ].some((key) => Object.prototype.hasOwnProperty.call(suppliedTopology, key))), + ); +} + +function isArtifactInspectorWorkflowSelected( + candidate, + contract, + guidanceProfile, + surfaceGuidance, +) { + const identifiers = getArtifactInspectorIdentifiers(contract); + + return Boolean( + hasArtifactInspectorContract(contract) && + (isArtifactTopologyCandidate(candidate, contract) || + optionalString(guidanceProfile?.profile_id) === + identifiers.workflow_profile || + optionalString(surfaceGuidance?.recommended_surface_type) === + identifiers.surface_type), + ); +} + +function getArtifactInspectorDiagnosticMeaning(contract, code, fallback) { + const diagnostics = getArtifactInspectorModel(contract)?.diagnostics; + + if (Array.isArray(diagnostics)) { + const match = diagnostics.find( + (entry) => isPlainObject(entry) && optionalString(entry.code) === code, + ); + + return optionalString(match?.meaning) || fallback; + } + + if (isPlainObject(diagnostics)) { + const entry = diagnostics[code]; + + return optionalString(isPlainObject(entry) ? entry.meaning : entry) || fallback; + } + + return fallback; +} + +function createArtifactInspectorWorkflowDiagnostic( + contract, + { code, field, meaning, expected, observed, repair_instruction: repairInstruction }, +) { + return { + code, + meaning: getArtifactInspectorDiagnosticMeaning(contract, code, meaning), + field, + expected_contract: expected, + observed: observed === undefined + ? null + : cloneWorkflowStructuredValue(observed), + repair_instruction: repairInstruction, + }; +} + +function artifactTargetModel(candidate) { + if (isPlainObject(candidate?.workflow?.target_model)) { + return candidate.workflow.target_model; + } + + return isPlainObject(candidate?.target_model) ? candidate.target_model : null; +} + +function artifactTargetKinds(targetModel) { + if (!isPlainObject(targetModel)) { + return []; + } + + return unique([ + ...toStringArray(targetModel.target_kinds), + ...toStringArray(targetModel.kinds), + optionalString(targetModel.target_kind), + optionalString(targetModel.kind), + ]); +} + +function buildArtifactInspectorWorkflowDiagnostics( + candidate, + contract, + guidanceProfile, + surfaceGuidance, + activityReview, + sourceInput, +) { + const groundedActivityArtifactEvidence = buildArtifactInspectorEvidence( + sourceInput, + contract, + ); + if ( + !groundedActivityArtifactEvidence.mandatory_satisfied && + !isArtifactInspectorWorkflowSelected( + candidate, + contract, + guidanceProfile, + surfaceGuidance, + ) + ) { + return null; + } + + const identifiers = getArtifactInspectorIdentifiers(contract); + const workflow = candidate.workflow ?? {}; + const topologySource = isPlainObject(workflow.topology) + ? workflow.topology + : isPlainObject(workflow.topology_contract) + ? workflow.topology_contract + : {}; + const observedTopologyKind = isPlainObject(workflow.topology) + ? optionalString(workflow.topology.kind) + : optionalString(workflow.topology) || optionalString(topologySource.kind); + const topologyContract = normalizeArtifactTopologyContract(candidate, contract, { + force: true, + }); + const workUnits = toWorkflowWorkUnitArray(workflow.work_units); + const workUnitIds = workflowWorkUnitIds(workUnits); + const diagnostics = []; + const push = (diagnostic) => { + diagnostics.push(createArtifactInspectorWorkflowDiagnostic(contract, diagnostic)); + }; + const suppliedActivityArtifactEvidence = + activityReview?.review?.evidence?.artifact_inspector ?? + activityReview?.guardrails?.artifact_inspector ?? + null; + const selectedSurfaceType = optionalString( + surfaceGuidance?.recommended_surface_type, + ); + const selectedGuidanceProfileId = optionalString(guidanceProfile?.profile_id); + const hasRoutingConflict = Boolean( + !groundedActivityArtifactEvidence.mandatory_satisfied || + groundedActivityArtifactEvidence.conflict || + suppliedActivityArtifactEvidence?.conflict || + optionalString(surfaceGuidance?.status) === "review_required" || + (selectedSurfaceType && selectedSurfaceType !== identifiers.surface_type) || + (selectedGuidanceProfileId && + selectedGuidanceProfileId !== identifiers.workflow_profile), + ); + + if (hasRoutingConflict) { + push({ + code: "JK_ARTIFACT_INSPECTOR_KEYWORD_ROUTING_CONFLICT", + field: "artifact_inspector.routing", + meaning: + "Artifact Inspector selection conflicts with grounded activity, surface, or workflow-profile evidence.", + expected: { + mandatory_evidence_satisfied: true, + activity_conflict: false, + surface_type: identifiers.surface_type, + workflow_profile: identifiers.workflow_profile, + }, + observed: { + mandatory_evidence_satisfied: + groundedActivityArtifactEvidence.mandatory_satisfied, + missing_mandatory_evidence: + groundedActivityArtifactEvidence.missing_mandatory_evidence, + activity_conflict: Boolean(groundedActivityArtifactEvidence.conflict), + matched_exclusion_evidence: + groundedActivityArtifactEvidence.matched_exclusion_evidence, + surface_review_status: optionalString(surfaceGuidance?.status) || null, + surface_type: selectedSurfaceType || null, + workflow_profile: selectedGuidanceProfileId || null, + }, + repair_instruction: + "Resolve missing mandatory evidence and any activity, surface, or profile conflict before accepting an Artifact Inspector workflow; topology and profile metadata cannot override grounded routing.", + }); + } + + if (!topologyContract) { + push({ + code: "JK_ARTIFACT_INSPECTOR_TOPOLOGY_CONTRACT_MISSING", + field: "workflow.topology_contract", + meaning: "The artifact-centered workflow has no explicit structured topology contract.", + expected: + "The normative artifact_centered topology object in workflow.topology or workflow.topology_contract.", + observed: workflow.topology, + repair_instruction: + "Provide the full artifact_centered topology object; the legacy topology string is only a downstream compatibility projection.", + }); + } + + if (observedTopologyKind !== identifiers.topology_kind) { + push({ + code: "JK_ARTIFACT_INSPECTOR_TOPOLOGY_KIND_INVALID", + field: isPlainObject(workflow.topology) + ? "workflow.topology.kind" + : "workflow.topology", + meaning: "The artifact-inspector workflow does not declare the artifact-centered topology kind.", + expected: identifiers.topology_kind, + observed: observedTopologyKind || null, + repair_instruction: `Set workflow.topology.kind to "${identifiers.topology_kind}" or use that legacy topology string.`, + }); + } + + workUnits.forEach((workUnit, index) => { + if (isPlainObject(workUnit) && !optionalString(workUnit.id)) { + push({ + code: "JK_ARTIFACT_INSPECTOR_WORK_UNIT_ID_MISSING", + field: `workflow.work_units[${index}].id`, + meaning: "A structured artifact work unit has no stable identifier.", + expected: "A non-empty work-unit id referenced by the topology.", + observed: workUnit.id, + repair_instruction: "Add a stable id to this work unit and use it in topology references.", + }); + } + }); + + const duplicateWorkUnitIds = duplicateWorkflowWorkUnitIds(workUnits); + if (duplicateWorkUnitIds.length > 0) { + push({ + code: "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + field: "workflow.work_units", + meaning: + "Artifact work-unit identifiers must be unique so topology references resolve unambiguously.", + expected: "Exactly one work-unit object for each canonical id.", + observed: duplicateWorkUnitIds, + repair_instruction: `Remove duplicate work-unit ids: ${duplicateWorkUnitIds.join(", ")}.`, + }); + } + + const canonicalWorkUnits = Array.isArray( + getArtifactInspectorModel(contract)?.work_units, + ) + ? getArtifactInspectorModel(contract).work_units.filter(isPlainObject) + : []; + const canonicalWorkUnitIds = canonicalWorkUnits + .map((workUnit) => optionalString(workUnit.id)) + .filter(Boolean); + const missingCanonicalWorkUnitIds = canonicalWorkUnitIds.filter( + (workUnitId) => !workUnitIds.includes(workUnitId), + ); + const unexpectedWorkUnitIds = workUnitIds.filter( + (workUnitId) => !canonicalWorkUnitIds.includes(workUnitId), + ); + + if (missingCanonicalWorkUnitIds.length > 0) { + push({ + code: "JK_ARTIFACT_INSPECTOR_WORK_UNIT_ID_MISSING", + field: "workflow.work_units", + meaning: "The artifact workflow omits one or more required work units.", + expected: canonicalWorkUnitIds, + observed: workUnitIds, + repair_instruction: `Add the missing canonical work units: ${missingCanonicalWorkUnitIds.join(", ")}.`, + }); + } + + if (unexpectedWorkUnitIds.length > 0) { + push({ + code: "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + field: "workflow.work_units", + meaning: + "The artifact workflow includes work-unit identifiers outside the canonical interaction model.", + expected: canonicalWorkUnitIds, + observed: workUnitIds, + repair_instruction: `Remove unexpected work-unit ids: ${unexpectedWorkUnitIds.join(", ")}.`, + }); + } + + for (const canonicalWorkUnit of canonicalWorkUnits) { + const workUnitIndex = workUnits.findIndex( + (workUnit) => + workflowWorkUnitId(workUnit) === optionalString(canonicalWorkUnit.id), + ); + if (workUnitIndex === -1) { + continue; + } + const observedWorkUnit = workUnits[workUnitIndex]; + for (const fieldName of [ + "participant_intent", + "system_responsibility", + ]) { + const expectedValue = optionalString(canonicalWorkUnit[fieldName]); + const observedValue = optionalString(observedWorkUnit[fieldName]); + if (observedValue !== expectedValue) { + push({ + code: "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + field: `workflow.work_units[${workUnitIndex}].${fieldName}`, + meaning: + "A required artifact work unit does not preserve its canonical participant intent or system responsibility.", + expected: expectedValue, + observed: observedValue || null, + repair_instruction: `Restore the canonical ${fieldName} for the ${canonicalWorkUnit.id} work unit.`, + }); + } + } + } + + const primaryObjectId = optionalString(topologyContract?.primary_object_id); + const canonicalPrimaryObjectId = + optionalString( + getArtifactInspectorModel(contract)?.topology?.primary_object_id, + ) || "artifact"; + + if (topologyContract && !primaryObjectId) { + push({ + code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + field: "workflow.topology.primary_object_id", + meaning: "No bounded rendered artifact is declared.", + expected: "A non-empty primary artifact id.", + observed: topologyContract?.primary_object_id, + repair_instruction: "Declare the bounded rendered artifact in workflow.topology.primary_object_id.", + }); + } else if (primaryObjectId !== canonicalPrimaryObjectId) { + push({ + code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + field: "workflow.topology.primary_object_id", + meaning: + "The artifact-centered topology does not preserve the canonical primary artifact identity.", + expected: canonicalPrimaryObjectId, + observed: primaryObjectId || null, + repair_instruction: `Set workflow.topology.primary_object_id to "${canonicalPrimaryObjectId}" and use that id for the artifact and target model.`, + }); + } + + const candidateArtifact = isPlainObject(workflow.artifact) + ? workflow.artifact + : isPlainObject(candidate.artifact) + ? candidate.artifact + : null; + const declaredArtifactId = optionalString( + candidateArtifact?.id ?? candidateArtifact?.artifact_id, + ); + + if (!candidateArtifact || !declaredArtifactId) { + push({ + code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + field: "workflow.artifact.id", + meaning: "No bounded rendered artifact is declared.", + expected: primaryObjectId || "artifact", + observed: declaredArtifactId || null, + repair_instruction: + "Declare workflow.artifact with the same stable id used by workflow.topology.primary_object_id.", + }); + } + + if (!optionalString(candidateArtifact?.boundary)) { + push({ + code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + field: "workflow.artifact.boundary", + meaning: "The rendered artifact has no explicit boundary declaration.", + expected: "A non-empty rendered artifact boundary description.", + observed: candidateArtifact?.boundary, + repair_instruction: + "Declare the bounded rendered region owned by the external artifact authority.", + }); + } + + if (declaredArtifactId && primaryObjectId && declaredArtifactId !== primaryObjectId) { + push({ + code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + field: "workflow.topology.primary_object_id", + meaning: "The artifact-centered topology references a different primary object than the declared artifact.", + expected: declaredArtifactId, + observed: primaryObjectId, + repair_instruction: "Point primary_object_id at the declared artifact id.", + }); + } + + const targetModel = artifactTargetModel(candidate); + const canonicalTargetModel = getArtifactInspectorModel(contract)?.target_model ?? {}; + const targetValuesAreCanonicalSubset = (value, canonicalValue) => { + const observed = toStringArray(value); + const allowed = toStringArray(canonicalValue); + return ( + observed.length > 0 && + observed.every((entry) => allowed.includes(entry)) + ); + }; + const targetFieldRequirements = [ + { + key: "target_kinds", + valid: targetValuesAreCanonicalSubset( + targetModel?.target_kinds, + canonicalTargetModel.target_kinds, + ), + expected: + canonicalTargetModel.target_kinds ?? + ["whole_artifact", "element", "text_range", "region", "point"], + repair: "Declare the semantic locus kinds the participant can select.", + }, + { + key: "target_identity_sources", + valid: targetValuesAreCanonicalSubset( + targetModel?.target_identity_sources, + canonicalTargetModel.target_identity_sources, + ), + expected: + canonicalTargetModel.target_identity_sources ?? + ["artifact_supplied", "participant_selection"], + repair: + "Declare whether target identity comes from the artifact or explicit participant selection.", + }, + { + key: "geometry_policy", + valid: + optionalString(targetModel?.geometry_policy) === + optionalString(canonicalTargetModel.geometry_policy), + expected: + optionalString(canonicalTargetModel.geometry_policy) || + "A read-only geometry and semantic re-anchoring policy.", + repair: + "Declare how target geometry stays stable, re-anchors, or becomes stale across artifact revisions.", + }, + { + key: "label_sources", + valid: targetValuesAreCanonicalSubset( + targetModel?.label_sources, + canonicalTargetModel.label_sources, + ), + expected: + canonicalTargetModel.label_sources ?? + ["artifact_supplied", "artifact_authorized_proxy", "Unavailable"], + repair: + "Declare the artifact-authorized sources for accessible target labels.", + }, + { + key: "artifact_interactivity", + valid: targetValuesAreCanonicalSubset( + targetModel?.artifact_interactivity, + canonicalTargetModel.artifact_interactivity, + ), + expected: + canonicalTargetModel.artifact_interactivity ?? ["static", "live", "hybrid"], + repair: + "Declare the supported artifact interactivity modes so native interaction precedence can be protected.", + }, + { + key: "native_interaction_precedence", + valid: + optionalString(targetModel?.native_interaction_precedence) === + optionalString(canonicalTargetModel.native_interaction_precedence), + expected: + optionalString(canonicalTargetModel.native_interaction_precedence) || + "A policy preserving native artifact actions until explicit inspection is active.", + repair: + "Declare when inspection may capture an action and when the artifact retains native interaction precedence.", + }, + ]; + + for (const requirement of targetFieldRequirements) { + if (!requirement.valid) { + push({ + code: "JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING", + field: `workflow.target_model.${requirement.key}`, + meaning: "The participant cannot reliably select and retain a semantic artifact locus.", + expected: requirement.expected, + observed: targetModel?.[requirement.key], + repair_instruction: requirement.repair, + }); + } + } + + const targetArtifactId = optionalString( + targetModel?.artifact_id ?? targetModel?.primary_object_id, + ); + + if (!targetArtifactId) { + push({ + code: "JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING", + field: "workflow.target_model.artifact_id", + meaning: "The target model is not attached to the declared primary artifact.", + expected: primaryObjectId || "workflow.topology.primary_object_id", + observed: targetArtifactId || null, + repair_instruction: + "Set workflow.target_model.artifact_id to the topology primary_object_id.", + }); + } else if (primaryObjectId && targetArtifactId !== primaryObjectId) { + push({ + code: "JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING", + field: "workflow.target_model.artifact_id", + meaning: "The target model is attached to a different artifact than the topology primary object.", + expected: primaryObjectId, + observed: targetArtifactId, + repair_instruction: "Attach the target model to workflow.topology.primary_object_id.", + }); } -} -function buildUiWorkflowCandidateMissingFields(candidate) { - const workflow = candidate.workflow; - const handoff = candidate.handoff; - const completionState = optionalString(workflow.completion_state); - const handoffCompletion = - optionalString(handoff.next_action).length > 0 && - optionalString(handoff.reason).length > 0; - const workUnits = toStringArray(workflow.work_units); - const surfaceSet = toSurfaceSetArray(candidate.surface_set); - const hasSurfaceStructure = - surfaceSet.some((surface) => toStringArray(surface.sections).length > 0); + const entryWorkUnitId = optionalString(topologyContract?.entry_work_unit_id); + + if ( + topologyContract && + (!entryWorkUnitId || !workUnitIds.includes(entryWorkUnitId)) + ) { + push({ + code: "JK_ARTIFACT_INSPECTOR_ENTRY_REFERENCE_INVALID", + field: "workflow.topology.entry_work_unit_id", + meaning: "The topology entry does not reference a declared work unit.", + expected: workUnitIds, + observed: entryWorkUnitId || null, + repair_instruction: "Reference one declared workflow.work_units id as the topology entry.", + }); + } + + const completionWorkUnitIds = toStringArray( + topologyContract?.completion_work_unit_ids, + ); + const invalidCompletionIds = completionWorkUnitIds.filter( + (id) => !workUnitIds.includes(id), + ); + + if ( + topologyContract && + (completionWorkUnitIds.length === 0 || + invalidCompletionIds.length > 0 || + !completionWorkUnitIds.includes("verify_result")) + ) { + push({ + code: "JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID", + field: "workflow.topology.completion_work_unit_ids", + meaning: "Artifact-local completion does not reference declared work units.", + expected: { + declared_work_unit_ids: workUnitIds, + required_artifact_local_completion: "verify_result", + }, + observed: completionWorkUnitIds, + repair_instruction: "Reference one or more declared work-unit ids that visibly complete the artifact-local activity.", + }); + } + + const transitions = Array.isArray(topologyContract?.transitions) + ? topologyContract.transitions + : []; + const invalidTransitions = transitions + .map((transition, index) => ({ + index, + from: optionalString(transition.from), + to: optionalString(transition.to), + })) + .filter( + (transition) => + !workUnitIds.includes(transition.from) || + !workUnitIds.includes(transition.to), + ); + const canonicalTransitions = Array.isArray( + getArtifactInspectorModel(contract)?.topology?.transitions, + ) + ? getArtifactInspectorModel(contract).topology.transitions + : []; + const transitionContractMismatch = + transitions.length !== canonicalTransitions.length || + canonicalTransitions.some((expectedTransition, index) => { + const observedTransition = transitions[index]; + return ( + !isPlainObject(observedTransition) || + optionalString(observedTransition.from) !== + optionalString(expectedTransition.from) || + optionalString(observedTransition.to) !== + optionalString(expectedTransition.to) || + optionalString(observedTransition.when) !== + optionalString(expectedTransition.when) + ); + }); + + if ( + topologyContract && + (transitions.length === 0 || + invalidTransitions.length > 0 || + transitionContractMismatch) + ) { + push({ + code: "JK_ARTIFACT_INSPECTOR_TRANSITION_REFERENCE_INVALID", + field: "workflow.topology.transitions", + meaning: "One or more topology transitions do not connect declared work units.", + expected: canonicalTransitions, + observed: + transitions.length === 0 + ? [] + : invalidTransitions.length > 0 + ? invalidTransitions + : transitions, + repair_instruction: + "Restore the ordered canonical transition contract so every required work unit is reachable from orient through artifact-local verification and recovery.", + }); + } + + const recoveryWorkUnitId = "recover"; + const hasRecoveryEntry = transitions.some( + (transition) => + optionalString(transition.to) === recoveryWorkUnitId && + workUnitIds.includes(optionalString(transition.from)), + ); + const hasRecoveryExit = transitions.some( + (transition) => + optionalString(transition.from) === recoveryWorkUnitId && + workUnitIds.includes(optionalString(transition.to)), + ); + + if ( + topologyContract && + (!workUnitIds.includes(recoveryWorkUnitId) || + !hasRecoveryEntry || + !hasRecoveryExit) + ) { + push({ + code: "JK_ARTIFACT_INSPECTOR_RECOVERY_PATH_MISSING", + field: "workflow.topology.transitions", + meaning: "The artifact workflow has no explicit connected recovery work unit.", + expected: + "Declared transitions enter and leave the recover work unit using valid work-unit ids.", + observed: transitions, + repair_instruction: + "Add valid inbound and outbound transitions for the recover work unit so cancellation or invalid work returns to a declared safe state.", + }); + } + + const workflowStateGroups = isPlainObject(workflow.state_groups) + ? workflow.state_groups + : null; + const canonicalStateGroups = isPlainObject( + getArtifactInspectorModel(contract)?.state_groups, + ) + ? getArtifactInspectorModel(contract).state_groups + : {}; + const canonicalStateGroupIds = Object.keys(canonicalStateGroups); + const activityActivatedStateGroups = deriveArtifactInspectorActiveStateGroups({ + source_input: sourceInput, + workflow: { + ...workflow, + state_groups: {}, + }, + activity_model: activityReview?.candidate?.activity_model, + interaction_contract: activityReview?.candidate?.interaction_contract, + }); + + if (!workflowStateGroups) { + push({ + code: "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + field: "workflow.state_groups", + meaning: "The artifact workflow does not declare its active state groups.", + expected: { core: canonicalStateGroups.core ?? [] }, + observed: workflow.state_groups, + repair_instruction: + "Declare the core state group and only the conditional state groups activated by the activity.", + }); + } else { + const observedGroupIds = Object.keys(workflowStateGroups); + const missingActivityGroups = activityActivatedStateGroups.filter( + (groupId) => !observedGroupIds.includes(groupId), + ); + const unexpectedGroupIds = observedGroupIds.filter( + (groupId) => !canonicalStateGroupIds.includes(groupId), + ); + const inventedConditionalGroupIds = observedGroupIds.filter( + (groupId) => !activityActivatedStateGroups.includes(groupId), + ); + if (!observedGroupIds.includes("core") || unexpectedGroupIds.length > 0) { + push({ + code: "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + field: "workflow.state_groups", + meaning: + "The artifact workflow must declare core and only canonical conditional state groups.", + expected: { + required: ["core"], + allowed: canonicalStateGroupIds, + }, + observed: observedGroupIds, + repair_instruction: + "Restore core and remove unknown state-group ids; add conditional groups only when the activity activates them.", + }); + } + if (missingActivityGroups.length > 0) { + push({ + code: "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + field: "workflow.state_groups", + meaning: + "The artifact workflow omits conditional state groups activated by the reviewed activity.", + expected: activityActivatedStateGroups, + observed: observedGroupIds, + repair_instruction: `Add the activity-required state groups from the registry: ${missingActivityGroups.join(", ")}.`, + }); + } + if (inventedConditionalGroupIds.length > 0) { + push({ + code: "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + field: "workflow.state_groups", + meaning: + "The artifact workflow invents conditional state groups that the reviewed activity does not activate.", + expected: activityActivatedStateGroups, + observed: observedGroupIds, + repair_instruction: `Remove inactive conditional state groups: ${inventedConditionalGroupIds.join(", ")}.`, + }); + } + for (const groupId of observedGroupIds.filter((id) => + canonicalStateGroupIds.includes(id), + )) { + const expectedStates = toStringArray(canonicalStateGroups[groupId]); + const observedStates = toStringArray(workflowStateGroups[groupId]); + if ( + observedStates.length !== expectedStates.length || + expectedStates.some((state) => !observedStates.includes(state)) + ) { + push({ + code: "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + field: `workflow.state_groups.${groupId}`, + meaning: + "An active Artifact Inspector state group does not match the canonical registry definition.", + expected: expectedStates, + observed: observedStates, + repair_instruction: `Restore the canonical ${groupId} state set from the interaction-model registry.`, + }); + } + } + } return { - workflow_structure: workUnits.length === 0 && !hasSurfaceStructure, - primary_actions: toStringArray(workflow.primary_actions).length === 0, - decision_support: toStringArray(workflow.decision_points).length === 0, - surface_sections: !hasSurfaceStructure, - completion_or_handoff: - completionState.length === 0 && !handoffCompletion, + selected: true, + surface_type: identifiers.surface_type, + workflow_profile: identifiers.workflow_profile, + topology_kind: identifiers.topology_kind, + active_state_groups: activityActivatedStateGroups, + valid: diagnostics.length === 0, + diagnostics, }; } @@ -3415,7 +5794,18 @@ function buildUiWorkflowCandidateGuardrails( contract, activityReview, surfaceGuidance, + guidanceProfile, + sourceInput, ) { + const artifactInspector = buildArtifactInspectorWorkflowDiagnostics( + candidate, + contract, + guidanceProfile, + surfaceGuidance, + activityReview, + sourceInput, + ); + return { candidate_primary_terms_detected: buildUiWorkflowPrimaryTermsDetected( candidate, @@ -3430,6 +5820,7 @@ function buildUiWorkflowCandidateGuardrails( surfaceGuidance, contract, ), + ...(artifactInspector ? { artifact_inspector: artifactInspector } : {}), }; } @@ -3444,6 +5835,7 @@ function normalizeUiWorkflowCandidate( { contract, surfaceGuidance, + guidanceProfile, stepperEligibility, } = {}, ) { @@ -3472,11 +5864,46 @@ function normalizeUiWorkflowCandidate( candidate, candidatePrimaryTermsDetected, ); - const workUnits = sanitizeUiWorkflowList( - workflow.work_units, - candidatePrimaryTermsDetected, + const artifactInspectorSelected = isArtifactInspectorWorkflowSelected( + candidate, + contract, + guidanceProfile, + surfaceGuidance, ); - const topology = inferWorkflowTopology(candidate, surfaceGuidance, contract); + const workUnits = artifactInspectorSelected + ? cloneWorkflowStructuredValue(toWorkflowWorkUnitArray(workflow.work_units)) + : sanitizeUiWorkflowList( + workflow.work_units, + candidatePrimaryTermsDetected, + ); + const topology = artifactInspectorSelected + ? getArtifactInspectorIdentifiers(contract).topology_kind + : inferWorkflowTopology(candidate, surfaceGuidance, contract); + const topologyContract = artifactInspectorSelected + ? normalizeArtifactTopologyContract(candidate, contract, { force: true }) + : null; + const workflowArtifact = isPlainObject(workflow.artifact) + ? cloneWorkflowStructuredValue(workflow.artifact) + : artifactInspectorSelected && isPlainObject(candidate.artifact) + ? cloneWorkflowStructuredValue(candidate.artifact) + : null; + const workflowTargetModel = isPlainObject(workflow.target_model) + ? cloneWorkflowStructuredValue(workflow.target_model) + : artifactInspectorSelected && isPlainObject(candidate.target_model) + ? cloneWorkflowStructuredValue(candidate.target_model) + : null; + const workflowStateGroups = isPlainObject(workflow.state_groups) + ? cloneWorkflowStructuredValue(workflow.state_groups) + : null; + const topLevelArtifact = isPlainObject(candidate.artifact) + ? cloneWorkflowStructuredValue(candidate.artifact) + : null; + const topLevelTargetModel = isPlainObject(candidate.target_model) + ? cloneWorkflowStructuredValue(candidate.target_model) + : null; + const topLevelStateGroups = isPlainObject(candidate.state_groups) + ? cloneWorkflowStructuredValue(candidate.state_groups) + : null; return { workflow: { @@ -3486,7 +5913,11 @@ function normalizeUiWorkflowCandidate( "Workflow review", ), topology, + ...(topologyContract ? { topology_contract: topologyContract } : {}), work_units: workUnits, + ...(workflowArtifact ? { artifact: workflowArtifact } : {}), + ...(workflowTargetModel ? { target_model: workflowTargetModel } : {}), + ...(workflowStateGroups ? { state_groups: workflowStateGroups } : {}), stepper_eligibility: stepperEligibility, primary_actions: sanitizeUiWorkflowList( workflow.primary_actions, @@ -3502,6 +5933,13 @@ function normalizeUiWorkflowCandidate( activityCandidate?.interaction_contract?.completion ?? "", ), }, + ...(!artifactInspectorSelected && topLevelArtifact + ? { artifact: topLevelArtifact } + : {}), + ...(!artifactInspectorSelected && topLevelTargetModel + ? { target_model: topLevelTargetModel } + : {}), + ...(topLevelStateGroups ? { state_groups: topLevelStateGroups } : {}), surface_set: surfaceSet, product_terms: sanitizedUserTerms, handoff: { @@ -3573,6 +6011,11 @@ function buildUiWorkflowQuestions(activityReview, candidateGuardrails) { ); } + for (const diagnostic of + candidateGuardrails.artifact_inspector?.diagnostics ?? []) { + questions.push(diagnostic.repair_instruction); + } + return selectTargetedQuestionsFromCandidates(questions); } @@ -3619,6 +6062,7 @@ function buildUiWorkflowConfidence(activityReview, candidateGuardrails) { activityReview.review_status !== "ready_for_review" || hasUiWorkflowMissingField(candidateGuardrails.candidate_missing_fields) || candidateGuardrails.stepper_eligibility?.blocked || + candidateGuardrails.artifact_inspector?.valid === false || candidateGuardrails.candidate_primary_terms_detected.length > 0 || candidateGuardrails.candidate_primary_meta_terms_detected.length > 0 ) { @@ -3639,6 +6083,7 @@ function buildUiWorkflowReviewPacket( contract, guidanceProfile = null, surfaceReview = null, + sourceInput = "", ) { const sourceReady = activityReview.review_status === "ready_for_review"; const surfaceGuidance = summarizeSurfaceReview(surfaceReview); @@ -3647,10 +6092,28 @@ function buildUiWorkflowReviewPacket( contract, activityReview, surfaceGuidance, + guidanceProfile, + sourceInput, ); + const validatedArtifactInspector = + candidateGuardrails.artifact_inspector?.valid === true + ? candidateGuardrails.artifact_inspector + : null; + const resolvedSurfaceGuidance = + validatedArtifactInspector && + !optionalString(surfaceGuidance?.recommended_surface_type) + ? { + recommended_surface_type: validatedArtifactInspector.surface_type, + confidence: "validated_workflow", + blocked_surface_types: [], + ...buildSurfaceImplications(validatedArtifactInspector.surface_type), + } + : surfaceGuidance; const candidateReady = !hasUiWorkflowMissingField(candidateGuardrails.candidate_missing_fields) && !candidateGuardrails.stepper_eligibility?.blocked && + candidateGuardrails.artifact_inspector?.valid !== false && + resolvedSurfaceGuidance?.status !== "review_required" && candidateGuardrails.candidate_primary_terms_detected.length === 0 && candidateGuardrails.candidate_primary_meta_terms_detected.length === 0; const normalizedCandidate = normalizeUiWorkflowCandidate( @@ -3659,7 +6122,8 @@ function buildUiWorkflowReviewPacket( candidateGuardrails.candidate_primary_terms_detected, { contract, - surfaceGuidance, + surfaceGuidance: resolvedSurfaceGuidance, + guidanceProfile, stepperEligibility: candidateGuardrails.stepper_eligibility, }, ); @@ -3677,12 +6141,17 @@ function buildUiWorkflowReviewPacket( source: { ...source, input_excerpt: activityReview.source?.input_excerpt, + ...(candidateGuardrails.artifact_inspector && + typeof sourceInput === "string" && + sourceInput.trim().length > 0 + ? { reviewed_activity_input: sourceInput.trim() } + : {}), }, ...(guidanceProfile ? { guidance_profile: guidanceProfile } : {}), - ...(surfaceGuidance + ...(resolvedSurfaceGuidance ? { - surface_type: surfaceGuidance.recommended_surface_type, - surface_guidance: surfaceGuidance, + surface_type: resolvedSurfaceGuidance.recommended_surface_type, + surface_guidance: resolvedSurfaceGuidance, } : {}), activity_review: activityReview, @@ -3706,12 +6175,15 @@ function buildUiWorkflowReviewPacket( candidateGuardrails.candidate_primary_terms_detected, candidate_primary_meta_terms_detected: candidateGuardrails.candidate_primary_meta_terms_detected, + ...(candidateGuardrails.artifact_inspector + ? { artifact_inspector: candidateGuardrails.artifact_inspector } + : {}), }, assumptions: buildUiWorkflowReviewAssumptions( activityReview, source, guidanceProfile, - surfaceGuidance, + resolvedSurfaceGuidance, ), confidence: buildUiWorkflowConfidence(activityReview, candidateGuardrails), targeted_questions: buildUiWorkflowQuestions(activityReview, candidateGuardrails), @@ -3725,24 +6197,41 @@ function buildUiWorkflowReviewPacket( candidate_primary_meta_terms_detected: candidateGuardrails.candidate_primary_meta_terms_detected, stepper_eligibility: candidateGuardrails.stepper_eligibility, + ...(candidateGuardrails.artifact_inspector + ? { artifact_inspector: candidateGuardrails.artifact_inspector } + : {}), implementation_terms_detected: activityReview.guardrails?.implementation_terms_detected ?? [], disclosure_translation_candidates: activityReview.guardrails?.disclosure_translation_candidates ?? [], ...(guidanceProfile ? { guidance_profile_id: guidanceProfile.profile_id } : {}), - ...(surfaceGuidance - ? { recommended_surface_type: surfaceGuidance.recommended_surface_type } + ...(resolvedSurfaceGuidance + ? { + recommended_surface_type: + resolvedSurfaceGuidance.recommended_surface_type, + } : {}), }, }; + if (validatedArtifactInspector) { + packet.source.artifact_inspector_review_integrity = + createArtifactInspectorIntegritySeal( + "workflow_review", + artifactInspectorWorkflowReviewIntegrityPayload(packet, contract), + ); + } + assertNoStyleFields(packet); return packet; } -function buildUiWorkflowCandidateShapeGuide() { - return { +function buildUiWorkflowCandidateShapeGuide( + contract, + { artifactInspector = false } = {}, +) { + const guide = { workflow: { surface_name: "Short domain name for the workflow.", topology: @@ -3774,6 +6263,49 @@ function buildUiWorkflowCandidateShapeGuide() { reveal_contexts: ["Contexts where diagnostics may be shown."], }, }; + + if (!artifactInspector) { + return guide; + } + + const model = getArtifactInspectorModel(contract) ?? {}; + const identifiers = getArtifactInspectorIdentifiers(contract); + const topology = isPlainObject(model.topology) + ? cloneWorkflowStructuredValue(model.topology) + : { + kind: identifiers.topology_kind, + primary_object_id: "artifact", + entry_work_unit_id: "orient", + completion_work_unit_ids: ["verify_result"], + transitions: [], + }; + + guide.workflow.topology = topology; + guide.workflow.work_units = Array.isArray(model.work_units) + ? cloneWorkflowStructuredValue(model.work_units) + : [ + { + id: "orient", + participant_intent: "What the participant is trying to understand or do.", + system_responsibility: "What the UI must preserve or reveal.", + }, + ]; + guide.workflow.artifact = { + id: optionalString(topology.primary_object_id) || "artifact", + boundary: "The bounded rendered artifact that remains primary.", + }; + guide.workflow.target_model = isPlainObject(model.target_model) + ? cloneWorkflowStructuredValue(model.target_model) + : { + target_kinds: ["whole_artifact", "element", "text_range", "region", "point"], + }; + guide.workflow.state_groups = isPlainObject(model.state_groups) + ? { + core: cloneWorkflowStructuredValue(model.state_groups.core ?? []), + } + : {}; + + return guide; } function buildUiWorkflowReviewContext(activityReview) { @@ -3816,18 +6348,38 @@ export function buildUiWorkflowCandidateRequest({ ); } + const resolvedContract = contract ?? loadActivityContract(contractPath); const guidanceProfile = profileId === undefined || profileId === null ? null : resolveUiWorkflowGuidanceProfile( - contract ?? loadActivityContract(contractPath), + resolvedContract, profileId, ); + const surfaceGuidance = summarizeSurfaceReview(surfaceReview); + const artifactInspectorRequested = isArtifactInspectorWorkflowSelected( + { workflow: {} }, + resolvedContract, + guidanceProfile, + surfaceGuidance, + ) || Boolean( + activityReview.review?.evidence?.artifact_inspector?.mandatory_satisfied || + activityReview.guardrails?.artifact_inspector?.mandatory_satisfied, + ); const userPayload = { brief: brief.trim(), activity_review: buildUiWorkflowReviewContext(activityReview), - candidate_shape: buildUiWorkflowCandidateShapeGuide(), + candidate_shape: buildUiWorkflowCandidateShapeGuide(resolvedContract, { + artifactInspector: artifactInspectorRequested, + }), + ...(artifactInspectorRequested + ? { + artifact_inspector_state_group_catalog: + cloneWorkflowStructuredValue( + getArtifactInspectorModel(resolvedContract)?.state_groups ?? {}, + ), + } + : {}), }; - const surfaceGuidance = summarizeSurfaceReview(surfaceReview); if (guidanceProfile) { userPayload.guidance_profile = guidanceProfile; @@ -3845,6 +6397,9 @@ export function buildUiWorkflowCandidateRequest({ "You propose a reviewable JudgmentKit UI workflow candidate.", "Return only JSON whose root object matches the UI workflow candidate shape.", "Ground topology, work units, coordinated surfaces, actions, decisions, handoff, and user-facing terms in the source brief and activity review.", + artifactInspectorRequested + ? "Use the artifact_centered topology object, stable structured work-unit ids, one artifact boundary, a semantic target model, explicit recovery transitions, artifact-local completion, and only the conditional state groups the activity needs." + : "", "Do not use staged_flow or numbered wizard/stepper framing unless the source has strong staged-flow intent such as explicit wizard wording, ordered setup/onboarding, form validation sequence, or strict dependency order.", "Keep implementation terms and JudgmentKit review-packet terms out of workflow, surface_set, and handoff.", "Implementation terms may appear only in diagnostics when they are diagnostic.", @@ -3905,6 +6460,8 @@ export function createUiWorkflowProposer({ ); } + const resolvedContract = contract ?? loadActivityContract(contractPath); + return async function proposeUiWorkflowCandidate({ brief, activity_review: activityReview, @@ -3916,12 +6473,11 @@ export function createUiWorkflowProposer({ activity_review: activityReview, profile_id: requestProfileId ?? defaultProfileId, surface_review: surfaceReview, - contract, - contractPath, + contract: resolvedContract, }); const candidate = parseCandidateResponse(await callModel(request)); - assertUiWorkflowCandidateShape(candidate); + assertUiWorkflowCandidateShape(candidate, resolvedContract); return candidate; }; @@ -3937,11 +6493,11 @@ export function reviewUiWorkflowCandidate(input, candidate, options = {}) { ...analysisOptions } = options; - assertUiWorkflowCandidateShape(candidate); + const contract = analysisOptions.contract ?? loadActivityContract(analysisOptions.contractPath); + assertUiWorkflowCandidateShape(candidate, contract); const activityReview = providedActivityReview ?? createActivityModelReview(input, analysisOptions); - const contract = analysisOptions.contract ?? loadActivityContract(analysisOptions.contractPath); const guidanceProfile = resolveUiWorkflowGuidanceProfile(contract, profileId); const resolvedSurfaceType = providedSurfaceType ? resolveSurfaceType(contract, providedSurfaceType).surface_type @@ -3964,6 +6520,7 @@ export function reviewUiWorkflowCandidate(input, candidate, options = {}) { contract, guidanceProfile, surfaceReview, + input, ); } @@ -4383,6 +6940,96 @@ function buildCognitiveDimensionsReviewFindings({ optionalString(interactionContract.primary_decision), ]).filter(Boolean); const findings = []; + const artifactInspectorSelected = + surfaceType === getArtifactInspectorIdentifiers(contract).surface_type; + + if (artifactInspectorSelected) { + const hasSemanticLocus = /\b(?:semantic\s+)?(?:locus|selected (?:element|passage|range|region|node|point|control)|active (?:element|passage|range|region|node|point|control))\b/.test( + normalizedPrimary, + ); + const hasLocusRelativeContext = /\b(?:context|evidence|authority|action|feedback|reason|receipt)\b[^.]{0,140}\b(?:locus|selected|active|attached|anchored|beside|local)\b/.test( + normalizedPrimary, + ); + const hasPreviewCommitSeparation = + /\bpreview\b/.test(normalizedPrimary) && + /\b(?:commit|confirm|complete|result)\b/.test(normalizedPrimary); + const hasLocalEvaluation = /\b(?:validate|supported|incompatible|unavailable|stale|ambiguous|blocked|local (?:feedback|result|status))\b/.test( + normalizedPrimary, + ); + const hasBoundedRecovery = /\b(?:back|cancel|recover|retry|reconcile|last safe|uncommitted)\b/.test( + normalizedPrimary, + ); + + if (!hasSemanticLocus) { + findings.push(createCognitiveFinding({ + dimension: "closeness_of_mapping", + evidence: + "Artifact Inspector candidate does not name the semantic artifact locus that actions and context operate on.", + user_cost: + "The participant cannot tell which part of the artifact an action will inspect or change.", + repair_instruction: + "Name the selectable semantic locus and keep every action mapped to that active target.", + acceptance_check: + "The selected locus and the action that operates on it are legible together.", + })); + } + + if (!hasLocusRelativeContext) { + findings.push(createCognitiveFinding({ + dimension: "hidden_dependencies", + evidence: + "Artifact Inspector support is not visibly or semantically attached to the active locus.", + user_cost: + "The participant must remember which evidence, authority, or reason applies to the selected target.", + repair_instruction: + "Attach decision-changing context, authority, feedback, and receipts to the active semantic locus.", + acceptance_check: + "Every support object exposes its relation to the active locus without relying on memory.", + })); + } + + if (!hasPreviewCommitSeparation) { + findings.push(createCognitiveFinding({ + dimension: "premature_commitment", + evidence: + "Artifact Inspector candidate does not distinguish reversible preview from commitment or durable result.", + user_cost: + "A participant can mistake provisional state for a committed outcome or commit before validation.", + repair_instruction: + "Declare separate preview, local validation, explicit commitment when consequential, and durable result states.", + acceptance_check: + "Preview and committed result remain visibly and semantically distinct with no default affirmative.", + })); + } + + if (!hasLocalEvaluation) { + findings.push(createCognitiveFinding({ + dimension: "progressive_evaluation", + evidence: + "Artifact Inspector candidate lacks locus-local supported, invalid, unavailable, stale, ambiguous, or blocked evaluation state.", + user_cost: + "The participant cannot evaluate the relation or action before completing it.", + repair_instruction: + "Show validation and failure meaning on or immediately beside the active locus before completion.", + acceptance_check: + "The participant can evaluate a preview locally before commitment or bounded completion.", + })); + } + + if (!hasBoundedRecovery) { + findings.push(createCognitiveFinding({ + dimension: "viscosity", + evidence: + "Artifact Inspector candidate lacks Back, cancellation, retry, or reconciliation behavior tied to uncommitted state.", + user_cost: + "Recovering from a wrong target or invalid preview may discard committed work or require restarting the inspection.", + repair_instruction: + "Add a recovery path that reverses only uncommitted state and preserves committed results.", + acceptance_check: + "Back and cancellation return to the last safe state without erasing committed results.", + })); + } + } if (implementationTermsDetected.length > 0 && !setupDiagnosticContext) { findings.push(createCognitiveFinding({ @@ -4782,36 +7429,296 @@ export async function createModelAssistedUiWorkflowReview(input, options = {}) { }); } -function assertReadyUiWorkflowReviewShape(workflowReview) { - if (!isPlainObject(workflowReview.candidate)) { - throw new JudgmentKitInputError( - "createUiGenerationHandoff requires a workflow_review with candidate.", +function assertReadyUiWorkflowReviewShape(workflowReview) { + if (!isPlainObject(workflowReview.candidate)) { + throw new JudgmentKitInputError( + "createUiGenerationHandoff requires a workflow_review with candidate.", + ); + } + + if (!isPlainObject(workflowReview.candidate.workflow)) { + throw new JudgmentKitInputError( + "createUiGenerationHandoff requires candidate.workflow.", + ); + } + + if (toSurfaceSetArray(workflowReview.candidate.surface_set).length === 0) { + throw new JudgmentKitInputError( + "createUiGenerationHandoff requires candidate.surface_set.", + ); + } + + if (!isPlainObject(workflowReview.candidate.handoff)) { + throw new JudgmentKitInputError( + "createUiGenerationHandoff requires candidate.handoff.", + ); + } + + if (!isPlainObject(workflowReview.activity_review?.candidate)) { + throw new JudgmentKitInputError( + "createUiGenerationHandoff requires activity_review.candidate.", + ); + } +} + +function objectHasTruthyReviewFlag(value) { + return isPlainObject(value) && Object.values(value).some(Boolean); +} + +function artifactInspectorWorkflowReviewIntegrityPayload( + workflowReview, + contract, +) { + const source = isPlainObject(workflowReview?.source) + ? { ...workflowReview.source } + : workflowReview?.source; + if (isPlainObject(source)) { + delete source.artifact_inspector_review_integrity; + } + + return { + contract_model: getArtifactInspectorModel(contract), + packet: { + ...workflowReview, + source, + }, + }; +} + +function artifactInspectorBoundaryIntegrityPayload(packet) { + const source = isPlainObject(packet?.source) + ? { ...packet.source } + : packet?.source; + if (isPlainObject(source)) { + delete source.artifact_inspector_boundary_integrity; + } + + return { + ...packet, + source, + }; +} + +function assertUiWorkflowReviewStillReady(workflowReview, contract) { + const activityReview = workflowReview.activity_review; + const activityEvidence = activityReview?.review?.evidence ?? {}; + const retainedActivityCandidateMissingFields = + activityReview?.guardrails?.candidate_missing_fields ?? {}; + const recomputedActivityCandidateMissingFields = + buildCandidateMissingFields(activityReview?.candidate ?? {}); + const retainedActivityPrimaryTerms = Array.isArray( + activityReview?.guardrails?.candidate_primary_terms_detected, + ) + ? activityReview.guardrails.candidate_primary_terms_detected + : []; + const recomputedActivityPrimaryTerms = buildCandidatePrimaryTermsDetected( + activityReview?.candidate ?? {}, + contract, + ); + const retainedSourceMissingEvidence = + workflowReview.guardrails?.source_missing_evidence ?? {}; + const activitySourceMissingEvidence = + activityReview?.guardrails?.source_missing_evidence ?? + activityReview?.guardrails?.missing_evidence ?? + {}; + const retainedCandidateMissingFields = + workflowReview.guardrails?.candidate_missing_fields ?? {}; + const recomputedCandidateMissingFields = buildUiWorkflowCandidateMissingFields( + workflowReview.candidate, + ); + const recomputedPrimaryTerms = buildUiWorkflowPrimaryTermsDetected( + workflowReview.candidate, + contract, + ); + const recomputedPrimaryMetaTerms = buildCandidatePrimaryMetaTermsDetected( + workflowReview.candidate, + ); + const failures = []; + const requireReady = (condition, field, observed) => { + if (!condition) failures.push({ field, observed }); + }; + + requireReady( + activityReview?.review_status === "ready_for_review", + "activity_review.review_status", + activityReview?.review_status ?? null, + ); + requireReady( + workflowReview.guardrails?.activity_review_status === "ready_for_review", + "guardrails.activity_review_status", + workflowReview.guardrails?.activity_review_status ?? null, + ); + requireReady( + workflowReview.review?.evidence?.activity_review_ready === true, + "review.evidence.activity_review_ready", + workflowReview.review?.evidence?.activity_review_ready ?? null, + ); + for (const field of ["activity", "domain_vocabulary", "decision", "outcome"]) { + requireReady( + activityEvidence[field] === true, + `activity_review.review.evidence.${field}`, + activityEvidence[field] ?? null, ); } + requireReady( + !objectHasTruthyReviewFlag(retainedSourceMissingEvidence), + "guardrails.source_missing_evidence", + retainedSourceMissingEvidence, + ); + requireReady( + !objectHasTruthyReviewFlag(activitySourceMissingEvidence), + "activity_review.guardrails.source_missing_evidence", + activitySourceMissingEvidence, + ); + requireReady( + !objectHasTruthyReviewFlag(retainedActivityCandidateMissingFields) && + !objectHasTruthyReviewFlag(recomputedActivityCandidateMissingFields), + "activity_review.candidate", + recomputedActivityCandidateMissingFields, + ); + requireReady( + retainedActivityPrimaryTerms.length === 0 && + recomputedActivityPrimaryTerms.length === 0, + "activity_review.guardrails.candidate_primary_terms_detected", + recomputedActivityPrimaryTerms, + ); + requireReady( + !objectHasTruthyReviewFlag(retainedCandidateMissingFields), + "guardrails.candidate_missing_fields", + retainedCandidateMissingFields, + ); + requireReady( + !objectHasTruthyReviewFlag(recomputedCandidateMissingFields), + "candidate", + recomputedCandidateMissingFields, + ); + requireReady( + toStringArray(workflowReview.guardrails?.candidate_primary_terms_detected) + .length === 0 && recomputedPrimaryTerms.length === 0, + "guardrails.candidate_primary_terms_detected", + recomputedPrimaryTerms, + ); + requireReady( + toStringArray( + workflowReview.guardrails?.candidate_primary_meta_terms_detected, + ).length === 0 && recomputedPrimaryMetaTerms.length === 0, + "guardrails.candidate_primary_meta_terms_detected", + recomputedPrimaryMetaTerms, + ); - if (!isPlainObject(workflowReview.candidate.workflow)) { - throw new JudgmentKitInputError( - "createUiGenerationHandoff requires candidate.workflow.", + const artifactInspectorSelected = isArtifactInspectorWorkflowSelected( + workflowReview.candidate, + contract, + workflowReview.guidance_profile, + workflowReview.surface_guidance, + ); + let reviewedActiveStateGroups = []; + if (artifactInspectorSelected) { + const reviewedArtifactEvidence = + workflowReview.review?.evidence?.artifact_inspector; + const reviewedArtifactGuardrail = + workflowReview.guardrails?.artifact_inspector; + const activityArtifactEvidence = + activityEvidence.artifact_inspector ?? + activityReview?.guardrails?.artifact_inspector; + const evidenceStateGroups = toStringArray( + reviewedArtifactEvidence?.active_state_groups, ); - } - - if (toSurfaceSetArray(workflowReview.candidate.surface_set).length === 0) { - throw new JudgmentKitInputError( - "createUiGenerationHandoff requires candidate.surface_set.", + const guardrailStateGroups = toStringArray( + reviewedArtifactGuardrail?.active_state_groups, ); - } - - if (!isPlainObject(workflowReview.candidate.handoff)) { - throw new JudgmentKitInputError( - "createUiGenerationHandoff requires candidate.handoff.", + reviewedActiveStateGroups = ARTIFACT_INSPECTOR_STATE_GROUP_IDS.filter( + (groupId) => guardrailStateGroups.includes(groupId), + ); + const reviewedActivityInput = optionalRawString( + workflowReview.source?.reviewed_activity_input, + ); + const revalidatedArtifactGuardrail = reviewedActivityInput + ? buildArtifactInspectorWorkflowDiagnostics( + workflowReview.candidate, + contract, + workflowReview.guidance_profile, + workflowReview.surface_guidance, + activityReview, + reviewedActivityInput, + ) + : null; + const independentlyDerivedActiveStateGroups = toStringArray( + revalidatedArtifactGuardrail?.active_state_groups, + ); + const revalidatedStateGroupDiagnostics = Array.isArray( + revalidatedArtifactGuardrail?.diagnostics, + ) + ? revalidatedArtifactGuardrail.diagnostics.filter( + (diagnostic) => + optionalString(diagnostic?.code) === + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + ) + : []; + requireReady( + reviewedActivityInput.length > 0 && + revalidatedArtifactGuardrail !== null && + revalidatedStateGroupDiagnostics.length === 0, + "guardrails.artifact_inspector.active_state_groups", + { + reviewed_activity_input_present: reviewedActivityInput.length > 0, + diagnostics: revalidatedStateGroupDiagnostics, + }, + ); + requireReady( + reviewedArtifactEvidence?.valid === true && + reviewedArtifactGuardrail?.valid === true, + "guardrails.artifact_inspector.valid", + { + review: reviewedArtifactEvidence?.valid ?? null, + guardrails: reviewedArtifactGuardrail?.valid ?? null, + }, + ); + requireReady( + artifactInspectorStateGroupsMatch( + evidenceStateGroups, + guardrailStateGroups, + ) && + artifactInspectorStateGroupsMatch( + guardrailStateGroups, + reviewedActiveStateGroups, + ) && + artifactInspectorStateGroupsMatch( + reviewedActiveStateGroups, + independentlyDerivedActiveStateGroups, + ) && + reviewedActiveStateGroups.includes("core"), + "guardrails.artifact_inspector.active_state_groups", + { + review: evidenceStateGroups, + guardrails: guardrailStateGroups, + independently_derived: independentlyDerivedActiveStateGroups, + }, + ); + requireReady( + activityArtifactEvidence?.mandatory_satisfied === true && + activityArtifactEvidence?.conflict !== true && + toStringArray(activityArtifactEvidence?.missing_mandatory_evidence) + .length === 0, + "activity_review.review.evidence.artifact_inspector", + activityArtifactEvidence ?? null, ); } - if (!isPlainObject(workflowReview.activity_review?.candidate)) { + if (failures.length > 0) { throw new JudgmentKitInputError( - "createUiGenerationHandoff requires activity_review.candidate.", + "UI generation handoff requires the nested reviewed evidence and candidate guardrails to remain ready.", + { + code: "handoff_blocked", + details: { + reason: "review_packet_no_longer_ready", + failures, + }, + }, ); } + + return reviewedActiveStateGroups; } function termEntriesToNames(entries) { @@ -6600,6 +9507,33 @@ function normalizeDefaultAiNativeDesignSystem(sourcePolicy, fallbackPolicy) { }; } +function canonicalJudgmentKitDesignSystemAuthority() { + const implementationContract = getContractUiImplementationContract( + loadActivityContract(), + ); + const defaultDesignSystem = normalizeDefaultAiNativeDesignSystem( + implementationContract.default_ai_native_design_system, + DEFAULT_AI_NATIVE_DESIGN_SYSTEM, + ); + const visualTokenAdapter = normalizeVisualTokenAdapter( + implementationContract.visual_token_adapter, + DEFAULT_VISUAL_TOKEN_ADAPTER, + ); + const designSystemSource = normalizeDesignSystemSource( + implementationContract.design_system_source, + { + visualTokenAdapter, + componentContracts: defaultDesignSystem.component_contracts, + }, + ); + + return { + defaultDesignSystem, + visualTokenAdapter, + designSystemSource, + }; +} + function firstDefined(...values) { return values.find((value) => value !== undefined && value !== null); } @@ -8295,6 +11229,232 @@ function localComponentAuthorityIsActive(authority) { return policy.mode === "repo_local" || policy.enforcement === "required"; } +function deriveArtifactInspectorActiveStateGroups(source = {}) { + const explicit = toStringArray( + source.artifact_inspector?.active_state_groups ?? + source.artifactInspector?.activeStateGroups, + ); + + if (explicit.length > 0) { + return ARTIFACT_INSPECTOR_STATE_GROUP_IDS.filter((groupId) => + explicit.includes(groupId), + ); + } + + const declaredStateGroups = isPlainObject(source.workflow?.state_groups) + ? source.workflow.state_groups + : isPlainObject(source.state_groups) + ? source.state_groups + : {}; + const activityText = normalizeText( + collectStringValues({ + source_input: source.source_input, + workflow: source.workflow, + activity_model: source.activity_model, + interaction_contract: source.interaction_contract, + }).join(" "), + ); + const active = new Set(["core"]); + + for (const groupId of ARTIFACT_INSPECTOR_STATE_GROUP_IDS.slice(1)) { + if ( + Array.isArray(declaredStateGroups[groupId]) && + declaredStateGroups[groupId].length > 0 + ) { + active.add(groupId); + } + } + + if ( + /\b(?:consequential|commit|approve|reject|publish|external effect|outcome pending|committing|commit succeeded|known failure|unknown result|receipt reconciliation|immutable receipt|concurrent result|superseding action)\b/.test( + activityText, + ) + ) { + active.add("consequential"); + } + + if ( + /\b(?:reusable guidance|later repeats?|future cases?|accepted version|accepting guidance|supersession|revocation)\b/.test( + activityText, + ) + ) { + active.add("reusable_guidance"); + } + + if ( + /\b(?:automation|automatic resolution|match preflight|exact match|near or partial match|inline causal receipt|exception returned to human review)\b/.test( + activityText, + ) + ) { + active.add("automation"); + } + + return ARTIFACT_INSPECTOR_STATE_GROUP_IDS.filter((groupId) => + active.has(groupId), + ); +} + +function deriveArtifactInspectorReviewedActiveStateGroups({ + sourceInput, +} = {}) { + return deriveArtifactInspectorActiveStateGroups({ + source_input: sourceInput, + workflow: { state_groups: {} }, + activity_model: {}, + interaction_contract: {}, + }); +} + +function artifactInspectorStateGroupsMatch(left, right) { + return ( + Array.isArray(left) && + Array.isArray(right) && + left.length === right.length && + left.every((groupId, index) => groupId === right[index]) + ); +} + +function artifactInspectorImplementationFields(source, contract) { + const identifiers = getArtifactInspectorIdentifiers(contract); + const requestedSurfaceType = normalizeOptionalSurfaceType( + source.surface_type ?? source.surfaceType, + ); + const suppliedScopes = + source.design_system_scopes ?? source.designSystemScopes; + const suppliedBoundaries = + source.boundary_contracts ?? source.boundaryContracts; + const suppliedArtifactInspector = + source.artifact_inspector ?? source.artifactInspector; + const hasAnyBundleField = + suppliedScopes !== undefined || + suppliedBoundaries !== undefined || + suppliedArtifactInspector !== undefined; + const model = getArtifactInspectorModel(contract); + + if (requestedSurfaceType === identifiers.surface_type && !model) { + throw new JudgmentKitInputError( + "The active contract does not support the requested Artifact Inspector profile.", + { + code: "artifact_inspector_profile_unsupported", + details: { + surface_type: identifiers.surface_type, + workflow_profile: identifiers.workflow_profile, + frontend_surface_profile: identifiers.frontend_surface_profile, + fallback_applied: false, + }, + }, + ); + } + + if (requestedSurfaceType) { + resolveSurfaceType(contract, requestedSurfaceType); + } + + if ( + requestedSurfaceType && + requestedSurfaceType !== identifiers.surface_type && + hasAnyBundleField + ) { + throw new JudgmentKitInputError( + "Artifact Inspector authority fields cannot be attached to a different surface type.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + selected_surface_type: requestedSurfaceType, + required_surface_type: identifiers.surface_type, + }, + }, + ); + } + + const activate = requestedSurfaceType === identifiers.surface_type; + if (!activate && !hasAnyBundleField) { + return {}; + } + + if (!model) { + throw new JudgmentKitInputError( + "The active contract does not support Artifact Inspector authority.", + { + code: "artifact_inspector_profile_unsupported", + details: { + surface_type: identifiers.surface_type, + frontend_surface_profile: identifiers.frontend_surface_profile, + }, + }, + ); + } + + const canonicalArtifactInspector = { + registry_id: optionalString(model.id) || identifiers.surface_type, + registry_version: optionalString(model.version) || "1.0.0", + surface_type: identifiers.surface_type, + workflow_profile: identifiers.workflow_profile, + frontend_surface_profile: identifiers.frontend_surface_profile, + topology_kind: identifiers.topology_kind, + active_state_groups: deriveArtifactInspectorActiveStateGroups(source), + state_groups: cloneWorkflowStructuredValue(model.state_groups ?? {}), + trusted_runtime_evidence_required: true, + external_artifact_review_status: "external_not_reviewed", + }; + const candidate = { + ...(activate + ? { + design_system_scopes: + suppliedScopes ?? + cloneWorkflowStructuredValue(model.design_system?.scopes ?? []), + boundary_contracts: + suppliedBoundaries ?? + cloneWorkflowStructuredValue( + model.design_system?.boundary_contracts ?? [], + ), + artifact_inspector: isPlainObject(suppliedArtifactInspector) + ? { + ...canonicalArtifactInspector, + ...cloneWorkflowStructuredValue(suppliedArtifactInspector), + state_groups: + suppliedArtifactInspector.state_groups ?? + canonicalArtifactInspector.state_groups, + } + : canonicalArtifactInspector, + } + : { + ...(suppliedScopes !== undefined + ? { design_system_scopes: suppliedScopes } + : {}), + ...(suppliedBoundaries !== undefined + ? { boundary_contracts: suppliedBoundaries } + : {}), + ...(suppliedArtifactInspector !== undefined + ? { artifact_inspector: suppliedArtifactInspector } + : {}), + }), + }; + + try { + const normalized = validateArtifactInspectorAuthorityContract(candidate); + return normalized.active + ? { + design_system_scopes: normalized.design_system_scopes, + boundary_contracts: normalized.boundary_contracts, + artifact_inspector: normalized.artifact_inspector, + } + : {}; + } catch (error) { + throw new JudgmentKitInputError( + error instanceof Error + ? error.message + : "Artifact Inspector authority contract is invalid.", + { + code: + optionalString(error?.code) || + "invalid_artifact_inspector_authority_contract", + details: isPlainObject(error?.details) ? error.details : {}, + }, + ); + } +} + function normalizeUiImplementationContract(input = {}, options = {}) { const contract = options.contract ?? loadActivityContract(options.contractPath); const base = getContractUiImplementationContract(contract); @@ -8350,6 +11510,64 @@ function normalizeUiImplementationContract(input = {}, options = {}) { visualCompositionPolicyAuthority, designSystemAdapter, } = resolveImplementationDesignSystem(source, base); + const artifactInspectorFields = artifactInspectorImplementationFields( + source, + contract, + ); + const artifactInspectorComponentRoleIds = new Set( + toStringArray( + getArtifactInspectorModel(contract)?.design_system?.component_roles, + ), + ); + const artifactInspectorPatternId = + optionalString( + contract.ui_workflow_profiles?.[ + getArtifactInspectorIdentifiers(contract).workflow_profile + ]?.pattern_id, + ) || "artifact-inspector"; + const artifactInspectorActive = Boolean( + artifactInspectorFields.artifact_inspector, + ); + const canonicalArtifactInspectorDesignSystem = artifactInspectorActive + ? canonicalJudgmentKitDesignSystemAuthority() + : null; + const effectiveDefaultDesignSystem = + canonicalArtifactInspectorDesignSystem?.defaultDesignSystem ?? + defaultDesignSystem; + const scopedDefaultDesignSystem = { + ...effectiveDefaultDesignSystem, + component_contracts: normalizeComponentContracts( + effectiveDefaultDesignSystem.component_contracts, + ).filter( + (entry) => + artifactInspectorActive || + !artifactInspectorComponentRoleIds.has(optionalString(entry.id)), + ), + pattern_contracts: normalizePatternContracts( + effectiveDefaultDesignSystem.pattern_contracts, + ).filter( + (entry) => + artifactInspectorActive || + optionalString(entry.id) !== artifactInspectorPatternId, + ), + }; + if ( + artifactInspectorFields.artifact_inspector && + designSystemSource.mode !== "judgmentkit_default" + ) { + throw new JudgmentKitInputError( + "Artifact Inspector requires JudgmentKit authority for its chrome and overlay scopes; external visual authority belongs only to the declared primary_artifact scope.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "design_system_source.mode", + expected: "judgmentkit_default", + observed: designSystemSource.mode, + external_artifact_scope: "primary_artifact", + }, + }, + ); + } return { id: optionalString(source.id) || optionalString(base.id) || "judgmentkit.ui-implementation-contract.portable", @@ -8385,12 +11603,15 @@ function normalizeUiImplementationContract(input = {}, options = {}) { : true, checks: browserQaChecks, }, - default_ai_native_design_system: defaultDesignSystem, + default_ai_native_design_system: scopedDefaultDesignSystem, iteration_policy: normalizeIterationPolicy( source.iteration_policy ?? source.iterationPolicy, base.iteration_policy, ), - design_system_source: designSystemSource, + design_system_source: + canonicalArtifactInspectorDesignSystem?.designSystemSource ?? + designSystemSource, + ...artifactInspectorFields, ...(designSystemAdapter ? { design_system_adapter: designSystemAdapter } : {}), @@ -8410,7 +11631,9 @@ function normalizeUiImplementationContract(input = {}, options = {}) { source.defaultAiNativeDesignSystem?.localComponentAuthority, base.local_component_authority, ), - visual_token_adapter: visualTokenAdapter, + visual_token_adapter: + canonicalArtifactInspectorDesignSystem?.visualTokenAdapter ?? + visualTokenAdapter, visual_asset_policy: normalizeVisualAssetPolicy( source.visual_asset_policy ?? source.visualAssetPolicy, base.visual_asset_policy, @@ -8484,6 +11707,13 @@ export function createUiImplementationContract(input = {}, options = {}) { mode: implementationContractSource(input ?? {}), repo_name: optionalString(input?.repo_name), target_stack: optionalString(input?.target_stack), + ...(normalizeOptionalSurfaceType(input?.surface_type ?? input?.surfaceType) + ? { + surface_type: normalizeOptionalSurfaceType( + input?.surface_type ?? input?.surfaceType, + ), + } + : {}), external_authority: optionalString( input?.external_authority ?? input?.external_system_name, ), @@ -8529,6 +11759,22 @@ export function createUiImplementationContract(input = {}, options = {}) { : []), ], }, + ...(normalized.artifact_inspector + ? [ + { + id: "artifact_inspector_authority_gate", + status: "review_required", + requirement: + "This interaction-model release has no accepting interactive-attestation producer; implementation review remains review_required.", + checks: [ + "JudgmentKit chrome scope", + "JudgmentKit inspection overlay scope", + "external artifact preservation", + "declared cross-boundary interaction", + ], + }, + ] + : []), ], }; @@ -8630,7 +11876,167 @@ function candidateImplementationSourceText(value) { return values; } - return unique(collectSourceEntries(value)).join("\n"); + return unique(collectSourceEntries(value)).join("\n"); +} + +const ARTIFACT_INSPECTOR_EXTERNAL_SOURCE_KEYS = new Set([ + "artifact", + "artifactMarkup", + "artifactSource", + "artifact_markup", + "artifact_source", + "externalArtifact", + "external_artifact", + "primaryArtifact", + "primary_artifact", +]); + +const HTML_VOID_ELEMENT_NAMES = new Set([ + "area", + "base", + "br", + "col", + "embed", + "hr", + "img", + "input", + "link", + "meta", + "param", + "source", + "track", + "wbr", +]); + +function omitDeclaredExternalArtifactSources(value, depth = 0) { + if (!value || depth > 5) { + return value; + } + if (Array.isArray(value)) { + return value.map((entry) => + omitDeclaredExternalArtifactSources(entry, depth + 1), + ); + } + if (!isPlainObject(value)) { + return value; + } + return Object.fromEntries( + Object.entries(value) + .filter(([key]) => !ARTIFACT_INSPECTOR_EXTERNAL_SOURCE_KEYS.has(key)) + .map(([key, entry]) => [ + key, + omitDeclaredExternalArtifactSources(entry, depth + 1), + ]), + ); +} + +function matchingElementEnd(source, tagName, openingEnd) { + const tagPattern = /<\s*(\/?)\s*([A-Za-z][\w:.-]*)\b[^>]*?>/g; + const normalizedTagName = tagName.toLowerCase(); + let depth = 1; + tagPattern.lastIndex = openingEnd; + let match; + while ((match = tagPattern.exec(source)) !== null) { + if (match[2].toLowerCase() !== normalizedTagName) { + continue; + } + const closing = match[1] === "/"; + const selfClosing = /\/\s*>$/.test(match[0]); + if (closing) { + depth -= 1; + if (depth === 0) { + return tagPattern.lastIndex; + } + } else if (!selfClosing) { + depth += 1; + } + } + return null; +} + +function stripBoundedPrimaryArtifactMarkup(value) { + const source = optionalString(value); + if (!source || !/\bdata-artifact-root\b/i.test(source)) { + return source; + } + const tagPattern = /<\s*(\/?)\s*([A-Za-z][\w:.-]*)\b[^>]*?>/g; + const kept = []; + let cursor = 0; + let match; + while ((match = tagPattern.exec(source)) !== null) { + if ( + match[1] === "/" || + !/\bdata-artifact-root\b/i.test(match[0]) + ) { + continue; + } + const tagName = match[2]; + const selfClosing = + /\/\s*>$/.test(match[0]) || + HTML_VOID_ELEMENT_NAMES.has(tagName.toLowerCase()); + const elementEnd = selfClosing + ? tagPattern.lastIndex + : matchingElementEnd(source, tagName, tagPattern.lastIndex); + if (elementEnd === null) { + continue; + } + kept.push(source.slice(cursor, match.index)); + cursor = elementEnd; + tagPattern.lastIndex = elementEnd; + } + kept.push(source.slice(cursor)); + return kept.join("\n"); +} + +function stripPrimaryArtifactScopedCss(value) { + const source = optionalString(value); + if (!source || !/\bdata-artifact-root\b/i.test(source)) { + return source; + } + return source.replace( + /(]*>)([\s\S]*?)(<\/style\s*>)/gi, + (_styleBlock, opening, cssText, closing) => { + const filteredCss = cssText.replace( + /([^{}]+)\{([^{}]*)\}/g, + (rule, selectorText) => { + const selectors = selectorText + .split(",") + .map((selector) => selector.trim()) + .filter(Boolean); + return selectors.length > 0 && + selectors.every((selector) => { + const artifactRootMatch = + /\[data-artifact-root(?:\s|\]|=)/i.exec(selector); + if (!artifactRootMatch) { + return false; + } + const prefix = selector.slice(0, artifactRootMatch.index); + const rootAppearsInsideFunctionalPseudo = + prefix.lastIndexOf("(") > prefix.lastIndexOf(")"); + return ( + !rootAppearsInsideFunctionalPseudo && + !/[+~]/.test(selector) && + !/:(?:has|is|not|where)\s*\(/i.test(selector) + ); + }) + ? "" + : rule; + }, + ); + return `${opening}${filteredCss}${closing}`; + }, + ); +} + +function artifactInspectorOwnedImplementationText(candidate) { + const candidateWithoutExternalSources = omitDeclaredExternalArtifactSources( + candidate, + ); + return stripPrimaryArtifactScopedCss( + stripBoundedPrimaryArtifactMarkup( + candidateImplementationSourceText(candidateWithoutExternalSources), + ), + ); } function normalizeCandidateList(candidate, keys) { @@ -12592,6 +15998,11 @@ function reviewEvidenceFieldMapping( "token family, font role, icon role, and catalog icon-id boundary proof -> visual_token_evidence", "visual-token, typography, icon asset, renderer component, import, package, and source-export proof -> design_system_provenance", "repo-local component selector and computed-style proof -> local_component_authority_evidence", + ...(sourceContract.artifact_inspector + ? [ + "deferred owned-scope, artifact-preservation, and boundary attestation requirement -> checks.artifact_inspector (no accepting producer or candidate-authored field in this release)", + ] + : []), ], primitives_used: { field: "primitives_used", @@ -12708,6 +16119,20 @@ function reviewEvidenceFieldMapping( not_for: "Do not use local_component_authority_evidence as component contract evidence, approved primitive evidence, accessibility evidence, static evidence, or browser QA evidence.", }, + ...(sourceContract.artifact_inspector + ? { + artifact_inspector_authority_evidence: { + field: null, + reviewed_by: "checks.artifact_inspector", + source_path: + "implementation_contract.design_system_scopes + implementation_contract.boundary_contracts + implementation_contract.artifact_inspector", + accepts: + "No accepting evidence source is available in this release; the separately deferred interactive attestation must eventually separate inspector_chrome, inspection_overlay, primary_artifact preservation, and boundary results.", + candidate_authored_evidence_accepted: false, + external_artifact_review_status: "external_not_reviewed", + }, + } + : {}), ...(sourceContract.visual_composition_policy ? { visual_composition_evidence: { @@ -12812,7 +16237,10 @@ function candidateVisualCompositionEvidence(candidate) { ); } -function candidateTextWithoutVisualCompositionEvidence(candidate) { +function candidateTextWithoutVisualCompositionEvidence( + candidate, + implementationContract, +) { if (!isPlainObject(candidate)) return candidateText(candidate); const { visual_composition_manifest: _manifest, @@ -12830,10 +16258,15 @@ function candidateTextWithoutVisualCompositionEvidence(candidate) { delete browserQa.visual_composition_manifest; delete browserQa.visualCompositionManifest; } - return candidateText({ + const candidateWithoutVisualCompositionEvidence = { ...rest, ...(browserQa ? { browser_qa: browserQa } : {}), - }); + }; + return implementationContract?.artifact_inspector + ? artifactInspectorOwnedImplementationText( + candidateWithoutVisualCompositionEvidence, + ) + : candidateText(candidateWithoutVisualCompositionEvidence); } function visualCompositionManifestSamples(manifest) { @@ -13943,7 +17376,10 @@ function buildImplementationCandidateChecks( implementationContract, { selectedSurfaceType } = {}, ) { - const text = candidateTextWithoutVisualCompositionEvidence(candidate); + const text = candidateTextWithoutVisualCompositionEvidence( + candidate, + implementationContract, + ); const rawControls = detectRawControls(text); const primitivesUsed = normalizeCandidateList(candidate, [ "primitives_used", @@ -13964,7 +17400,23 @@ function buildImplementationCandidateChecks( "states_verified", "state_coverage", ]); - const requiredStates = implementationContract.state_coverage.required_states; + const artifactInspectorStateConfig = isPlainObject( + implementationContract.artifact_inspector, + ) + ? implementationContract.artifact_inspector + : null; + const activeArtifactInspectorStateGroups = artifactInspectorStateConfig + ? toStringArray(artifactInspectorStateConfig.active_state_groups) + : []; + const artifactInspectorRequiredStates = artifactInspectorStateConfig + ? activeArtifactInspectorStateGroups.flatMap((groupId) => + toStringArray(artifactInspectorStateConfig.state_groups?.[groupId]), + ) + : []; + const requiredStates = unique([ + ...implementationContract.state_coverage.required_states, + ...artifactInspectorRequiredStates, + ]); const missingStates = requiredStates.filter((state) => !statesCovered.includes(state)); const staticChecks = normalizeCandidateList(candidate, [ "static_checks", @@ -14243,12 +17695,20 @@ function findingContractArea(check) { return "visual_composition"; } + if (String(check).startsWith("artifact_inspector")) { + return "artifact_inspector_authority"; + } + return "evidence_gates"; } function repairInstructionForFinding(finding, implementationContract) { const check = optionalString(finding.check); + if (optionalString(finding.repair_instruction)) { + return optionalString(finding.repair_instruction); + } + if (check === "raw_controls") { return "Replace raw form controls with approved primitives or repo-local helpers before resubmitting."; } @@ -14381,7 +17841,11 @@ function buildRepairInstructions(findings, implementationContract) { }; } -function buildAutofixLoop(failed, iterationContext, iterationPolicy) { +function buildAutofixLoop( + { failed, reviewRequired }, + iterationContext, + iterationPolicy, +) { const currentAttempt = iterationContext.current_attempt; const maxAttempts = iterationContext.max_attempts; const remainingAttempts = Math.max(0, maxAttempts - currentAttempt); @@ -14389,10 +17853,14 @@ function buildAutofixLoop(failed, iterationContext, iterationPolicy) { return { owner: iterationPolicy.owner, - status: failed ? (stopForHuman ? "stopped" : "repairable") : "passed", + status: reviewRequired + ? "not_applicable" + : failed + ? (stopForHuman ? "stopped" : "repairable") + : "passed", current_attempt: currentAttempt, max_attempts: maxAttempts, - remaining_attempts: failed ? remainingAttempts : maxAttempts - currentAttempt, + remaining_attempts: remainingAttempts, loop: iterationPolicy.loop, judgmentkit_role: iterationPolicy.judgmentkit_role, }; @@ -14426,37 +17894,94 @@ export function reviewUiImplementationCandidate(candidate, options = {}) { throwIncompleteDesignSystemAuthority(); } const selectedSurfaceType = - selectedSurfaceTypeFromImplementationReviewOptions(options); + selectedSurfaceTypeFromImplementationReviewOptions( + options, + contract, + candidate, + ); const checks = buildImplementationCandidateChecks( candidate, implementationContract, { selectedSurfaceType }, ); - const designSystemFailed = designSystemGateFailed(checks); - const failed = checks.findings.some((finding) => finding.severity === "fail"); + const artifactInspectorReview = reviewArtifactInspectorAuthorityEvidence( + implementationContract, + ); + if ( + selectedSurfaceType === getArtifactInspectorIdentifiers(contract).surface_type && + !artifactInspectorReview.applicable + ) { + throw new JudgmentKitInputError( + "Artifact Inspector implementation review requires the scoped authority contract returned by create_ui_implementation_contract.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + selected_surface_type: selectedSurfaceType, + required_fields: [ + "design_system_scopes", + "boundary_contracts", + "artifact_inspector", + ], + }, + }, + ); + } + const artifactInspectorApplicable = artifactInspectorReview.applicable; + const artifactInspectorFailed = artifactInspectorReview.status === "fail"; + const artifactInspectorReviewRequired = + artifactInspectorReview.status === "review_required"; + const combinedFindings = artifactInspectorApplicable + ? [...checks.findings, ...artifactInspectorReview.findings] + : checks.findings; + const designSystemFailed = + designSystemGateFailed(checks) || artifactInspectorFailed; + const failed = + checks.findings.some((finding) => finding.severity === "fail") || + artifactInspectorFailed; + const reviewRequired = !failed && artifactInspectorReviewRequired; const iterationPolicy = implementationContract.iteration_policy; const iterationContext = normalizeIterationContext( options.iteration_context ?? options.iterationContext, iterationPolicy, ); - const autofixLoop = buildAutofixLoop(failed, iterationContext, iterationPolicy); - const nextAgentAction = failed + const autofixLoop = buildAutofixLoop( + { failed, reviewRequired }, + iterationContext, + iterationPolicy, + ); + const nextAgentAction = reviewRequired + ? "none" + : failed ? autofixLoop.status === "stopped" ? "stop_for_human" : "repair_and_resubmit" : "accept"; + const implementationReviewStatus = failed + ? "failed" + : reviewRequired + ? "review_required" + : "passed"; + const designSystemAcceptanceStatus = designSystemFailed + ? "failed" + : reviewRequired + ? "review_required" + : "passed"; const packet = { version: contract.version, contract_id: contract.id, workflow_id: getContractWorkflowId(contract), - implementation_review_status: failed ? "failed" : "passed", - candidate_artifact_status: failed ? "not_an_artifact" : "accepted_artifact", - design_system_acceptance_status: designSystemFailed ? "failed" : "passed", + implementation_review_status: implementationReviewStatus, + candidate_artifact_status: failed + ? "not_an_artifact" + : reviewRequired + ? "review_required" + : "accepted_artifact", + design_system_acceptance_status: designSystemAcceptanceStatus, implementation_contract_id: implementationContract.id, next_agent_action: nextAgentAction, autofix_loop: autofixLoop, repair_instructions: buildRepairInstructions( - failed ? checks.findings : [], + failed ? combinedFindings : [], implementationContract, ), generation_gates: [ @@ -14468,16 +17993,26 @@ export function reviewUiImplementationCandidate(candidate, options = {}) { }, { id: "implementation_gate", - status: failed ? "failed" : "passed", + status: failed ? "failed" : reviewRequired ? "review_required" : "passed", requirement: "Generated UI must use approved primitives, respect local component authority, and provide static, browser QA, and applicable rendered visual composition evidence.", }, { id: "design_system_gate", - status: designSystemFailed ? "failed" : "passed", + status: designSystemAcceptanceStatus, requirement: "Generated UI must prove active design-system provenance for visual tokens, typography, icon assets, renderer components, component contracts, and pattern contracts before it can count as an artifact.", }, + ...(artifactInspectorApplicable + ? [ + { + id: "artifact_inspector_authority_gate", + status: artifactInspectorReview.status, + requirement: + "Acceptance requires the separately deferred trusted interactive attestation for JudgmentKit chrome, inspection overlay, external artifact preservation, and boundary behavior; this release remains review_required.", + }, + ] + : []), ], checks: { raw_controls: checks.raw_controls, @@ -14495,8 +18030,11 @@ export function reviewUiImplementationCandidate(candidate, options = {}) { component_contracts: checks.component_contracts, pattern_contracts: checks.pattern_contracts, visual_composition: checks.visual_composition, + ...(artifactInspectorApplicable + ? { artifact_inspector: artifactInspectorReview } + : {}), }, - findings: checks.findings, + findings: combinedFindings, implementation_contract: implementationContract, }; @@ -14525,9 +18063,9 @@ function withoutCallerVisualCompositionEvidence(candidate) { } /** - * Independently render and measure a candidate before reviewing it. The - * private browser attestation exists only for this call; neither an attacher - * nor the attested candidate is exposed to callers. + * Independently render and measure generic visual-composition relationships + * before reviewing a candidate. This static browser path does not produce or + * satisfy Artifact Inspector interactive-attestation evidence. */ export async function reviewUiImplementationCandidateWithBrowserRuntime( candidate, @@ -14634,6 +18172,15 @@ function compactImplementationContractForHandoff(implementationContract) { implementationContract.default_ai_native_design_system, iteration_policy: implementationContract.iteration_policy, design_system_source: implementationContract.design_system_source, + ...(implementationContract.design_system_scopes + ? { design_system_scopes: implementationContract.design_system_scopes } + : {}), + ...(implementationContract.boundary_contracts + ? { boundary_contracts: implementationContract.boundary_contracts } + : {}), + ...(implementationContract.artifact_inspector + ? { artifact_inspector: implementationContract.artifact_inspector } + : {}), ...(implementationContract.design_system_adapter ? { design_system_adapter: implementationContract.design_system_adapter } : {}), @@ -14699,23 +18246,180 @@ 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 reviewedArtifactInspectorStateGroups = + assertUiWorkflowReviewStillReady(workflowReview, contract); + const identifiers = getArtifactInspectorIdentifiers(contract); + const workflowSelectsArtifactInspector = isArtifactTopologyCandidate( + workflowCandidate, + contract, + ); + const declaredSurfaceType = normalizeOptionalSurfaceType( + workflowReview.surface_type, + ); + const guidanceSurfaceType = normalizeOptionalSurfaceType( + workflowReview.surface_guidance?.recommended_surface_type, + ); + if ( + declaredSurfaceType && + guidanceSurfaceType && + declaredSurfaceType !== guidanceSurfaceType + ) { + throw new JudgmentKitInputError( + "UI generation handoff received conflicting reviewed surface fields.", + { + code: "handoff_blocked", + details: { + surface_type: declaredSurfaceType, + surface_guidance_type: guidanceSurfaceType, + }, + }, + ); + } + const reviewedSurfaceType = declaredSurfaceType ?? guidanceSurfaceType; + if ( + workflowSelectsArtifactInspector && + reviewedSurfaceType && + reviewedSurfaceType !== identifiers.surface_type + ) { + throw new JudgmentKitInputError( + "UI generation handoff cannot route an artifact-centered workflow to a conflicting surface.", + { + code: "handoff_blocked", + details: { + expected_surface_type: identifiers.surface_type, + observed_surface_type: reviewedSurfaceType, + workflow_topology: identifiers.topology_kind, + }, + }, + ); + } + const handoffSurfaceType = workflowSelectsArtifactInspector + ? identifiers.surface_type + : reviewedSurfaceType; + const duplicateWorkUnitIds = duplicateWorkflowWorkUnitIds( + workflowCandidate.workflow?.work_units, + ); + if ( + handoffSurfaceType === identifiers.surface_type && + duplicateWorkUnitIds.length > 0 + ) { + throw new JudgmentKitInputError( + "Artifact Inspector handoff requires unique work-unit identifiers.", + { + code: "handoff_blocked", + details: { + field: "workflow.work_units", + duplicate_work_unit_ids: duplicateWorkUnitIds, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + }, + }, + ); + } + const implementationContractInput = options.implementation_contract ?? - options.ui_implementation_contract ?? - contract.implementation_contract, + options.ui_implementation_contract ?? + contract.implementation_contract; + if ( + workflowSelectsArtifactInspector && + !isPlainObject(implementationContractInput) + ) { + throw new JudgmentKitInputError( + "Artifact Inspector handoff requires an object implementation contract so scoped authority cannot be omitted.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "implementation_contract", + observed_type: Array.isArray(implementationContractInput) + ? "array" + : typeof implementationContractInput, + }, + }, + ); + } + const handoffActiveStateGroups = ARTIFACT_INSPECTOR_STATE_GROUP_IDS.filter( + (groupId) => reviewedArtifactInspectorStateGroups.includes(groupId), + ); + const implementationContract = normalizeUiImplementationContract( + handoffSurfaceType === identifiers.surface_type + ? { + ...implementationContractInput, + surface_type: handoffSurfaceType, + artifact_inspector: { + ...(isPlainObject(implementationContractInput.artifact_inspector) + ? implementationContractInput.artifact_inspector + : {}), + active_state_groups: handoffActiveStateGroups, + }, + } + : implementationContractInput, { contract }, ); + assertArtifactInspectorBoundaryConsistency({ + workflow: workflowCandidate.workflow, + surfaceTypes: [handoffSurfaceType], + profileIds: [workflowReview.guidance_profile?.profile_id], + implementationContract, + activityModel: activityCandidate.activity_model, + interactionContract: activityCandidate.interaction_contract, + reviewedActiveStateGroups: handoffActiveStateGroups, + contract, + code: "handoff_blocked", + message: + "UI generation handoff cannot accept conflicting Artifact Inspector surface, topology, profile, or authority signals.", + }); + if ( + workflowSelectsArtifactInspector && + !artifactInspectorIntegritySealMatches( + "workflow_review", + artifactInspectorWorkflowReviewIntegrityPayload( + workflowReview, + contract, + ), + workflowReview.source?.artifact_inspector_review_integrity, + ) + ) { + throw new JudgmentKitInputError( + "UI generation handoff requires an intact workflow review from the current trusted review process.", + { + code: "handoff_blocked", + details: { + reason: "review_packet_no_longer_ready", + failures: [ + { + field: "source.artifact_inspector_review_integrity", + observed: "invalid_or_stale", + }, + ], + }, + }, + ); + } const workflowSurfaceSet = toSurfaceSetArray(workflowCandidate.surface_set); - const handoffSurfaceGuidance = summarizeSurfaceReview( + let handoffSurfaceGuidance = summarizeSurfaceReview( workflowReview.surface_guidance, { includeFrontendPosture: true }, ); - if (handoffSurfaceGuidance?.recommended_surface_type) { - handoffSurfaceGuidance.frontend_posture = - buildSurfaceImplications( - handoffSurfaceGuidance.recommended_surface_type, - ).frontend_posture; + if (workflowSelectsArtifactInspector) { + const canonicalSurfaceImplications = buildSurfaceImplications( + identifiers.surface_type, + ); + handoffSurfaceGuidance = { + ...(handoffSurfaceGuidance ?? {}), + recommended_surface_type: identifiers.surface_type, + blocked_surface_types: toStringArray( + handoffSurfaceGuidance?.blocked_surface_types, + ), + confidence: + optionalString(handoffSurfaceGuidance?.confidence) || + optionalString(workflowReview.review?.confidence), + ...canonicalSurfaceImplications, + }; + } else if (handoffSurfaceGuidance?.recommended_surface_type) { + handoffSurfaceGuidance.frontend_posture = buildSurfaceImplications( + handoffSurfaceGuidance.recommended_surface_type, + ).frontend_posture; } const handoff = { version: workflowReview.version, @@ -14725,11 +18429,19 @@ export function createUiGenerationHandoff(workflowReview, options = {}) { mode: workflowReview.source?.mode, proposer: workflowReview.source?.proposer, input_excerpt: workflowReview.source?.input_excerpt, + ...(workflowSelectsArtifactInspector + ? { + reviewed_activity_input: optionalRawString( + workflowReview.source?.reviewed_activity_input, + ), + reviewed_active_state_groups: handoffActiveStateGroups, + } + : {}), }, ...(workflowReview.guidance_profile ? { guidance_profile: workflowReview.guidance_profile } : {}), - ...(workflowReview.surface_type ? { surface_type: workflowReview.surface_type } : {}), + ...(handoffSurfaceType ? { surface_type: handoffSurfaceType } : {}), ...(handoffSurfaceGuidance ? { surface_guidance: handoffSurfaceGuidance } : {}), @@ -14753,7 +18465,42 @@ export function createUiGenerationHandoff(workflowReview, options = {}) { workflow: { surface_name: optionalString(workflowCandidate.workflow.surface_name), topology: optionalString(workflowCandidate.workflow.topology), - work_units: toStringArray(workflowCandidate.workflow.work_units), + ...(isPlainObject(workflowCandidate.workflow.topology_contract) + ? { + topology_contract: cloneWorkflowStructuredValue( + workflowCandidate.workflow.topology_contract, + ), + } + : {}), + work_units: cloneWorkflowStructuredValue( + toWorkflowWorkUnitArray(workflowCandidate.workflow.work_units), + ), + ...((isPlainObject(workflowCandidate.workflow.artifact) || + isPlainObject(workflowCandidate.artifact)) + ? { + artifact: cloneWorkflowStructuredValue( + workflowCandidate.workflow.artifact ?? workflowCandidate.artifact, + ), + } + : {}), + ...((isPlainObject(workflowCandidate.workflow.target_model) || + isPlainObject(workflowCandidate.target_model)) + ? { + target_model: cloneWorkflowStructuredValue( + workflowCandidate.workflow.target_model ?? + workflowCandidate.target_model, + ), + } + : {}), + ...((isPlainObject(workflowCandidate.workflow.state_groups) || + isPlainObject(workflowCandidate.state_groups)) + ? { + state_groups: cloneWorkflowStructuredValue( + workflowCandidate.workflow.state_groups ?? + workflowCandidate.state_groups, + ), + } + : {}), stepper_eligibility: workflowCandidate.workflow.stepper_eligibility ?? workflowReview.guardrails?.stepper_eligibility, primary_actions: toStringArray(workflowCandidate.workflow.primary_actions), @@ -14827,6 +18574,39 @@ export function createUiGenerationHandoff(workflowReview, options = {}) { ], implementation_contract: compactImplementationContractForHandoff(implementationContract), + ...(implementationContract.artifact_inspector + ? { + artifact_inspector: { + registry: cloneWorkflowStructuredValue( + implementationContract.artifact_inspector, + ), + artifact: cloneWorkflowStructuredValue( + workflowCandidate.workflow.artifact ?? + workflowCandidate.artifact ?? + {}, + ), + target_model: cloneWorkflowStructuredValue( + workflowCandidate.workflow.target_model ?? + workflowCandidate.target_model ?? + {}, + ), + state_groups: cloneWorkflowStructuredValue( + workflowCandidate.workflow.state_groups ?? + workflowCandidate.state_groups ?? + {}, + ), + design_system_scopes: cloneWorkflowStructuredValue( + implementationContract.design_system_scopes, + ), + boundary_contracts: cloneWorkflowStructuredValue( + implementationContract.boundary_contracts, + ), + responsive_posture: + handoffSurfaceGuidance?.frontend_posture?.responsive_expectations ?? + null, + }, + } + : {}), ...(isPlainObject(cognitiveDimensionsReview) ? { cognitive_dimensions_review: { @@ -14840,12 +18620,33 @@ export function createUiGenerationHandoff(workflowReview, options = {}) { : {}), }; + if (workflowSelectsArtifactInspector) { + handoff.source.artifact_inspector_boundary_integrity = + createArtifactInspectorIntegritySeal( + "ui_generation_handoff", + artifactInspectorBoundaryIntegrityPayload(handoff), + ); + } + assertNoStyleFields(handoff); return handoff; } function textFromHandoff(handoff) { + const workflowWorkUnitText = toWorkflowWorkUnitArray( + handoff.workflow?.work_units, + ).flatMap((workUnit) => + typeof workUnit === "string" + ? [workUnit] + : [ + workUnit.id, + workUnit.label, + workUnit.participant_intent, + workUnit.system_responsibility, + ], + ); + return [ handoff.activity_model?.activity, handoff.activity_model?.objective, @@ -14857,7 +18658,7 @@ function textFromHandoff(handoff) { handoff.interaction_contract?.completion, handoff.workflow?.surface_name, handoff.workflow?.topology, - ...(toStringArray(handoff.workflow?.work_units)), + ...workflowWorkUnitText, ...(toStringArray(handoff.workflow?.primary_actions)), ...(toStringArray(handoff.workflow?.decision_points)), handoff.workflow?.completion_state, @@ -14974,9 +18775,21 @@ function hasCompleteExternalImplementationAuthority({ ) .map((contract) => normalizeText(contract.id)) .filter(Boolean); + const governedSurfaceComponentIds = listSurfacePresentationProfiles() + .flatMap((profile) => + Array.isArray(profile.component_roles) ? profile.component_roles : [], + ) + .map((component) => normalizeText(component?.id)) + .filter(Boolean); + const canonicalJudgmentKitComponentIds = unique([ + ...defaultComponentIds, + ...governedSurfaceComponentIds, + ]); const usesOnlyDefaultComponentContracts = - externalComponentIds.length === defaultComponentIds.length && - externalComponentIds.every((id) => defaultComponentIds.includes(id)); + externalComponentIds.length > 0 && + externalComponentIds.every((id) => + canonicalJudgmentKitComponentIds.includes(id), + ); const rendererComponentIds = toStringArray( designSystemSource.renderer_components, ) @@ -15382,6 +19195,7 @@ export function createFrontendGenerationContext({ surface_review: surfaceReview, surface_type: surfaceType, surface_profile: surfaceProfile, + supported_surface_profiles: supportedSurfaceProfiles, frontend_context: frontendContext, verification, contract, @@ -15407,6 +19221,14 @@ export function createFrontendGenerationContext({ } const resolvedContract = contract ?? loadActivityContract(contractPath); + const artifactIdentifiers = getArtifactInspectorIdentifiers(resolvedContract); + const handoffArtifactTopologySelected = isArtifactTopologyCandidate( + uiGenerationHandoff, + resolvedContract, + ); + const topologySurfaceType = handoffArtifactTopologySelected + ? artifactIdentifiers.surface_type + : null; const providedSurfaceType = normalizeOptionalSurfaceType(surfaceType); const handoffSurfaceType = normalizeOptionalSurfaceType( uiGenerationHandoff.surface_type, @@ -15422,7 +19244,11 @@ export function createFrontendGenerationContext({ ? normalizeOptionalSurfaceType(surfaceReview.recommended_surface_type) : null; const selectedSurfaceType = - providedSurfaceType ?? handoffSurfaceType ?? reviewedSurfaceType; + providedSurfaceType ?? + handoffSurfaceType ?? + handoffGuidanceSurfaceType ?? + reviewedSurfaceType ?? + topologySurfaceType; const surfaceTypeCandidates = [ ["surface_type", providedSurfaceType], ["ui_generation_handoff.surface_type", handoffSurfaceType], @@ -15431,6 +19257,7 @@ export function createFrontendGenerationContext({ handoffGuidanceSurfaceType, ], ["surface_review.recommended_surface_type", reviewedSurfaceType], + ["ui_generation_handoff.workflow.topology", topologySurfaceType], ].filter(([, value]) => value); const conflictingSurfaceTypes = surfaceTypeCandidates.filter( ([, value]) => value !== selectedSurfaceType, @@ -15438,63 +19265,219 @@ export function createFrontendGenerationContext({ if (conflictingSurfaceTypes.length > 0) { throw new JudgmentKitInputError( - "Frontend generation context received conflicting surface type selections.", + "Frontend generation context received conflicting surface type selections.", + { + details: { + selected_surface_type: selectedSurfaceType, + surface_type_candidates: Object.fromEntries(surfaceTypeCandidates), + }, + }, + ); + } + + if ( + selectedSurfaceType === artifactIdentifiers.surface_type && + !handoffArtifactTopologySelected + ) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend context requires artifact-centered workflow topology.", + { + code: "frontend_context_blocked", + details: { + surface_type: selectedSurfaceType, + expected_topology: artifactIdentifiers.topology_kind, + observed_topology: + optionalString(uiGenerationHandoff.workflow?.topology) || null, + }, + }, + ); + } + + const inferredSurfaceReview = isPlainObject(surfaceReview) + ? surfaceReview + : handoffSurfaceGuidance + ? handoffSurfaceGuidance + : selectedSurfaceType + ? { + recommended_surface_type: resolveSurfaceType( + resolvedContract, + selectedSurfaceType, + ).surface_type, + confidence: "provided", + blocked_surface_types: [], + ...buildSurfaceImplications(selectedSurfaceType), + } + : recommendSurfaceTypes(textFromHandoff(uiGenerationHandoff), { + contract: resolvedContract, + activity_review: { + review_status: "ready_for_review", + candidate: { + activity_model: uiGenerationHandoff.activity_model, + interaction_contract: uiGenerationHandoff.interaction_contract, + disclosure_policy: { + terms_to_use: uiGenerationHandoff.product_terms ?? [], + }, + }, + }, + }); + let surfaceGuidance = summarizeSurfaceReview(inferredSurfaceReview, { + includeFrontendPosture: true, + }); + const artifactInspectorSelected = + handoffArtifactTopologySelected || + surfaceGuidance.recommended_surface_type === artifactIdentifiers.surface_type; + if (artifactInspectorSelected) { + surfaceGuidance = { + ...(surfaceGuidance ?? {}), + recommended_surface_type: artifactIdentifiers.surface_type, + ...buildSurfaceImplications(artifactIdentifiers.surface_type), + }; + } + const serializedImplementationContract = isPlainObject( + uiGenerationHandoff.implementation_contract, + ) + ? uiGenerationHandoff.implementation_contract + : {}; + const serializedDesignSystemMode = optionalString( + serializedImplementationContract.design_system_source?.mode, + ); + if ( + artifactInspectorSelected && + serializedDesignSystemMode && + serializedDesignSystemMode !== "judgmentkit_default" + ) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend context requires JudgmentKit authority for inspector chrome and the inspection overlay.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "design_system_source.mode", + expected: "judgmentkit_default", + observed: serializedDesignSystemMode, + external_artifact_scope: "primary_artifact", + }, + }, + ); + } + let effectiveImplementationContract = serializedImplementationContract; + if (artifactInspectorSelected) { + const canonicalDesignSystem = + canonicalJudgmentKitDesignSystemAuthority(); + const serializedWithoutDesignSystemAuthority = { + ...serializedImplementationContract, + }; + delete serializedWithoutDesignSystemAuthority.design_system_adapter; + delete serializedWithoutDesignSystemAuthority.designSystemAdapter; + delete serializedWithoutDesignSystemAuthority.default_ai_native_design_system; + delete serializedWithoutDesignSystemAuthority.defaultAiNativeDesignSystem; + delete serializedWithoutDesignSystemAuthority.visual_token_adapter; + delete serializedWithoutDesignSystemAuthority.visualTokenAdapter; + delete serializedWithoutDesignSystemAuthority.design_system_source; + delete serializedWithoutDesignSystemAuthority.designSystemSource; + effectiveImplementationContract = { + ...serializedWithoutDesignSystemAuthority, + default_ai_native_design_system: + canonicalDesignSystem.defaultDesignSystem, + visual_token_adapter: canonicalDesignSystem.visualTokenAdapter, + design_system_source: canonicalDesignSystem.designSystemSource, + }; + } + const reviewedActivityInput = optionalRawString( + uiGenerationHandoff.source?.reviewed_activity_input, + ); + const reviewedActiveStateGroups = artifactInspectorSelected + ? deriveArtifactInspectorReviewedActiveStateGroups({ + sourceInput: reviewedActivityInput, + }) + : undefined; + const serializedReviewedActiveStateGroups = toStringArray( + uiGenerationHandoff.source?.reviewed_active_state_groups, + ); + if (artifactInspectorSelected && !reviewedActivityInput) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend context requires the reviewed activity input used to justify conditional state groups.", + { + code: "frontend_context_blocked", + details: { + field: "source.reviewed_activity_input", + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }, + }, + ); + } + if ( + artifactInspectorSelected && + !artifactInspectorStateGroupsMatch( + serializedReviewedActiveStateGroups, + reviewedActiveStateGroups, + ) + ) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend context requires the serialized reviewed-state ceiling to match the grounded activity.", { + code: "frontend_context_blocked", details: { - selected_surface_type: selectedSurfaceType, - surface_type_candidates: Object.fromEntries(surfaceTypeCandidates), + field: "source.reviewed_active_state_groups", + expected: reviewedActiveStateGroups, + observed: serializedReviewedActiveStateGroups, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", }, }, ); } - - const inferredSurfaceReview = isPlainObject(surfaceReview) - ? surfaceReview - : handoffSurfaceGuidance - ? handoffSurfaceGuidance - : selectedSurfaceType - ? { - recommended_surface_type: resolveSurfaceType( - resolvedContract, - selectedSurfaceType, - ).surface_type, - confidence: "provided", - blocked_surface_types: [], - ...buildSurfaceImplications(selectedSurfaceType), - } - : recommendSurfaceTypes(textFromHandoff(uiGenerationHandoff), { - contract: resolvedContract, - activity_review: { - review_status: "ready_for_review", - candidate: { - activity_model: uiGenerationHandoff.activity_model, - interaction_contract: uiGenerationHandoff.interaction_contract, - disclosure_policy: { - terms_to_use: uiGenerationHandoff.product_terms ?? [], - }, - }, - }, - }); - const surfaceGuidance = summarizeSurfaceReview(inferredSurfaceReview, { - includeFrontendPosture: true, + assertArtifactInspectorBoundaryConsistency({ + workflow: uiGenerationHandoff.workflow, + surfaceTypes: [surfaceGuidance.recommended_surface_type], + profileIds: [uiGenerationHandoff.guidance_profile?.profile_id], + implementationContract: effectiveImplementationContract, + additionalAuthoritySignals: [uiGenerationHandoff.artifact_inspector], + activityModel: uiGenerationHandoff.activity_model, + interactionContract: uiGenerationHandoff.interaction_contract, + reviewedActiveStateGroups, + contract: resolvedContract, + code: "frontend_context_blocked", + message: + "Frontend generation context cannot accept conflicting Artifact Inspector surface, topology, profile, or authority signals.", }); + if ( + artifactInspectorSelected && + !artifactInspectorIntegritySealMatches( + "ui_generation_handoff", + artifactInspectorBoundaryIntegrityPayload(uiGenerationHandoff), + uiGenerationHandoff.source?.artifact_inspector_boundary_integrity, + ) + ) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend context requires an intact handoff from the current trusted review process.", + { + code: "frontend_context_blocked", + details: { + field: "source.artifact_inspector_boundary_integrity", + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }, + }, + ); + } const normalizedFrontendContext = normalizeFrontendContext(frontendContext); const normalizedVerification = normalizeVerificationContext(verification); const requiredSurfaces = toSurfaceSetArray(uiGenerationHandoff.surface_set); const requiredSurfaceAggregate = aggregateSurfaceSet(requiredSurfaces); const designSystemContract = normalizeDefaultAiNativeDesignSystem( - uiGenerationHandoff.implementation_contract?.default_ai_native_design_system, + effectiveImplementationContract.default_ai_native_design_system, DEFAULT_AI_NATIVE_DESIGN_SYSTEM, ); const localComponentAuthority = normalizeLocalComponentAuthority( - uiGenerationHandoff.implementation_contract?.local_component_authority, + effectiveImplementationContract.local_component_authority, DEFAULT_LOCAL_COMPONENT_AUTHORITY, ); const visualCompositionPolicy = - uiGenerationHandoff.implementation_contract?.visual_composition_policy ?? + effectiveImplementationContract.visual_composition_policy ?? null; const evidenceFieldMapping = reviewEvidenceFieldMapping( - uiGenerationHandoff.implementation_contract, + effectiveImplementationContract, designSystemContract, { selectedSurfaceType: surfaceGuidance.recommended_surface_type }, ); @@ -15515,8 +19498,113 @@ export function createFrontendGenerationContext({ ? "surface_review" : "inferred_from_handoff"; const designSystemSource = - uiGenerationHandoff.implementation_contract?.design_system_source ?? + effectiveImplementationContract.design_system_source ?? DEFAULT_DESIGN_SYSTEM_SOURCE; + const supportedProfileIds = supportedSurfaceProfiles === undefined + ? listSurfacePresentationProfiles().map((entry) => entry.id) + : toStringArray(supportedSurfaceProfiles); + if ( + supportedSurfaceProfiles !== undefined && + (!Array.isArray(supportedSurfaceProfiles) || + supportedProfileIds.length !== supportedSurfaceProfiles.length) + ) { + throw new JudgmentKitInputError( + "supported_surface_profiles must be an array of non-empty canonical profile ids when provided.", + ); + } + const frontendDuplicateWorkUnitIds = duplicateWorkflowWorkUnitIds( + uiGenerationHandoff.workflow?.work_units, + ); + if ( + artifactInspectorSelected && + frontendDuplicateWorkUnitIds.length > 0 + ) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend context requires unique work-unit identifiers.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "workflow.work_units", + duplicate_work_unit_ids: frontendDuplicateWorkUnitIds, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + }, + }, + ); + } + if ( + artifactInspectorSelected && + !supportedProfileIds.includes(artifactIdentifiers.frontend_surface_profile) + ) { + throw new JudgmentKitInputError( + "The caller cannot consume the selected Artifact Inspector frontend profile.", + { + code: "artifact_inspector_profile_unsupported", + details: { + surface_type: artifactIdentifiers.surface_type, + required_surface_profile: + artifactIdentifiers.frontend_surface_profile, + supported_surface_profiles: supportedProfileIds, + fallback_applied: false, + }, + }, + ); + } + let artifactInspectorAuthority = null; + if (artifactInspectorSelected) { + try { + artifactInspectorAuthority = validateArtifactInspectorAuthorityContract( + effectiveImplementationContract, + ); + } catch (error) { + throw new JudgmentKitInputError( + error instanceof Error + ? error.message + : "Artifact Inspector authority contract is invalid.", + { + code: "invalid_artifact_inspector_authority_contract", + details: isPlainObject(error?.details) ? error.details : {}, + }, + ); + } + if (!artifactInspectorAuthority.active) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend context requires scoped authority fields from the implementation contract.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + required_fields: [ + "design_system_scopes", + "boundary_contracts", + "artifact_inspector", + ], + }, + }, + ); + } + if ( + !artifactInspectorStateGroupsMatch( + artifactInspectorAuthority.artifact_inspector.active_state_groups, + reviewedActiveStateGroups, + ) + ) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend context cannot activate state groups absent from the reviewed workflow.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "artifact_inspector.active_state_groups", + expected: reviewedActiveStateGroups, + observed: + artifactInspectorAuthority.artifact_inspector + .active_state_groups, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }, + }, + ); + } + } const normalizedSurfaceProfileRequest = normalizeSurfaceProfileRequest(surfaceProfile); const selectedSurfaceProfile = resolveSurfacePresentationProfile({ @@ -15530,7 +19618,7 @@ export function createFrontendGenerationContext({ designSystemMode: designSystemSource.mode, }); - return { + const packet = { version: uiGenerationHandoff.version, contract_id: uiGenerationHandoff.contract_id, workflow_id: getContractWorkflowId(resolvedContract), @@ -15539,6 +19627,16 @@ export function createFrontendGenerationContext({ handoff_status: uiGenerationHandoff.handoff_status, surface_type_source: surfaceTypeSource, surface_profile_request: normalizedSurfaceProfileRequest, + supported_surface_profiles: supportedProfileIds, + ...(artifactInspectorSelected + ? { + reviewed_activity_input: reviewedActivityInput, + reviewed_active_state_groups: reviewedActiveStateGroups, + artifact_inspector_boundary_integrity: + uiGenerationHandoff.source + ?.artifact_inspector_boundary_integrity, + } + : {}), }, surface_type: surfaceGuidance.recommended_surface_type, surface_guidance: surfaceGuidance, @@ -15551,7 +19649,7 @@ export function createFrontendGenerationContext({ surface_set: requiredSurfaces, product_terms: toStringArray(uiGenerationHandoff.product_terms), handoff: uiGenerationHandoff.handoff, - implementation_contract: uiGenerationHandoff.implementation_contract, + implementation_contract: effectiveImplementationContract, disclosure_reminders: uiGenerationHandoff.disclosure_reminders, frontend_context: { target_runtime: optionalString(normalizedFrontendContext.target_runtime), @@ -15575,7 +19673,7 @@ export function createFrontendGenerationContext({ interaction_implications: surfaceGuidance.interaction_implications, disclosure_implications: surfaceGuidance.disclosure_implications, frontend_posture: surfaceGuidance.frontend_posture, - implementation_contract: uiGenerationHandoff.implementation_contract, + implementation_contract: effectiveImplementationContract, design_system_source: designSystemSource, local_component_authority: localComponentAuthority, @@ -15583,14 +19681,47 @@ export function createFrontendGenerationContext({ ? { visual_composition_policy: visualCompositionPolicy } : {}), visual_asset_policy: - uiGenerationHandoff.implementation_contract?.visual_asset_policy ?? + effectiveImplementationContract.visual_asset_policy ?? DEFAULT_VISUAL_ASSET_POLICY, accessibility_policy: - uiGenerationHandoff.implementation_contract?.accessibility_policy ?? + effectiveImplementationContract.accessibility_policy ?? DEFAULT_ACCESSIBILITY_POLICY, evidence_field_mapping: evidenceFieldMapping, component_contracts: designSystemContract.component_contracts, pattern_contracts: designSystemContract.pattern_contracts, + ...(artifactInspectorAuthority?.active + ? { + artifact_inspector: { + registry: cloneWorkflowStructuredValue( + artifactInspectorAuthority.artifact_inspector, + ), + artifact: cloneWorkflowStructuredValue( + isPlainObject(uiGenerationHandoff.workflow?.artifact) + ? uiGenerationHandoff.workflow.artifact + : {}, + ), + target_model: cloneWorkflowStructuredValue( + isPlainObject(uiGenerationHandoff.workflow?.target_model) + ? uiGenerationHandoff.workflow.target_model + : {}, + ), + state_groups: cloneWorkflowStructuredValue( + isPlainObject(uiGenerationHandoff.workflow?.state_groups) + ? uiGenerationHandoff.workflow.state_groups + : {}, + ), + active_state_groups: + artifactInspectorAuthority.artifact_inspector + .active_state_groups, + design_system_scopes: + artifactInspectorAuthority.design_system_scopes, + boundary_contracts: + artifactInspectorAuthority.boundary_contracts, + external_artifact_review_status: + "external_not_reviewed", + }, + } + : {}), required_surfaces: requiredSurfaces, required_sections: requiredSurfaceAggregate.sections, required_controls: requiredSurfaceAggregate.controls, @@ -15603,6 +19734,14 @@ export function createFrontendGenerationContext({ "Render declared visual-composition relationships at required viewports after fonts are ready, measure DOM geometry under the active policy, and attach candidate-scoped visual_composition_evidence.", ] : []), + ...(artifactInspectorAuthority?.active + ? [ + "Verify JudgmentKit chrome and inspection overlay scopes independently from the external artifact.", + "Verify artifact render fingerprints remain stable across chrome-only transitions.", + "Verify native artifact actions retain precedence until explicit inspection mode is active.", + "Verify semantic target re-anchoring, stale-target handling, overlay occlusion, focus return, and cross-boundary status announcements.", + ] + : []), ]), states_to_verify: toStringArray(normalizedVerification.states_to_verify), }, @@ -15616,8 +19755,20 @@ export function createFrontendGenerationContext({ diagnostic_contexts: uiGenerationHandoff.disclosure_reminders?.diagnostic_contexts ?? [], approved_primitives: - uiGenerationHandoff.implementation_contract?.approved_primitives ?? [], + effectiveImplementationContract.approved_primitives ?? [], design_system_source: designSystemSource, + ...(artifactInspectorAuthority?.active + ? { + artifact_inspector_authority: { + design_system_scopes: + artifactInspectorAuthority.design_system_scopes, + boundary_contracts: + artifactInspectorAuthority.boundary_contracts, + external_artifact_review_status: "external_not_reviewed", + trusted_runtime_evidence_required: true, + }, + } + : {}), ...(visualCompositionPolicy ? { visual_composition_policy: visualCompositionPolicy } : {}), @@ -15626,6 +19777,16 @@ export function createFrontendGenerationContext({ : {}), }, }; + + if (artifactInspectorSelected) { + packet.source.artifact_inspector_boundary_integrity = + createArtifactInspectorIntegritySeal( + "frontend_generation_context", + artifactInspectorBoundaryIntegrityPayload(packet), + ); + } + + return packet; } function buildFrontendImplementationInstructionMarkdown({ @@ -15634,8 +19795,16 @@ function buildFrontendImplementationInstructionMarkdown({ selectedSurfaceProfile, targetClient, evidenceFieldMapping, + artifactInspectorGuidance: trustedArtifactInspectorGuidance, }) { const implementationGuidance = frontendGenerationContext.implementation_guidance ?? {}; + const artifactInspectorGuidance = isPlainObject( + trustedArtifactInspectorGuidance, + ) + ? trustedArtifactInspectorGuidance + : isPlainObject(implementationGuidance.artifact_inspector) + ? implementationGuidance.artifact_inspector + : null; const reviewEvidenceMapping = evidenceFieldMapping ?? implementationGuidance.evidence_field_mapping ?? {}; const primitiveEvidenceMapping = reviewEvidenceMapping.primitives_used ?? {}; @@ -15654,6 +19823,15 @@ function buildFrontendImplementationInstructionMarkdown({ const verification = implementationGuidance.verification_expectations ?? {}; const frontendContext = frontendGenerationContext.frontend_context ?? {}; const workflow = frontendGenerationContext.workflow ?? {}; + const workflowWorkUnitLabels = toWorkflowWorkUnitArray(workflow.work_units) + .map((workUnit) => + typeof workUnit === "string" + ? workUnit + : optionalString( + workUnit.label ?? workUnit.participant_intent ?? workUnit.id, + ), + ) + .filter(Boolean); const requiredSurfaces = toSurfaceSetArray(implementationGuidance.required_surfaces); const visualAssetPolicy = implementationGuidance.visual_asset_policy ?? DEFAULT_VISUAL_ASSET_POLICY; @@ -15708,7 +19886,7 @@ function buildFrontendImplementationInstructionMarkdown({ "- Shape the interface around the selected surface type and surface set before choosing section layout.", ...(selectedSurfaceProfile ? [ - "- Apply the selected surface presentation profile after the activity and Workbench pattern contract are satisfied; it does not replace runtime truth or the active design-system source.", + "- Apply the selected surface presentation profile after the activity and matching pattern contract are satisfied; it does not replace runtime truth or the active design-system source.", ] : []), "- Use numbered wizard or stepper UI only when workflow.stepper_eligibility.allowed is true.", @@ -15731,6 +19909,13 @@ function buildFrontendImplementationInstructionMarkdown({ "- Repair fail or review outcomes, rerender, and replace the receipt before resubmitting. Keep browser_owned_indicator_unmeasured as the policy-declared non-blocking warning for native select arrows.", ] : []), + ...(artifactInspectorGuidance + ? [ + "- Keep the rendered artifact primary and preserve its external visual authority; apply JudgmentKit tokens and component conformance only inside inspector_chrome and inspection_overlay.", + "- Use declared semantic locus identifiers for every overlay-to-artifact event, preserve native live-artifact actions until explicit inspection mode, and re-anchor to the same target or mark it stale.", + "- Treat candidate-authored scope, preservation, or boundary claims as non-accepting context. This release cannot produce or accept the deferred interactive attestation, so implementation review remains review_required and the primary artifact remains external_not_reviewed.", + ] + : []), "- 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.", "- 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.", @@ -15761,7 +19946,7 @@ function buildFrontendImplementationInstructionMarkdown({ "", "## Required Surface", `- Topology: ${workflow.topology || "workspace"}`, - `- Work units: ${toStringArray(workflow.work_units).join("; ") || "none supplied"}`, + `- Work units: ${workflowWorkUnitLabels.join("; ") || "none supplied"}`, `- Stepper eligibility: ${workflow.stepper_eligibility?.allowed ? "allowed" : "not allowed"}`, `- Surfaces: ${requiredSurfaces.map((surface) => `${surface.name}: ${surface.purpose}`).join("; ") || "none supplied"}`, `- Sections: ${toStringArray(implementationGuidance.required_sections).join("; ") || "none supplied"}`, @@ -15847,13 +20032,13 @@ function buildFrontendImplementationInstructionMarkdown({ `- Type aliases: ${formatRoleEntries(selectedSurfaceProfile.typography?.css_custom_properties, (entry) => `${entry.name}: ${entry.value}`) || "none supplied"}`, `- Density aliases: ${formatRoleEntries(selectedSurfaceProfile.density?.css_custom_properties, (entry) => `${entry.name}: ${entry.value}`) || "none supplied"}`, `- Composition: ${selectedSurfaceProfile.composition?.density || "operational"} density; ${selectedSurfaceProfile.composition?.hierarchy || "flat_border_led"} hierarchy`, - `- Navigation shapes: ${toStringArray(selectedSurfaceProfile.composition?.navigation_shapes).join("; ") || "none supplied"}`, + `- Navigation shapes: ${toStringArray(selectedSurfaceProfile.composition?.navigation_shapes).join("; ") || optionalString(selectedSurfaceProfile.composition?.navigation_shape) || "none supplied"}`, `- Interaction regions and controls: governed by the ${selectedSurfaceProfile.authority?.pattern_contract_id || "selected"} pattern contract`, `- Profile rules: ${toStringArray(selectedSurfaceProfile.composition?.rules).join("; ") || "none supplied"}`, `- State coverage: ${toStringArray(selectedSurfaceProfile.state_coverage).join("; ") || "none supplied"}`, - `- Desktop: ${selectedSurfaceProfile.responsive?.desktop || "none supplied"}`, - `- Compact: ${selectedSurfaceProfile.responsive?.compact || "none supplied"}`, - `- Product adapter owns: ${toStringArray(selectedSurfaceProfile.product_adapter_boundary?.product_adapter_owns).join("; ") || "none supplied"}`, + `- Desktop or wide: ${selectedSurfaceProfile.responsive?.desktop || selectedSurfaceProfile.responsive?.wide || "none supplied"}`, + `- Compact or narrow: ${selectedSurfaceProfile.responsive?.compact || selectedSurfaceProfile.responsive?.narrow || "none supplied"}`, + `- Product or external artifact authority owns: ${toStringArray(selectedSurfaceProfile.product_adapter_boundary?.product_adapter_owns).join("; ") || toStringArray(selectedSurfaceProfile.product_adapter_boundary?.external_artifact_authority_owns).join("; ") || "none supplied"}`, `- Excluded from this generic profile: ${toStringArray(selectedSurfaceProfile.product_adapter_boundary?.excluded_from_generic_profile).join("; ") || "none supplied"}`, ] : []), @@ -15955,6 +20140,11 @@ export function createFrontendImplementationSkillContext({ implementationGuidance.visual_composition_policy ?? implementationContract.visual_composition_policy ?? null; + let artifactInspectorGuidance = isPlainObject( + implementationGuidance.artifact_inspector, + ) + ? cloneWorkflowStructuredValue(implementationGuidance.artifact_inspector) + : null; let visualTokenAdapter = normalizeVisualTokenAdapter( implementationContract.visual_token_adapter ?? {}, DEFAULT_VISUAL_TOKEN_ADAPTER, @@ -15974,6 +20164,215 @@ export function createFrontendImplementationSkillContext({ const hasInlineDesignSystemAdapter = hasDesignGuidanceValue( normalizedDesignSystemAdapter, ); + const frontendSurfaceTypeCandidates = [ + optionalString(frontendGenerationContext.surface_type), + optionalString(frontendGenerationContext.surface_guidance?.recommended_surface_type), + optionalString(implementationGuidance.surface_type), + ].filter(Boolean); + const reviewedActivityInput = optionalRawString( + frontendGenerationContext.source?.reviewed_activity_input, + ); + const reviewedActiveStateGroups = reviewedActivityInput + ? deriveArtifactInspectorReviewedActiveStateGroups({ + sourceInput: reviewedActivityInput, + }) + : undefined; + const serializedReviewedActiveStateGroups = toStringArray( + frontendGenerationContext.source?.reviewed_active_state_groups, + ); + const skillArtifactConsistency = assertArtifactInspectorBoundaryConsistency({ + workflow, + surfaceTypes: frontendSurfaceTypeCandidates, + profileIds: [ + frontendGenerationContext.guidance_profile?.profile_id, + implementationGuidance.guidance_profile_id, + ], + implementationContract, + additionalAuthoritySignals: [artifactInspectorGuidance], + activityModel: frontendGenerationContext.activity_model, + interactionContract: frontendGenerationContext.interaction_contract, + reviewedActiveStateGroups, + code: "invalid_artifact_inspector_authority_contract", + message: + "Frontend implementation skill context cannot accept conflicting Artifact Inspector surface, topology, profile, or authority signals.", + }); + const artifactInspectorContextActive = + skillArtifactConsistency.artifactInspectorActive; + + if (artifactInspectorContextActive) { + if (!reviewedActivityInput) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend skill context requires the reviewed activity input used to justify conditional state groups.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "source.reviewed_activity_input", + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }, + }, + ); + } + if ( + !artifactInspectorStateGroupsMatch( + serializedReviewedActiveStateGroups, + reviewedActiveStateGroups, + ) + ) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend skill context requires the serialized reviewed-state ceiling to match the grounded activity.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "source.reviewed_active_state_groups", + expected: reviewedActiveStateGroups, + observed: serializedReviewedActiveStateGroups, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }, + }, + ); + } + const frontendDuplicateWorkUnitIds = duplicateWorkflowWorkUnitIds( + workflow.work_units, + ); + if (frontendDuplicateWorkUnitIds.length > 0) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend skill context requires unique work-unit identifiers.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "workflow.work_units", + duplicate_work_unit_ids: frontendDuplicateWorkUnitIds, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + }, + }, + ); + } + let serializedArtifactInspectorAuthority; + try { + serializedArtifactInspectorAuthority = + validateArtifactInspectorAuthorityContract(implementationContract); + } catch (error) { + throw new JudgmentKitInputError( + error instanceof Error + ? error.message + : "Artifact Inspector frontend skill authority is invalid.", + { + code: "invalid_artifact_inspector_authority_contract", + details: isPlainObject(error?.details) ? error.details : {}, + }, + ); + } + if (!serializedArtifactInspectorAuthority.active) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend skill context requires the scoped authority bundle.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + required_fields: [ + "design_system_scopes", + "boundary_contracts", + "artifact_inspector", + ], + }, + }, + ); + } + const declaredStateGroupSelections = [ + serializedArtifactInspectorAuthority.artifact_inspector + .active_state_groups, + ...(Array.isArray(artifactInspectorGuidance?.active_state_groups) + ? [artifactInspectorGuidance.active_state_groups] + : []), + ...(Array.isArray( + artifactInspectorGuidance?.registry?.active_state_groups, + ) + ? [artifactInspectorGuidance.registry.active_state_groups] + : []), + ]; + if ( + declaredStateGroupSelections.some( + (selection) => + !artifactInspectorStateGroupsMatch( + selection, + reviewedActiveStateGroups, + ), + ) + ) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend skill context cannot activate state groups absent from the reviewed workflow.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "artifact_inspector.active_state_groups", + expected: reviewedActiveStateGroups, + observed: declaredStateGroupSelections, + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }, + }, + ); + } + artifactInspectorGuidance = { + registry: cloneWorkflowStructuredValue( + serializedArtifactInspectorAuthority.artifact_inspector, + ), + artifact: cloneWorkflowStructuredValue( + isPlainObject(workflow.artifact) ? workflow.artifact : {}, + ), + target_model: cloneWorkflowStructuredValue( + isPlainObject(workflow.target_model) ? workflow.target_model : {}, + ), + state_groups: cloneWorkflowStructuredValue( + isPlainObject(workflow.state_groups) ? workflow.state_groups : {}, + ), + active_state_groups: reviewedActiveStateGroups, + design_system_scopes: cloneWorkflowStructuredValue( + serializedArtifactInspectorAuthority.design_system_scopes, + ), + boundary_contracts: cloneWorkflowStructuredValue( + serializedArtifactInspectorAuthority.boundary_contracts, + ), + external_artifact_review_status: "external_not_reviewed", + }; + if (optionalString(designSystemSource.mode) !== "judgmentkit_default") { + throw new JudgmentKitInputError( + "Artifact Inspector frontend skill context requires JudgmentKit authority for inspector chrome and the inspection overlay.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "design_system_source.mode", + expected: "judgmentkit_default", + observed: optionalString(designSystemSource.mode) || null, + external_artifact_scope: "primary_artifact", + }, + }, + ); + } + const canonicalDesignSystem = canonicalJudgmentKitDesignSystemAuthority(); + visualTokenAdapter = canonicalDesignSystem.visualTokenAdapter; + designSystemContract = canonicalDesignSystem.defaultDesignSystem; + designSystemSource = canonicalDesignSystem.designSystemSource; + } + + if (artifactInspectorContextActive && hasInlineDesignSystemAdapter) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend skill context cannot replace JudgmentKit authority for inspector chrome or the inspection overlay with a whole-context design-system adapter.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "design_system_adapter", + judgmentkit_owned_scopes: [ + "inspector_chrome", + "inspection_overlay", + ], + external_artifact_scope: "primary_artifact", + }, + }, + ); + } if ( designSystemSource.mode === "external_design_system" && @@ -16000,6 +20399,30 @@ export function createFrontendImplementationSkillContext({ }; } + if ( + artifactInspectorContextActive && + !artifactInspectorIntegritySealMatches( + "frontend_generation_context", + artifactInspectorBoundaryIntegrityPayload( + frontendGenerationContext, + ), + frontendGenerationContext.source + ?.artifact_inspector_boundary_integrity, + ) + ) { + throw new JudgmentKitInputError( + "Artifact Inspector frontend skill context requires an intact serialized boundary from the current trusted review process.", + { + code: "invalid_artifact_inspector_authority_contract", + details: { + field: "source.artifact_inspector_boundary_integrity", + diagnostic_code: + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + }, + }, + ); + } + const selectedSurfaceProfileCandidate = frontendGenerationContext.selected_surface_profile ?? implementationGuidance.selected_surface_profile; @@ -16028,7 +20451,10 @@ export function createFrontendImplementationSkillContext({ } if (designSystemSource.mode === "judgmentkit_default") { - if (selectedSurfaceProfileCandidate.id !== WORKBENCH_SURFACE_PROFILE_ID) { + const supportedCanonicalProfile = cloneSurfacePresentationProfile( + selectedSurfaceProfileCandidate.id, + ); + if (!supportedCanonicalProfile) { throw new JudgmentKitInputError( "selected_surface_profile must name a supported canonical profile id.", { @@ -16056,7 +20482,7 @@ export function createFrontendImplementationSkillContext({ const candidateSelection = selectedSurfaceProfileCandidate.selection; if ( - !["auto", WORKBENCH_SURFACE_PROFILE_ID].includes(recordedRequest) || + !["auto", supportedCanonicalProfile.id].includes(recordedRequest) || !isPlainObject(candidateSelection) || candidateSelection.request !== recordedRequest || candidateSelection.surface_type_source !== recordedSurfaceTypeSource || @@ -16171,6 +20597,14 @@ export function createFrontendImplementationSkillContext({ "When local component authority is active, scan component-specific selectors for visual identity declarations and direct --jk-* token use.", ] : []), + ...(artifactInspectorGuidance + ? [ + "Record inspector_chrome, inspection_overlay, external-artifact preservation, and boundary behavior as separate deferred attestation requirements.", + "Do not infer artifact preservation from static roots or unchanged fingerprints.", + "Leave native-action precedence, semantic target re-anchoring, overlay occlusion, focus return, cross-boundary announcements, and the required state/viewport matrix unverified in this release.", + "Keep primary_artifact external_not_reviewed and owned scopes review_required.", + ] + : []), "Verify substantive visuals use imagegen or premium Three.js/WebGL/D3-style rendering when the spec calls for them.", "Provide browser-rendered visual-background contrast evidence for text over images, canvas, WebGL, video, gradients, or generated visuals.", "Verify non-text contrast for meaningful icons, charts, state indicators, custom controls, and authored focus indicators.", @@ -16193,6 +20627,17 @@ export function createFrontendImplementationSkillContext({ (state) => `Verify required state: ${state}`, ), ]); + const skillSurfaceImplications = artifactInspectorContextActive + ? buildSurfaceImplications( + DEFAULT_ARTIFACT_INSPECTOR_SURFACE_TYPE_ID, + ) + : { + interaction_implications: + implementationGuidance.interaction_implications ?? {}, + disclosure_implications: + implementationGuidance.disclosure_implications ?? {}, + frontend_posture: implementationGuidance.frontend_posture ?? {}, + }; const packet = { version: frontendGenerationContext.version, contract_id: frontendGenerationContext.contract_id, @@ -16215,13 +20660,14 @@ export function createFrontendImplementationSkillContext({ selectedSurfaceProfile, targetClient: normalizedTargetClient, evidenceFieldMapping, + artifactInspectorGuidance, }), implementation_sequence: [ "Confirm the activity, primary decision, workflow topology, work units, coordinated surfaces, and handoff from the ready frontend context.", "Map the selected surface type to the surface set, required sections, controls, density, navigation, and responsive expectations.", ...(selectedSurfaceProfile ? [ - "Apply selected_surface_profile as supported presentation guidance after satisfying the activity, Workbench pattern, and active design-system source contracts.", + "Apply selected_surface_profile as supported presentation guidance after satisfying the activity, matching pattern, and active design-system source contracts.", ] : []), "Use numbered wizard or stepper UI only when workflow.stepper_eligibility.allowed is true.", @@ -16244,6 +20690,12 @@ export function createFrontendImplementationSkillContext({ "On a visual composition fail or review outcome, repair only the declared relationship, rerender, replace the receipt, and resubmit before acceptance.", ] : []), + ...(artifactInspectorGuidance + ? [ + "Keep the artifact dominant; attach context, action, feedback, and results to the active semantic locus without restyling the artifact.", + "Apply JudgmentKit design-system conformance only to inspector_chrome and inspection_overlay, preserve primary_artifact as external_not_reviewed, and require trusted scope, preservation, and boundary proof before acceptance.", + ] + : []), "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.", "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.", @@ -16258,14 +20710,36 @@ export function createFrontendImplementationSkillContext({ ? { presentation_profile_id: selectedSurfaceProfile.id } : {}), workflow_topology: optionalString(workflow.topology) || "workspace", - work_units: toStringArray(workflow.work_units), + ...(isPlainObject(workflow.topology_contract) + ? { + topology_contract: cloneWorkflowStructuredValue( + workflow.topology_contract, + ), + } + : {}), + work_units: cloneWorkflowStructuredValue( + toWorkflowWorkUnitArray(workflow.work_units), + ), + ...(isPlainObject(workflow.artifact) + ? { artifact: cloneWorkflowStructuredValue(workflow.artifact) } + : {}), + ...(isPlainObject(workflow.target_model) + ? { + target_model: cloneWorkflowStructuredValue(workflow.target_model), + } + : {}), + ...(isPlainObject(workflow.state_groups) + ? { + state_groups: cloneWorkflowStructuredValue(workflow.state_groups), + } + : {}), stepper_eligibility: workflow.stepper_eligibility ?? {}, surface_set: requiredSurfaces, interaction_implications: - implementationGuidance.interaction_implications ?? {}, + skillSurfaceImplications.interaction_implications, disclosure_implications: - implementationGuidance.disclosure_implications ?? {}, - frontend_posture: implementationGuidance.frontend_posture ?? {}, + skillSurfaceImplications.disclosure_implications, + frontend_posture: skillSurfaceImplications.frontend_posture, }, approved_primitives: toStringArray(implementationContract.approved_primitives), approved_component_families: toStringArray( @@ -16282,6 +20756,9 @@ export function createFrontendImplementationSkillContext({ ...(visualCompositionPolicy ? { visual_composition_policy: visualCompositionPolicy } : {}), + ...(artifactInspectorGuidance + ? { artifact_inspector: artifactInspectorGuidance } + : {}), ...(selectedSurfaceProfile ? { selected_surface_profile: selectedSurfaceProfile } : {}), @@ -16309,6 +20786,18 @@ export function createFrontendImplementationSkillContext({ ...(visualCompositionPolicy ? { visual_composition_policy: visualCompositionPolicy } : {}), + ...(artifactInspectorGuidance + ? { + artifact_inspector_authority: { + design_system_scopes: + artifactInspectorGuidance.design_system_scopes, + boundary_contracts: + artifactInspectorGuidance.boundary_contracts, + external_artifact_review_status: "external_not_reviewed", + trusted_runtime_evidence_required: true, + }, + } + : {}), visual_asset_policy: visualAssetPolicy, accessibility_policy: accessibilityPolicy, product_ui_rule: diff --git a/src/mcp.mjs b/src/mcp.mjs index e9f3b7d..fb62500 100644 --- a/src/mcp.mjs +++ b/src/mcp.mjs @@ -121,7 +121,7 @@ const ACTIVITY_MODEL_REVIEW_TOOL = { const RECOMMEND_SURFACE_TYPES_TOOL = { name: "recommend_surface_types", description: - "Recommend a purpose-based UI surface type from activity evidence before workflow review or frontend implementation.", + "Recommend a purpose-based UI surface type from activity evidence before workflow review or frontend implementation, including artifact_inspector only when its mandatory evidence is satisfied.", inputSchema: { type: "object", required: ["brief"], @@ -130,7 +130,7 @@ const RECOMMEND_SURFACE_TYPES_TOOL = { type: "string", minLength: 1, description: - "Source UI brief to classify by activity and purpose.", + "Source UI brief to classify by activity and purpose, including rendered-artifact, selectable-locus, and locus-relative support evidence when artifact_inspector may apply.", }, activity_review: { type: "object", @@ -150,7 +150,7 @@ const RECOMMEND_SURFACE_TYPES_TOOL = { const RECOMMEND_UI_WORKFLOW_PROFILES_TOOL = { name: "recommend_ui_workflow_profiles", description: - "Recommend optional UI workflow guidance profiles for a source brief without applying them automatically.", + "Recommend optional UI workflow guidance profiles, including artifact-inspector-ui when its artifact activity evidence applies, without applying them automatically.", inputSchema: { type: "object", required: ["brief"], @@ -205,12 +205,12 @@ const REVIEW_UI_WORKFLOW_CANDIDATE_TOOL = { candidate: { type: "object", description: - "Externally proposed UI workflow candidate with workflow, surface_set, handoff, and diagnostics.", + "Externally proposed UI workflow candidate with workflow, surface_set, handoff, and diagnostics. workflow.topology may be a legacy topology string or an artifact-centered topology object; workflow.topology_contract is also accepted for artifact-centered candidates.", }, profile_id: { type: "string", description: - "Optional guidance profile id, such as operator-review-ui.", + "Optional guidance profile id, such as operator-review-ui or artifact-inspector-ui.", }, surface_review: { type: "object", @@ -220,7 +220,7 @@ const REVIEW_UI_WORKFLOW_CANDIDATE_TOOL = { surface_type: { type: "string", description: - "Optional selected surface type, such as workbench, marketing, setup_debug_tool, or operator_review.", + "Optional selected surface type, such as workbench, marketing, setup_debug_tool, operator_review, or artifact_inspector.", }, }, additionalProperties: false, @@ -253,7 +253,7 @@ const REVIEW_COGNITIVE_DIMENSIONS_CANDIDATE_TOOL = { surface_type: { type: "string", description: - "Optional selected surface type, such as workbench, operator_review, dashboard_monitor, or setup_debug_tool.", + "Optional selected surface type, such as workbench, operator_review, dashboard_monitor, setup_debug_tool, or artifact_inspector.", }, surface_evidence: { type: "object", @@ -296,7 +296,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, optional repo-local component authority, or a complete external design-system adapter when supplied.", + "Create an implementation contract for generated UI, using JudgmentKit design-system authority by default, optional repo-local component authority, or a complete external design-system adapter when supplied. surface_type artifact_inspector activates scoped JudgmentKit chrome and overlay authority while keeping the primary artifact external_not_reviewed.", inputSchema: { type: "object", properties: { @@ -308,6 +308,11 @@ const UI_IMPLEMENTATION_CONTRACT_TOOL = { type: "string", description: "Optional frontend stack, such as vanilla JS, React, or server-rendered HTML.", }, + surface_type: { + type: "string", + description: + "Optional selected surface type. artifact_inspector activates the canonical design_system_scopes, boundary_contracts, and artifact_inspector bundle.", + }, external_authority: { type: "string", description: @@ -383,7 +388,7 @@ const UI_IMPLEMENTATION_CONTRACT_TOOL = { const REVIEW_UI_IMPLEMENTATION_CANDIDATE_TOOL = { name: "review_ui_implementation_candidate", description: - "Review generated UI or code evidence against an active UI implementation contract. The active design-system gate is hard: missing or failing design_system_provenance means the candidate is not an artifact and must be repaired and resubmitted. Include local_component_authority_evidence when repo-local component authority is active. When visual_composition_policy applies, the hosted MCP renders exact self-contained HTML in an isolated browser, measures declared and discovered relationships, and attaches a server-trusted receipt; caller-authored visual_composition_evidence cannot satisfy acceptance.", + "Review generated UI or code evidence against an active UI implementation contract. The active design-system gate is hard: missing or failing design_system_provenance means the candidate is not an artifact and must be repaired and resubmitted. Include local_component_authority_evidence when repo-local component authority is active. When visual_composition_policy applies, the hosted MCP renders exact self-contained HTML in an isolated browser, measures declared and discovered relationships, and attaches a server-trusted receipt; caller-authored visual_composition_evidence cannot satisfy acceptance. The hosted static renderer cannot satisfy Artifact Inspector authority: that surface remains review_required until the separately deferred interactive attestation exists, and the external artifact always remains external_not_reviewed.", inputSchema: { type: "object", required: ["candidate", "implementation_contract"], @@ -457,13 +462,24 @@ const FRONTEND_GENERATION_CONTEXT_TOOL = { surface_type: { type: "string", description: - "Optional selected surface type, such as marketing, workbench, setup_debug_tool, or operator_review.", + "Optional selected surface type, such as marketing, workbench, setup_debug_tool, operator_review, or artifact_inspector.", }, surface_profile: { type: "string", - enum: ["auto", "none", "judgmentkit.workbench.operational-v1"], + enum: [ + "auto", + "none", + "judgmentkit.workbench.operational-v1", + "judgmentkit.artifact-inspector.v1", + ], + description: + "Optional surface presentation profile request. Defaults to auto; use none to opt out. artifact_inspector may use judgmentkit.artifact-inspector.v1. It does not change surface classification or design-system authority.", + }, + supported_surface_profiles: { + type: "array", + items: { type: "string" }, description: - "Optional surface presentation profile request. Defaults to auto; use none to opt out. It does not change surface classification or design-system authority.", + "Optional caller capability list. If artifact_inspector is selected and judgmentkit.artifact-inspector.v1 is absent, return artifact_inspector_profile_unsupported without fallback.", }, frontend_context: { type: "object", @@ -496,7 +512,7 @@ const FRONTEND_IMPLEMENTATION_SKILL_CONTEXT_TOOL = { design_system_adapter: { type: "object", description: - "Deprecated compatibility path for complete external design-system authority. Prefer supplying design_system_adapter to create_ui_implementation_contract so the frontend context receives implementation_contract.design_system_source.", + "Deprecated compatibility path for complete external design-system authority. Prefer supplying design_system_adapter to create_ui_implementation_contract so the frontend context receives implementation_contract.design_system_source. Rejected for Artifact Inspector because JudgmentKit must retain authority over inspector chrome and the inspection overlay.", }, target_client: { type: "string", @@ -737,7 +753,14 @@ function toDisplayList(values, limit = 4) { } return values - .map((entry) => compactText(entry) || (isRecord(entry) ? compactText(entry.message) : "")) + .map((entry) => + compactText(entry) || + (isRecord(entry) + ? [entry.label, entry.participant_intent, entry.id, entry.message] + .map(compactText) + .find(Boolean) ?? "" + : ""), + ) .filter(Boolean) .slice(0, limit); } @@ -2560,6 +2583,10 @@ function planningStatus(result) { return "Implementation gate passed"; } + if (result.implementation_review_status === "review_required") { + return "Review required; interactive attestation deferred"; + } + if (result.implementation_review_status === "failed") { return "Implementation gate failed"; } @@ -2576,6 +2603,10 @@ function planningStatus(result) { return "Frontend skill context ready"; } + if (result.status === "review_required") { + return "Review required"; + } + if (result.recommended_surface_type) { return result.status === "needs_source_context" ? "Needs source context" @@ -2664,6 +2695,79 @@ function diagnosticSummary(result) { return diagnostics.length > 0 ? diagnostics.join("; ") : "No blocking diagnostics in the planning card."; } +function artifactTopologyDiagnosticCodes(result) { + const artifactGuardrail = result.guardrails?.artifact_inspector; + const entries = [ + ...(Array.isArray(artifactGuardrail?.diagnostics) + ? artifactGuardrail.diagnostics + : []), + ...(Array.isArray(result.guardrails?.artifact_topology_diagnostics) + ? result.guardrails.artifact_topology_diagnostics + : []), + ]; + + return [ + ...new Set( + entries + .map((entry) => + typeof entry === "string" + ? compactText(entry) + : isRecord(entry) + ? compactText(entry.code) + : "", + ) + .filter(Boolean), + ), + ]; +} + +function routingConflictSignalList(routingConflict) { + if (!isRecord(routingConflict)) { + return []; + } + + const signals = Array.isArray(routingConflict.conflicting_signals) + ? routingConflict.conflicting_signals + : []; + + return signals + .map((signal) => { + if (typeof signal === "string") { + return compactText(signal); + } + + if (!isRecord(signal)) { + return ""; + } + + const kind = compactText(signal.kind); + const id = compactText(signal.id ?? signal.evidence_id ?? signal.message); + + return [kind, id].filter(Boolean).join(": "); + }) + .filter(Boolean); +} + +function competingSurfaceTypeList(routingConflict) { + if (!isRecord(routingConflict)) { + return []; + } + + const entries = Array.isArray(routingConflict.competing_surface_types) + ? routingConflict.competing_surface_types + : []; + + return entries + .map((entry) => + typeof entry === "string" + ? compactText(entry) + : isRecord(entry) + ? compactText(entry.surface_type ?? entry.id ?? entry.label) + : "", + ) + .filter(Boolean); +} + function formatActivityReviewCard(result) { const activity = result.candidate?.activity_model ?? {}; const interaction = result.candidate?.interaction_contract ?? {}; @@ -2726,7 +2830,13 @@ function formatWorkflowReviewCard(result) { firstLine("Handoff", handoff.next_action), ]); addSection(lines, "Targeted questions", bulletList(result.review?.targeted_questions)); - addSection(lines, "Diagnostics", [`${diagnosticSummary(result)}`]); + addSection(lines, "Diagnostics", [ + `${diagnosticSummary(result)}`, + listLine( + "Artifact topology diagnostics", + artifactTopologyDiagnosticCodes(result), + ), + ]); return lines.join("\n"); } @@ -2786,10 +2896,16 @@ function formatAnalysisCard(result) { } function formatSurfaceRecommendationCard(result) { + const recommendedSurfaceType = compactText(result.recommended_surface_type); + const nextStep = recommendedSurfaceType + ? `Use surface_type "${recommendedSurfaceType}" as purpose guidance before workflow review and frontend implementation.` + : isRecord(result.routing_conflict) + ? "Resolve the routing conflict before choosing a surface type or continuing to workflow review." + : "Resolve the missing surface evidence before workflow review and frontend implementation."; const lines = [ "## JudgmentKit Surface Recommendation", `**Status:** ${planningStatus(result)}`, - `**Next step:** Use surface_type "${compactText(result.recommended_surface_type)}" as purpose guidance before workflow review and frontend implementation.`, + `**Next step:** ${nextStep}`, ]; addSection(lines, "Plan from this", [ @@ -2808,6 +2924,14 @@ function formatSurfaceRecommendationCard(result) { "Implementation terms", termList(result.evidence?.implementation_terms_detected), ), + listLine( + "Routing conflict signals", + routingConflictSignalList(result.routing_conflict), + ), + listLine( + "Competing surface types", + competingSurfaceTypeList(result.routing_conflict), + ), ]); return lines.join("\n"); @@ -2943,12 +3067,16 @@ function formatImplementationReviewCard(result) { "pattern_contracts", ].includes(finding.check), ); + const nextStep = + result.implementation_review_status === "passed" + ? "**Next step:** The candidate passed the implementation gate; use the evidence in the final handoff." + : result.implementation_review_status === "review_required" + ? "**Next step:** Stop before acceptance. This release cannot produce the deferred Artifact Inspector interactive attestation; keep the external artifact external_not_reviewed and owned scopes review_required." + : "**Next step:** This is not an artifact. Repair the failed gates and resubmit before final UI handoff."; const lines = [ "## JudgmentKit Implementation Review", `**Status:** ${planningStatus(result)}`, - result.implementation_review_status === "passed" - ? "**Next step:** The candidate passed the implementation gate; use the evidence in the final handoff." - : "**Next step:** This is not an artifact. Repair the failed gates and resubmit before final UI handoff.", + nextStep, ]; addSection(lines, "Checks", [ @@ -3354,7 +3482,10 @@ export function formatPlanningCard(result) { return formatImplementationContractCard(result); } - if (result?.recommended_surface_type) { + if ( + result?.recommended_surface_type || + (isRecord(result) && Object.hasOwn(result, "recommended_surface_type")) + ) { return formatSurfaceRecommendationCard(result); } @@ -3599,6 +3730,7 @@ export async function handleToolCall(name, args = {}) { surface_review: args.surface_review, surface_type: args.surface_type, surface_profile: args.surface_profile, + supported_surface_profiles: args.supported_surface_profiles, frontend_context: args.frontend_context, verification: args.verification, }); @@ -3828,6 +3960,7 @@ export function createJudgmentKitMcpServer() { inputSchema: { repo_name: z.string().optional(), target_stack: z.string().optional(), + surface_type: z.string().optional(), external_authority: z.string().optional(), design_system_adapter: z.record(z.any()).optional(), design_system_source: z.record(z.any()).optional(), @@ -3900,8 +4033,14 @@ export function createJudgmentKitMcpServer() { surface_review: z.record(z.any()).optional(), surface_type: z.string().optional(), surface_profile: z - .enum(["auto", "none", "judgmentkit.workbench.operational-v1"]) + .enum([ + "auto", + "none", + "judgmentkit.workbench.operational-v1", + "judgmentkit.artifact-inspector.v1", + ]) .optional(), + supported_surface_profiles: z.array(z.string()).optional(), frontend_context: z.record(z.any()).optional(), verification: z.record(z.any()).optional(), }, diff --git a/src/surface-presentation-profiles.mjs b/src/surface-presentation-profiles.mjs index 9f4d828..09fcc39 100644 --- a/src/surface-presentation-profiles.mjs +++ b/src/surface-presentation-profiles.mjs @@ -1,5 +1,7 @@ export const WORKBENCH_SURFACE_PROFILE_ID = "judgmentkit.workbench.operational-v1"; +export const ARTIFACT_INSPECTOR_SURFACE_PROFILE_ID = + "judgmentkit.artifact-inspector.v1"; function deepFreeze(value) { if (!value || typeof value !== "object" || Object.isFrozen(value)) { @@ -236,10 +238,289 @@ export const WORKBENCH_SURFACE_PROFILE = deepFreeze({ }, }); +export const ARTIFACT_INSPECTOR_SURFACE_PROFILE = deepFreeze({ + id: ARTIFACT_INSPECTOR_SURFACE_PROFILE_ID, + version: "1.0.0", + status: "proposed", + name: "JudgmentKit Artifact Inspector", + surface_type: "artifact_inspector", + workflow_profile_id: "artifact-inspector-ui", + interaction_topology_kind: "artifact_centered", + purpose: + "Keep one rendered artifact primary while JudgmentKit-owned chrome and overlays attach context, actions, state, and receipts to a selected artifact locus.", + authority: { + mode: "scoped_mixed_visual_authority", + public_contract: true, + runtime_renderer: false, + design_system_source_mode: "judgmentkit_default", + design_system_source_id: "judgmentkit.design-system.source-v1", + visual_token_adapter_id: "judgmentkit.visual-token-adapter.boundary-v1", + pattern_contract_id: "artifact-inspector", + design_system_scopes: [ + { + scope_id: "inspector_chrome", + root_selector: "[data-jk-scope='inspector-chrome']", + authority: "judgmentkit_default", + enforcement: "required", + style_isolation: "required", + }, + { + scope_id: "inspection_overlay", + root_selector: "[data-jk-scope='inspection-overlay']", + authority: "judgmentkit_default", + enforcement: "required", + style_isolation: "required", + }, + { + scope_id: "primary_artifact", + root_selector: "[data-artifact-root]", + authority: "external_declared", + enforcement: "external_not_reviewed", + style_isolation: "required", + }, + ], + boundary_contracts: [ + { + from_scope: "inspection_overlay", + to_scope: "primary_artifact", + allowed_roles: [ + "locus_target", + "annotation_overlay", + "connector_endpoint", + ], + event_contract_required: true, + }, + ], + review_result_policy: + "Report chrome, overlay, external artifact, and boundary results separately; never describe the external artifact as JudgmentKit-conformant, and keep owned scopes review_required until the deferred interactive attestation exists.", + }, + activation: { + default_request: "auto", + accepted_requests: [ + "auto", + "none", + ARTIFACT_INSPECTOR_SURFACE_PROFILE_ID, + ], + accepted_confidence: ["medium", "high", "provided"], + explicit_profile_request_requires_grounded_surface: true, + low_confidence_neutral_fallback: "do_not_activate", + external_artifact_authority: "allowed_when_scoped", + whole_candidate_external_design_system_fallback: "none", + }, + appearance: { + supported_modes: ["light", "dark", "system"], + default_mode: "system", + visible_toggle_default: false, + token_source: + "implementation_contract.visual_token_adapter.appearance_token_sets", + scope_rule: + "JudgmentKit appearance tokens apply only to inspector_chrome and inspection_overlay.", + }, + typography: { + font_source: "implementation_contract.visual_token_adapter.font_roles", + font_roles: ["body", "heading", "label", "numeric"], + css_custom_properties: [ + { + name: "--jk-artifact-inspector-type-body", + value: "0.875rem", + usage: "restrained inspector context and local feedback", + }, + { + name: "--jk-artifact-inspector-type-label", + value: "0.75rem", + usage: "sparse locus, authority, state, and receipt labels", + }, + ], + }, + density: { + css_custom_properties: [ + { + name: "--jk-artifact-inspector-chrome-gap", + value: "0.75rem", + usage: "space between the artifact boundary and contextual chrome", + }, + { + name: "--jk-artifact-inspector-target-size", + value: "2.75rem", + usage: "minimum JudgmentKit-owned locus and action target size", + }, + { + name: "--jk-artifact-inspector-overlay-offset", + value: "0.5rem", + usage: "minimum offset for overlay feedback from essential artifact content", + }, + ], + }, + composition: { + density: "artifact-first contextual", + hierarchy: "artifact_dominant", + navigation_shape: + "artifact persistent; supporting context revealed from the active locus", + allowed_variants: [ + "peripheral anchors", + "contextual tray", + "inline annotation", + "inspection lens", + "responsive hybrid", + ], + rules: [ + "Keep the artifact as the largest and most persistent visual region.", + "Keep the active locus visible while its supporting context is open.", + "Attach evidence, authority, actions, feedback, and receipts visibly or semantically to the active locus.", + "Distinguish reversible preview from consequential commitment and durable result.", + "Keep JudgmentKit-owned overlay marks distinguishable from artifact content.", + "Use the least persistent chrome that preserves target, context, action, recovery, and result together.", + ], + avoid_by_default: [ + "master-detail", + "queue-detail", + "dashboard summaries", + "persistent evidence dossiers", + "stacked labeled panels", + "form-like step progression", + "chat composer or message history", + "drag-only, hover-only, or color-only interaction", + ], + }, + state_coverage: [ + "artifact loading", + "artifact ready", + "artifact unavailable or failed", + "no active locus", + "locus focused or selected", + "context loading", + "context ready", + "relation or action preview", + "supported", + "incompatible", + "unavailable", + "stale", + "ambiguous", + "blocked", + "cancelled or Back", + "local error and retry", + ], + responsive: { + wide: + "Keep the artifact central and persistent, reveal sparse support at the periphery or from the active locus, and route connectors around the inspected locus and essential content.", + narrow: + "Keep the artifact primary, move support into a temporary edge affordance or contextual tray, and preserve the active locus, feedback, recovery, zoom, reflow, and non-drag alternatives together without obstruction.", + invariant: + "Wide and narrow placements use the same state machine, actions, completion, and recovery semantics.", + required_evidence: [ + "wide viewport", + "narrow viewport", + "pointer path", + "touch path without hover", + "keyboard path", + "focus order and focus return", + "responsive no obstruction", + "zoom and reflow", + ], + }, + component_role_authority: "semantic_contract_only", + component_roles: [ + { id: "ArtifactViewport", scope_id: "inspector_chrome" }, + { id: "ArtifactBoundary", scope_id: "inspector_chrome" }, + { id: "ArtifactStatus", scope_id: "inspector_chrome" }, + { id: "ObservationMarker", scope_id: "inspection_overlay" }, + { id: "LocusSelection", scope_id: "inspection_overlay" }, + { id: "ContextAnchor", scope_id: "inspection_overlay" }, + { id: "AuthorityAnchor", scope_id: "inspection_overlay" }, + { id: "AnchorRail", scope_id: "inspector_chrome" }, + { id: "RelationPreview", scope_id: "inspection_overlay" }, + { id: "RelationConnector", scope_id: "inspection_overlay" }, + { id: "InlineReason", scope_id: "inspection_overlay" }, + { id: "ContextTray", scope_id: "inspector_chrome" }, + { id: "CommitBoundary", scope_id: "inspector_chrome" }, + { id: "ReceiptMarker", scope_id: "inspection_overlay" }, + { id: "BackAction", scope_id: "inspector_chrome" }, + { id: "ResetAction", scope_id: "inspector_chrome" }, + { + id: "ZoomAndPanControls", + scope_id: "inspector_chrome", + conditional: "artifact_requires_zoom_or_pan", + }, + ], + product_adapter_boundary: { + generic_profile_owns: [ + "inspector chrome density and hierarchy", + "selection and overlay state treatment", + "context, action, recovery, and receipt relationships", + "responsive artifact-inspection transitions", + "cross-boundary focus and announcement contract", + ], + external_artifact_authority_owns: [ + "artifact typography", + "artifact components", + "artifact color and elevation", + "artifact internal layout", + "artifact internal semantics and controls", + ], + boundary_contract_owns: [ + "semantic locus identifiers", + "artifact target geometry", + "cross-boundary event precedence", + "overlay obstruction and target drift", + "focus order and focus return", + ], + excluded_from_generic_profile: [ + "artifact restyling", + "visual inference presented as artifact truth", + "silent interception of native artifact actions", + "whole-candidate JudgmentKit conformance claims", + ], + }, + evidence_expectations: [ + "Name this profile id, artifact_inspector surface type, artifact-inspector-ui workflow profile, and artifact_centered topology.", + "The deferred interactive attestation must provide an exact region and authority map for inspector chrome, inspection overlay, primary artifact, and their boundary.", + "The deferred interactive attestation must prove style isolation in both directions without restyling the external artifact.", + "The deferred interactive attestation must provide the artifact render fingerprint before and after every chrome state transition.", + "The deferred interactive attestation must verify pointer, touch, keyboard, and assistive-technology crossings through declared semantic locus identifiers.", + "The deferred interactive attestation must verify focus order, focus stability, inspection-mode announcements, and focus return.", + "The deferred interactive attestation must verify overlay occlusion, target re-anchoring, stale targets, and target-drift prevention.", + "The deferred interactive attestation must cover wide and narrow rest, selection, preview, invalid, supported, unavailable, recovery, and local-result states.", + "The deferred interactive attestation must report chrome conformance, overlay conformance, external artifact preservation, and boundary behavior separately.", + ], + provenance: { + definition_id: ARTIFACT_INSPECTOR_SURFACE_PROFILE_ID, + promotion_status: "proposed", + runtime_evidence_policy: "deferred_interactive_attestation_required", + runtime_evidence_producer: "unavailable_in_this_release", + external_artifact_review_status: "external_not_reviewed", + }, +}); + +const SURFACE_PRESENTATION_PROFILES = deepFreeze({ + [WORKBENCH_SURFACE_PROFILE_ID]: WORKBENCH_SURFACE_PROFILE, + [ARTIFACT_INSPECTOR_SURFACE_PROFILE_ID]: + ARTIFACT_INSPECTOR_SURFACE_PROFILE, +}); + +export function cloneSurfacePresentationProfile(profileId) { + const normalizedProfileId = + typeof profileId === "string" ? profileId.trim() : ""; + const profile = SURFACE_PRESENTATION_PROFILES[normalizedProfileId]; + + return profile ? clone(profile) : null; +} + +export function getSurfacePresentationProfile(profileId) { + return cloneSurfacePresentationProfile(profileId); +} + export function cloneWorkbenchSurfaceProfile() { - return clone(WORKBENCH_SURFACE_PROFILE); + return cloneSurfacePresentationProfile(WORKBENCH_SURFACE_PROFILE_ID); +} + +export function cloneArtifactInspectorSurfaceProfile() { + return cloneSurfacePresentationProfile( + ARTIFACT_INSPECTOR_SURFACE_PROFILE_ID, + ); } export function listSurfacePresentationProfiles() { - return [cloneWorkbenchSurfaceProfile()]; + return Object.keys(SURFACE_PRESENTATION_PROFILES).map((profileId) => + cloneSurfacePresentationProfile(profileId), + ); } diff --git a/tests/artifact-inspector-authority.test.mjs b/tests/artifact-inspector-authority.test.mjs new file mode 100644 index 0000000..946a7ef --- /dev/null +++ b/tests/artifact-inspector-authority.test.mjs @@ -0,0 +1,1193 @@ +import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +import Ajv2020 from "ajv/dist/2020.js"; + +import * as judgmentKitPublicApi from "../src/index.mjs"; +import { + JudgmentKitInputError, + createUiImplementationContract, + reviewUiImplementationCandidate, +} from "../src/index.mjs"; + +import { + ARTIFACT_INSPECTOR_CANONICAL_BOUNDARY_CONTRACTS, + ARTIFACT_INSPECTOR_CANONICAL_SCOPES, + ARTIFACT_INSPECTOR_CANONICAL_STATE_GROUPS, + ARTIFACT_INSPECTOR_DIAGNOSTIC_CODES, + ARTIFACT_INSPECTOR_SCOPE_IDS, + ARTIFACT_INSPECTOR_STATE_GROUP_IDS, + createArtifactInspectorFinding, + normalizeArtifactInspectorBoundaryContracts, + normalizeArtifactInspectorScopes, + normalizeArtifactInspectorStateConfig, + reviewArtifactInspectorAuthorityEvidence, + validateArtifactInspectorAuthorityContract, +} from "../src/artifact-inspector-authority.mjs"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const root = path.resolve(__dirname, ".."); +const contract = JSON.parse( + fs.readFileSync( + path.join(root, "contracts/ai-ui-generation.activity-contract.json"), + "utf8", + ), +); +const schema = JSON.parse( + fs.readFileSync( + path.join(root, "contracts/judgmentkit-kernel.schema.json"), + "utf8", + ), +); +const model = contract.interaction_models.artifact_inspector; +const ajv = new Ajv2020({ allErrors: true }); +const validateKernelContract = ajv.compile(schema); + +assert.equal( + "reviewArtifactInspectorAuthorityEvidence" in judgmentKitPublicApi, + false, + "The raw Artifact Inspector authority evaluator must remain package-internal so callers cannot submit self-asserted trusted evidence.", +); + +const EXPECTED_COMPONENT_ROLES = [ + "ArtifactViewport", + "ArtifactBoundary", + "ArtifactStatus", + "ObservationMarker", + "LocusSelection", + "ContextAnchor", + "AuthorityAnchor", + "AnchorRail", + "RelationPreview", + "RelationConnector", + "InlineReason", + "ContextTray", + "CommitBoundary", + "ReceiptMarker", + "BackAction", + "ResetAction", + "ZoomAndPanControls", +]; + +function canonicalArtifactImplementationContract() { + return { + design_system_scopes: structuredClone(model.design_system.scopes), + boundary_contracts: structuredClone( + model.design_system.boundary_contracts, + ), + artifact_inspector: { + registry_id: model.id, + registry_version: model.version, + ...structuredClone(model.canonical_identifiers), + active_state_groups: ["core"], + state_groups: structuredClone(model.state_groups), + trusted_runtime_evidence_required: true, + external_artifact_review_status: "external_not_reviewed", + }, + }; +} + +function contractWithArtifactImplementation() { + const candidate = structuredClone(contract); + Object.assign( + candidate.implementation_contract, + canonicalArtifactImplementationContract(), + ); + return candidate; +} + +function completeExternalDesignSystemAdapter() { + return { + design_system_name: "Material UI", + design_system_package: "@mui/material", + token_guidance: { + token_families: ["color", "type", "spacing", "radius"], + token_roles: [ + { + role: "surface", + families: ["color"], + usage: "Material UI surface colors", + }, + { + role: "decision", + families: ["color"], + usage: "Material UI action states", + }, + ], + css_custom_properties: [ + { + name: "--mui-palette-background-paper", + role: "surface", + family: "color", + value: "theme.palette.background.paper", + usage: "Material UI surfaces", + }, + { + name: "--mui-font-family", + role: "text", + family: "type", + value: "theme.typography.fontFamily", + usage: "Material UI typography", + }, + ], + }, + font_guidance: { + font_roles: { + body: { + stack: "var(--mui-font-family)", + usage: "Material UI body typography", + }, + heading: { + stack: "var(--mui-font-family)", + usage: "Material UI headings", + }, + }, + }, + icon_guidance: { + icon_roles: ["status", "action"], + icon_catalog: { + source: "external_design_system", + library: "mui-icons-material", + package: "@mui/icons-material", + version: "repo-approved", + icon_count: 2000, + license: "MIT", + notice: "Repo-approved Material UI icon adapter.", + mcp_tools: [], + }, + }, + components: ["Stack", "Button", "Alert"], + }; +} + +function passingEvidence(method = "inspection") { + return { + status: "pass", + method, + notes: "Verified.", + }; +} + +function artifactImplementationCandidate(implementationContract) { + const activeArtifactStates = implementationContract.artifact_inspector + .active_state_groups.flatMap( + (groupId) => + implementationContract.artifact_inspector.state_groups[groupId], + ); + return { + code: ` +
+
Selected locus
+
+ + + `, + primary_artifact: { + code: 'import { TextField } from "@mui/material";', + markup: + '
', + css: "[data-artifact-root] { --artifact-brand: rebeccapurple; color: var(--artifact-brand); }", + }, + primitives_used: [], + states_covered: [ + ...implementationContract.state_coverage.required_states, + ...activeArtifactStates, + ], + static_checks: ["npm run check"], + browser_qa: { + desktop: "desktop viewport checked", + mobile: "mobile viewport checked", + }, + accessibility_evidence: { + automated_checks: passingEvidence(), + semantic_content: passingEvidence(), + landmarks_headings: passingEvidence(), + name_role_value: passingEvidence(), + keyboard_navigation: passingEvidence(), + focus_order: passingEvidence(), + focus_visible: passingEvidence(), + responsive_no_overflow: passingEvidence(), + semantic_fallbacks: passingEvidence(), + non_text_contrast: { + status: "pass", + method: "computed style inspection", + samples: [{ target: "selection boundary", contrast_ratio: 3.2 }], + }, + forced_colors: { + status: "pass", + method: "forced-colors emulation", + notes: + "Owned chrome, overlays, focus indicators, and state labels remain visible.", + }, + form_labels_instructions: passingEvidence(), + form_errors: passingEvidence(), + status_messages: passingEvidence(), + }, + design_system_provenance: { + source: "judgmentkit_default", + token_source: "/design-system/visual-token-adapter.json", + typography_source: "/design-system/visual-token-adapter.json", + icon_source: "JudgmentKit icon catalog via get_icon_svg", + renderer_component_source: + "implementation_contract.default_ai_native_design_system.component_contracts", + import_boundary: + "No visual, typography, icon, or component package imports outside the active design-system source.", + token_prefix_source: + "implementation_contract.design_system_source.token_prefixes", + source_exports: + "implementation_contract.design_system_source.source_exports", + }, + pattern_contract_evidence: { + pattern_id: "artifact-inspector", + surface_type: "artifact_inspector", + regions_present: [ + "persistent rendered artifact", + "selectable artifact loci", + "locus-relative context", + "artifact-local feedback", + "artifact-local completion or recovery", + ], + controls_present: [ + "locus selection", + "context disclosure", + "preview and validation", + "Back or reset", + "commit and receipt when consequential", + ], + completion_or_handoff: + "participant verifies the result on or immediately beside the artifact locus", + }, + }; +} + +function assertInvalidKernelContract(value, message) { + assert.equal(validateKernelContract(value), false, message); + assert.ok( + (validateKernelContract.errors ?? []).length > 0, + `${message}: schema errors must be available.`, + ); +} + +assert.equal(validateKernelContract(contract), true, ajv.errorsText(validateKernelContract.errors)); +assert.deepEqual(model.canonical_identifiers, { + surface_type: "artifact_inspector", + workflow_profile: "artifact-inspector-ui", + frontend_surface_profile: "judgmentkit.artifact-inspector.v1", + topology_kind: "artifact_centered", +}); +assert.deepEqual(model.activity_evidence.mandatory, [ + "rendered_artifact_is_primary", + "locus_selection_required", + "support_context_is_locus_relative", +]); +assert.deepEqual(model.activity_evidence.positive.slice(0, 3), model.activity_evidence.mandatory); +assert.deepEqual(model.activity_evidence.exclusions, [ + "queue_or_case_is_primary", + "many_items_are_primary", + "open_ended_creation_is_primary", + "conversation_turns_are_primary", + "linear_reading_is_completion", + "monitoring_is_completion", + "configuration_is_completion", +]); +assert.equal(model.topology.kind, "artifact_centered"); +assert.equal(model.topology.primary_object_id, "artifact"); +assert.deepEqual(model.work_units.map((entry) => entry.id), [ + "orient", + "select_locus", + "inspect_context", + "preview", + "validate", + "complete", + "verify_result", + "recover", +]); +assert.deepEqual(Object.keys(model.state_groups), ARTIFACT_INSPECTOR_STATE_GROUP_IDS); +assert.deepEqual(model.design_system.component_roles, EXPECTED_COMPONENT_ROLES); +assert.deepEqual( + model.design_system.scopes.map((entry) => entry.scope_id), + ARTIFACT_INSPECTOR_SCOPE_IDS, +); +assert.deepEqual( + model.diagnostics.map((entry) => entry.code), + ARTIFACT_INSPECTOR_DIAGNOSTIC_CODES, +); + +const artifactComponentIds = new Set(EXPECTED_COMPONENT_ROLES); +assert.equal( + contract.implementation_contract.default_ai_native_design_system + .component_contracts.some((entry) => artifactComponentIds.has(entry.id)), + false, + "Artifact Inspector role names are semantic contract vocabulary, not claims of implemented component contracts.", +); +const artifactPattern = + contract.implementation_contract.default_ai_native_design_system + .pattern_contracts.find((entry) => entry.id === "artifact-inspector"); +assert.equal(artifactPattern.surface_type, "artifact_inspector"); +assert.ok( + artifactPattern.failure_signals.some((entry) => + entry.includes("external artifact is described as JudgmentKit-conformant"), + ), +); +assert.equal( + contract.implementation_contract.design_system_scopes, + undefined, + "Mixed authority must be opt-in for Artifact Inspector, not a new global default.", +); +assert.equal( + contract.implementation_contract.design_system_source.mode, + "judgmentkit_default", + "The established whole-candidate design-system source must remain unchanged.", +); + +{ + const augmented = contractWithArtifactImplementation(); + assert.equal( + validateKernelContract(augmented), + true, + ajv.errorsText(validateKernelContract.errors), + ); +} + +{ + const missingRegistry = structuredClone(contract); + delete missingRegistry.interaction_models.artifact_inspector; + assertInvalidKernelContract( + missingRegistry, + "The Artifact Inspector registry entry is required by this contract version.", + ); + + const registryWithUnknownField = structuredClone(contract); + registryWithUnknownField.interaction_models.artifact_inspector.untrusted_extension = true; + assertInvalidKernelContract( + registryWithUnknownField, + "The Artifact Inspector registry must remain strict.", + ); + + const registryWithDivergentDuplicateWorkUnit = structuredClone(contract); + const duplicateOrient = registryWithDivergentDuplicateWorkUnit.interaction_models + .artifact_inspector.work_units.find((entry) => entry.id === "recover"); + duplicateOrient.id = "orient"; + assertInvalidKernelContract( + registryWithDivergentDuplicateWorkUnit, + "The Artifact Inspector registry must reject duplicate work-unit ids even when the duplicate objects have different content.", + ); + + const partialAuthority = structuredClone(contract); + partialAuthority.implementation_contract.design_system_scopes = + structuredClone(model.design_system.scopes); + assertInvalidKernelContract( + partialAuthority, + "Partial authority declarations must fail closed.", + ); + + const wrongArtifactAuthority = contractWithArtifactImplementation(); + wrongArtifactAuthority.implementation_contract.design_system_scopes.find( + (entry) => entry.scope_id === "primary_artifact", + ).authority = "judgmentkit_default"; + assertInvalidKernelContract( + wrongArtifactAuthority, + "The primary artifact cannot be claimed by JudgmentKit.", + ); + + const globalExternalAuthority = contractWithArtifactImplementation(); + globalExternalAuthority.implementation_contract.design_system_source.mode = + "external_design_system"; + assertInvalidKernelContract( + globalExternalAuthority, + "Artifact Inspector chrome and overlays cannot inherit a global external design-system authority.", + ); + + const externalOverclaim = contractWithArtifactImplementation(); + externalOverclaim.implementation_contract.artifact_inspector + .external_artifact_review_status = "passed"; + assertInvalidKernelContract( + externalOverclaim, + "The schema must reject whole-artifact conformance overclaims.", + ); +} + +const canonicalAuthority = canonicalArtifactImplementationContract(); +const normalizedAuthority = validateArtifactInspectorAuthorityContract( + canonicalAuthority, +); +assert.equal(normalizedAuthority.active, true); +assert.deepEqual( + normalizedAuthority.design_system_scopes, + ARTIFACT_INSPECTOR_CANONICAL_SCOPES, +); +assert.deepEqual( + normalizedAuthority.boundary_contracts, + ARTIFACT_INSPECTOR_CANONICAL_BOUNDARY_CONTRACTS, +); +assert.equal( + normalizedAuthority.artifact_inspector.external_artifact_review_status, + "external_not_reviewed", +); +assert.deepEqual( + validateArtifactInspectorAuthorityContract({}), + { + active: false, + design_system_scopes: [], + boundary_contracts: [], + artifact_inspector: null, + }, + "Legacy implementation contracts must remain not applicable.", +); + +assert.deepEqual( + normalizeArtifactInspectorScopes(model.design_system.scopes, { + required: true, + }), + model.design_system.scopes, +); +assert.deepEqual( + normalizeArtifactInspectorBoundaryContracts( + model.design_system.boundary_contracts, + { + scopes: model.design_system.scopes, + required: true, + }, + ), + model.design_system.boundary_contracts, +); +for (const [label, allowedRoles] of [ + ["partial boundary-role set", ["locus_target"]], + [ + "superset boundary-role set", + [ + "locus_target", + "annotation_overlay", + "connector_endpoint", + "undeclared_role", + ], + ], + [ + "duplicate boundary-role set", + ["locus_target", "annotation_overlay", "annotation_overlay"], + ], + [ + "case-variant boundary-role set", + ["Locus_Target", "annotation_overlay", "connector_endpoint"], + ], +]) { + const boundaries = structuredClone(model.design_system.boundary_contracts); + boundaries[0].allowed_roles = allowedRoles; + assert.throws( + () => + normalizeArtifactInspectorBoundaryContracts(boundaries, { + scopes: model.design_system.scopes, + required: true, + }), + (error) => { + assert.equal(error.code, "invalid_artifact_inspector_authority_contract"); + return true; + }, + label, + ); +} + +{ + const repeatedBoundary = contractWithArtifactImplementation(); + const reversedRoles = structuredClone( + repeatedBoundary.implementation_contract.boundary_contracts[0], + ); + reversedRoles.allowed_roles.reverse(); + repeatedBoundary.implementation_contract.boundary_contracts.push( + reversedRoles, + ); + assertInvalidKernelContract( + repeatedBoundary, + "The schema must require exactly one canonical Artifact Inspector boundary.", + ); +} +assert.deepEqual( + normalizeArtifactInspectorStateConfig( + { + active_state_groups: ["core"], + state_groups: model.state_groups, + }, + { required: true }, + ), + { + active_state_groups: ["core"], + state_groups: ARTIFACT_INSPECTOR_CANONICAL_STATE_GROUPS, + }, +); + +{ + const missingCanonicalStateGroup = structuredClone(model.state_groups); + delete missingCanonicalStateGroup.automation; + const malformedCanonicalStateGroup = structuredClone(model.state_groups); + malformedCanonicalStateGroup.core = ["artifact loading"]; + const invalidStateConfigs = [ + { + label: "missing state configuration", + value: undefined, + }, + { + label: "non-object state configuration", + value: [], + }, + { + label: "missing active state groups", + value: { state_groups: structuredClone(model.state_groups) }, + }, + { + label: "malformed active state groups", + value: { + active_state_groups: "core", + state_groups: structuredClone(model.state_groups), + }, + }, + { + label: "active state groups without core", + value: { + active_state_groups: ["consequential"], + state_groups: structuredClone(model.state_groups), + }, + }, + { + label: "missing canonical state group", + value: { + active_state_groups: ["core"], + state_groups: missingCanonicalStateGroup, + }, + }, + { + label: "malformed canonical state group", + value: { + active_state_groups: ["core"], + state_groups: malformedCanonicalStateGroup, + }, + }, + ]; + + for (const testCase of invalidStateConfigs) { + assert.throws( + () => + normalizeArtifactInspectorStateConfig(testCase.value, { + required: true, + }), + (error) => { + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + testCase.label, + ); + assert.equal( + error.details?.diagnostic_code, + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + testCase.label, + ); + assert.equal(typeof error.details?.field, "string", testCase.label); + return true; + }, + testCase.label, + ); + } + + const authorityWithoutStateGroups = canonicalArtifactImplementationContract(); + delete authorityWithoutStateGroups.artifact_inspector.state_groups; + assert.throws( + () => validateArtifactInspectorAuthorityContract(authorityWithoutStateGroups), + (error) => { + assert.equal( + error.details?.diagnostic_code, + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + ); + assert.equal(error.details?.field, "artifact_inspector.state_groups"); + return true; + }, + "The implementation-contract validation path must preserve the state-group contract diagnostic.", + ); +} + +assert.throws( + () => + validateArtifactInspectorAuthorityContract({ + design_system_scopes: model.design_system.scopes, + }), + (error) => { + assert.equal(error.code, "invalid_artifact_inspector_authority_contract"); + assert.deepEqual(error.details.missing, [ + "boundary_contracts", + "artifact_inspector", + ]); + return true; + }, +); +assert.throws( + () => + normalizeArtifactInspectorScopes( + model.design_system.scopes.filter( + (entry) => entry.scope_id !== "primary_artifact", + ), + { required: true }, + ), + (error) => { + assert.equal( + error.details.diagnostic_code, + "JK_ARTIFACT_INSPECTOR_ARTIFACT_SCOPE_MISSING", + ); + assert.equal(error.details.field, "design_system_scopes"); + return true; + }, +); + +{ + const packet = createUiImplementationContract({ + surface_type: "artifact_inspector", + }); + const implementationContract = packet.implementation_contract; + + assert.equal(packet.implementation_contract_status, "ready"); + assert.equal(packet.source.surface_type, "artifact_inspector"); + assert.deepEqual( + implementationContract.design_system_scopes, + ARTIFACT_INSPECTOR_CANONICAL_SCOPES, + ); + assert.deepEqual( + implementationContract.boundary_contracts, + ARTIFACT_INSPECTOR_CANONICAL_BOUNDARY_CONTRACTS, + ); + assert.equal( + implementationContract.artifact_inspector.frontend_surface_profile, + "judgmentkit.artifact-inspector.v1", + ); + assert.equal( + implementationContract.artifact_inspector.external_artifact_review_status, + "external_not_reviewed", + ); + assert.equal( + implementationContract.design_system_source.mode, + contract.implementation_contract.design_system_source.mode, + "Scoped authority must not replace the existing whole-candidate authority model.", + ); + assert.ok( + packet.generation_gates.some( + (gate) => + gate.id === "artifact_inspector_authority_gate" && + gate.status === "review_required", + ), + ); + + const legacyPacket = createUiImplementationContract({ + surface_type: "workbench", + }); + assert.equal( + "design_system_scopes" in legacyPacket.implementation_contract, + false, + ); + assert.equal( + "artifact_inspector" in legacyPacket.implementation_contract, + false, + ); + + assert.throws( + () => + createUiImplementationContract({ + surface_type: "workbench", + design_system_scopes: model.design_system.scopes, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + return true; + }, + ); + + const legacyContractWithoutArtifactInspector = structuredClone(contract); + delete legacyContractWithoutArtifactInspector.interaction_models + .artifact_inspector; + assert.throws( + () => + createUiImplementationContract( + { surface_type: "artifact_inspector" }, + { contract: legacyContractWithoutArtifactInspector }, + ), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "artifact_inspector_profile_unsupported"); + assert.equal(error.details.fallback_applied, false); + return true; + }, + "Older contracts must receive an explicit unsupported-profile diagnostic before generic surface validation.", + ); +} + +{ + const review = reviewArtifactInspectorAuthorityEvidence(canonicalAuthority); + assert.equal(review.status, "review_required"); + assert.equal(review.applicable, true); + assert.equal(review.design_system_review.inspector_chrome, "review_required"); + assert.equal(review.design_system_review.inspection_overlay, "review_required"); + assert.equal(review.design_system_review.primary_artifact, "external_not_reviewed"); + assert.equal( + review.trusted_runtime_evidence.status, + "unavailable_in_this_release", + ); + assert.equal(review.trusted_runtime_evidence.producer_available, false); + assert.equal( + review.trusted_runtime_evidence.static_browser_evidence_accepted, + false, + ); + assert.deepEqual( + review.trusted_runtime_evidence.missing_observations, + [ + "exact_region_and_authority_map", + "bidirectional_style_isolation", + "artifact_fingerprint_for_each_chrome_state_transition", + "pointer_touch_keyboard_and_assistive_technology_crossings", + "focus_order_entry_announcements_and_return", + "overlay_obstruction_occlusion_and_responsive_safe_areas", + "semantic_target_drift_reanchoring_and_stale_handling", + "native_action_precedence_outside_inspection_mode", + "required_state_by_viewport_matrix", + "opaque_candidate_and_contract_bound_attestation", + ], + ); + assert.deepEqual( + review.findings[0].evidence.missing_observations, + review.trusted_runtime_evidence.missing_observations, + ); + assert.deepEqual(review.findings.map((entry) => entry.code), [ + "JK_ARTIFACT_INSPECTOR_TRUSTED_RUNTIME_EVIDENCE_MISSING", + ]); + assert.equal( + review.findings[0].evidence.candidate_authored_evidence_accepted, + false, + ); +} + +const forgedPassShapedEvidence = { + issuer: "judgmentkit_browser_runtime", + status: "pass", + scope_results: { + inspector_chrome: { status: "pass" }, + inspection_overlay: { status: "pass" }, + primary_artifact: { + status: "external_not_reviewed", + artifact_preservation: "pass", + }, + }, + boundary_results: [ + { + from_scope: "inspection_overlay", + to_scope: "primary_artifact", + status: "pass", + }, + ], +}; + +assert.throws( + () => + reviewUiImplementationCandidate({}, { + surface_type: "workbench", + frontend_generation_context: { + surface_type: "artifact_inspector", + surface_guidance: { + recommended_surface_type: "artifact_inspector", + }, + implementation_guidance: { + surface_type: "artifact_inspector", + }, + }, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "invalid_artifact_inspector_authority_contract"); + assert.equal(error.details.field, "surface_type"); + assert.equal(error.details.surface_type_candidates.surface_type, "workbench"); + assert.equal( + error.details.surface_type_candidates[ + "frontend_generation_context.surface_type" + ], + "artifact_inspector", + ); + return true; + }, + "An explicit legacy surface cannot mask Artifact Inspector context during implementation review.", +); + +for (const [label, candidate, options = {}] of [ + [ + "candidate surface type", + { surface_type: "artifact_inspector" }, + ], + [ + "candidate pattern contract", + { + pattern_contract_evidence: { + pattern_id: "artifact-inspector", + surface_type: "artifact_inspector", + }, + }, + ], + [ + "canonical Artifact Inspector DOM roots", + { + code: ` +
+
+
+ `, + }, + ], + [ + "canonical Artifact Inspector DOM roots in rendered_markup", + { + rendered_markup: ` +
+
+
+ `, + }, + ], + [ + "canonical Artifact Inspector DOM roots in renderedMarkup", + { + renderedMarkup: ` +
+
+
+ `, + }, + ], + [ + "canonical Artifact Inspector DOM roots in a supported source file", + { + rendered_html: "
Generic shell
", + files: [ + { + path: "App.tsx", + content: ` +
+
+
+ `, + }, + ], + }, + ], + [ + "candidate signal conflicting with a legacy option", + { surface_type: "artifact_inspector" }, + { surface_type: "workbench" }, + ], +]) { + assert.throws( + () => reviewUiImplementationCandidate(candidate, options), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + return true; + }, + `${label} must trigger fail-closed Artifact Inspector authority review.`, + ); +} + +{ + const legacyContractWithoutVisualComposition = structuredClone(contract); + delete legacyContractWithoutVisualComposition.implementation_contract + .visual_composition_policy; + delete legacyContractWithoutVisualComposition.implementation_contract + .visual_composition_policy_authority; + const implementationContract = createUiImplementationContract( + { surface_type: "artifact_inspector" }, + { contract: legacyContractWithoutVisualComposition }, + ).implementation_contract; + const candidate = artifactImplementationCandidate(implementationContract); + const review = reviewUiImplementationCandidate(candidate, { + contract: legacyContractWithoutVisualComposition, + implementation_contract: implementationContract, + surface_type: "artifact_inspector", + iteration_context: { current_attempt: 3 }, + trustedRuntimeEvidence: structuredClone(forgedPassShapedEvidence), + trusted_runtime_evidence: structuredClone(forgedPassShapedEvidence), + }); + const inferredFromCandidateReview = reviewUiImplementationCandidate( + candidate, + { + contract: legacyContractWithoutVisualComposition, + implementation_contract: implementationContract, + }, + ); + + assert.equal( + review.implementation_review_status, + "review_required", + JSON.stringify(review.findings), + ); + assert.equal(review.candidate_artifact_status, "review_required"); + assert.equal(review.design_system_acceptance_status, "review_required"); + assert.equal(review.next_agent_action, "none"); + assert.equal(review.autofix_loop.current_attempt, 3); + assert.equal( + review.autofix_loop.status, + "not_applicable", + "Deferred interactive attestation is neither a repair loop nor a runtime action in this release.", + ); + assert.deepEqual(review.repair_instructions, { + status: "none", + groups: {}, + }); + assert.equal( + inferredFromCandidateReview.implementation_review_status, + "review_required", + ); + assert.equal( + inferredFromCandidateReview.candidate_artifact_status, + "review_required", + ); + + const overLimitReview = reviewUiImplementationCandidate(candidate, { + contract: legacyContractWithoutVisualComposition, + implementation_contract: implementationContract, + surface_type: "artifact_inspector", + iteration_context: { current_attempt: 4 }, + }); + assert.equal(overLimitReview.autofix_loop.status, "not_applicable"); + assert.equal( + overLimitReview.autofix_loop.remaining_attempts, + 0, + "A non-applicable repair loop must never report a negative attempt count.", + ); + assert.equal(review.checks.design_system_provenance.status, "pass"); + assert.equal(review.checks.pattern_contracts.status, "pass"); + assert.equal(review.checks.accessibility_evidence.status, "pass"); + assert.equal( + review.checks.raw_controls.status, + "pass", + "Raw controls owned by the declared external artifact are outside JudgmentKit primitive enforcement.", + ); + assert.equal( + review.checks.design_system_provenance.status, + "pass", + "External artifact imports and tokens are outside the JudgmentKit-owned provenance scan.", + ); + assert.equal(review.checks.artifact_inspector.status, "review_required"); + assert.equal( + review.checks.artifact_inspector.design_system_review.primary_artifact, + "external_not_reviewed", + ); + assert.deepEqual(review.findings.map((entry) => entry.code), [ + "JK_ARTIFACT_INSPECTOR_TRUSTED_RUNTIME_EVIDENCE_MISSING", + ]); + assert.equal( + review.checks.artifact_inspector.findings[0].evidence + .candidate_authored_evidence_accepted, + false, + "A candidate-authored trusted-looking receipt must be ignored.", + ); + assert.ok( + review.generation_gates.some( + (gate) => + gate.id === "artifact_inspector_authority_gate" && + gate.status === "review_required", + ), + ); + + const staticRootsOnlyCandidate = artifactImplementationCandidate( + implementationContract, + ); + staticRootsOnlyCandidate.artifact_inspector_runtime_evidence = { + issuer: "judgmentkit_browser_runtime", + scope_root_counts: { + inspector_chrome: 1, + inspection_overlay: 1, + primary_artifact: 1, + }, + artifact_fingerprint_before: "unchanged-fixture", + artifact_fingerprint_after: "unchanged-fixture", + scope_overlap_count: 0, + }; + const staticRootsOnlyReview = reviewUiImplementationCandidate( + staticRootsOnlyCandidate, + { + contract: legacyContractWithoutVisualComposition, + implementation_contract: implementationContract, + surface_type: "artifact_inspector", + }, + ); + assert.equal(staticRootsOnlyReview.implementation_review_status, "review_required"); + assert.equal(staticRootsOnlyReview.candidate_artifact_status, "review_required"); + assert.equal( + staticRootsOnlyReview.checks.artifact_inspector.trusted_runtime_evidence + .static_browser_evidence_accepted, + false, + "Three static scope roots, non-overlap, and unchanged fingerprints cannot substitute for observed interactive boundary behavior.", + ); + + const chromeRawControlCandidate = artifactImplementationCandidate( + implementationContract, + ); + chromeRawControlCandidate.code = + '
'; + const chromeRawControlReview = reviewUiImplementationCandidate( + chromeRawControlCandidate, + { + contract: legacyContractWithoutVisualComposition, + implementation_contract: implementationContract, + surface_type: "artifact_inspector", + }, + ); + assert.equal( + chromeRawControlReview.checks.raw_controls.status, + "fail", + "JudgmentKit-owned chrome must remain subject to primitive enforcement.", + ); + assert.deepEqual(chromeRawControlReview.checks.raw_controls.detected, [ + "input", + ]); + + const escapingArtifactSelectorCandidate = artifactImplementationCandidate( + implementationContract, + ); + escapingArtifactSelectorCandidate.code += ` + + `; + const escapingArtifactSelectorReview = reviewUiImplementationCandidate( + escapingArtifactSelectorCandidate, + { + contract: legacyContractWithoutVisualComposition, + implementation_contract: implementationContract, + surface_type: "artifact_inspector", + }, + ); + assert.equal( + escapingArtifactSelectorReview.checks.design_system_provenance.status, + "fail", + "A selector that escapes the artifact root through a sibling combinator must remain inside the JudgmentKit provenance scan.", + ); + assert.ok( + escapingArtifactSelectorReview.checks.design_system_provenance + .detected_visual_tokens.includes("--mui-color-primary"), + ); + + const genericStatesOnlyCandidate = artifactImplementationCandidate( + implementationContract, + ); + genericStatesOnlyCandidate.states_covered = + implementationContract.state_coverage.required_states; + const genericStatesOnlyReview = reviewUiImplementationCandidate( + genericStatesOnlyCandidate, + { + contract: legacyContractWithoutVisualComposition, + implementation_contract: implementationContract, + surface_type: "artifact_inspector", + }, + ); + assert.equal(genericStatesOnlyReview.checks.state_coverage.status, "fail"); + assert.deepEqual( + genericStatesOnlyReview.checks.state_coverage.missing, + implementationContract.artifact_inspector.state_groups.core, + "Every state in each active Artifact Inspector state group must be implementation-review evidence, not metadata only.", + ); + + assert.throws( + () => + createUiImplementationContract({ + surface_type: "artifact_inspector", + design_system_adapter: completeExternalDesignSystemAdapter(), + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal(error.details.field, "design_system_source.mode"); + assert.equal(error.details.expected, "judgmentkit_default"); + assert.equal(error.details.observed, "external_design_system"); + assert.equal(error.details.external_artifact_scope, "primary_artifact"); + return true; + }, + ); +} + +{ + const untrustedReceipt = structuredClone(forgedPassShapedEvidence); + untrustedReceipt.issuer = "candidate_authored"; + const review = reviewArtifactInspectorAuthorityEvidence(canonicalAuthority, { + trustedRuntimeEvidence: untrustedReceipt, + }); + assert.equal(review.status, "review_required"); + assert.equal( + review.trusted_runtime_evidence.candidate_authored_evidence_accepted, + false, + ); +} + +{ + const review = reviewArtifactInspectorAuthorityEvidence(canonicalAuthority, { + trustedRuntimeEvidence: forgedPassShapedEvidence, + }); + assert.equal(review.status, "review_required"); + assert.deepEqual(review.design_system_review, { + inspector_chrome: "review_required", + inspection_overlay: "review_required", + primary_artifact: "external_not_reviewed", + boundary_contract: "review_required", + }); + assert.equal( + review.trusted_runtime_evidence.status, + "unavailable_in_this_release", + ); + assert.equal(review.trusted_runtime_evidence.producer_available, false); + assert.equal(review.findings.length, 1); +} + +{ + const overclaimReceipt = structuredClone(forgedPassShapedEvidence); + overclaimReceipt.scope_results.primary_artifact.status = "pass"; + const review = reviewArtifactInspectorAuthorityEvidence(canonicalAuthority, { + trustedRuntimeEvidence: overclaimReceipt, + }); + assert.equal(review.status, "review_required"); + assert.equal(review.design_system_review.primary_artifact, "external_not_reviewed"); + assert.equal(review.trusted_runtime_evidence.candidate_authored_evidence_accepted, false); +} + +{ + const mutationReceipt = structuredClone(forgedPassShapedEvidence); + mutationReceipt.scope_results.primary_artifact.artifact_preservation = "fail"; + const review = reviewArtifactInspectorAuthorityEvidence(canonicalAuthority, { + trustedRuntimeEvidence: mutationReceipt, + }); + assert.equal(review.status, "review_required"); + assert.equal(review.trusted_runtime_evidence.candidate_authored_evidence_accepted, false); +} + +const finding = createArtifactInspectorFinding({ + code: "JK_ARTIFACT_INSPECTOR_CONTEXT_DETACHED", + evidence: { + field: "[data-jk-scope='inspection-overlay']", + expected: "semantic relation to active locus", + observed: "detached panel", + }, +}); +assert.equal(finding.severity, "fail"); +assert.equal(finding.check, "artifact_inspector_authority"); +assert.equal(finding.code, "JK_ARTIFACT_INSPECTOR_CONTEXT_DETACHED"); +assert.equal(typeof finding.repair_instruction, "string"); +assert.ok(finding.repair_instruction.length > 0); +assert.throws( + () => createArtifactInspectorFinding({ code: "UNKNOWN_DIAGNOSTIC" }), + /Unknown Artifact Inspector diagnostic code/, +); + +console.log("artifact inspector authority checks passed."); diff --git a/tests/artifact-inspector-routing.test.mjs b/tests/artifact-inspector-routing.test.mjs new file mode 100644 index 0000000..9a2e4e0 --- /dev/null +++ b/tests/artifact-inspector-routing.test.mjs @@ -0,0 +1,505 @@ +import assert from "node:assert/strict"; + +import { + recommendSurfaceTypes, + recommendUiWorkflowProfiles, +} from "../src/index.mjs"; + +const MANDATORY_EVIDENCE_IDS = [ + "rendered_artifact_is_primary", + "locus_selection_required", + "support_context_is_locus_relative", +]; + +const ARTIFACT_ACTIVITY = ` + An accessibility specialist inspects one rendered interface that remains the + primary artifact during an accessibility audit. They must select a specific + control inside the artifact. Evidence and corrective actions attach to that + selected control. They preview the correction, decide whether it is supported, + complete the correction, and verify the local result beside the artifact. The + outcome is a verified local result and a handoff receipt for the accessibility + team. The artifact retains its own independent visual authority while + implementation details remain diagnostic. +`; + +function artifactEvidence(review) { + return review.evidence.artifact_inspector; +} + +function surfaceScore(review, surfaceType) { + return review.evidence.surface_type_scores.find( + (entry) => entry.surface_type === surfaceType, + ); +} + +function workflowProfile(review, profileId) { + return review.recommendations.find( + (entry) => entry.profile_id === profileId, + ); +} + +{ + const review = recommendSurfaceTypes(ARTIFACT_ACTIVITY); + const evidence = artifactEvidence(review); + const score = surfaceScore(review, "artifact_inspector"); + + assert.equal(review.status, "ready"); + assert.equal(review.recommended_surface_type, "artifact_inspector"); + assert.equal(review.profile_id, "artifact-inspector-ui"); + assert.equal( + review.primary_structure, + "persistent artifact, selectable loci, contextual support, local feedback, and artifact-local completion", + ); + assert.equal(review.density, "artifact-first contextual"); + assert.equal( + review.navigation_shape, + "artifact persistent; supporting context revealed from the active locus", + ); + assert.equal(review.routing_conflict, undefined); + assert.deepEqual(evidence.mandatory_evidence_ids, MANDATORY_EVIDENCE_IDS); + assert.deepEqual(evidence.matched_mandatory_evidence, MANDATORY_EVIDENCE_IDS); + assert.deepEqual(evidence.missing_mandatory_evidence, []); + assert.equal(evidence.status, "matched"); + assert.equal(evidence.conflict, false); + assert.equal(score.profile_id, "artifact-inspector-ui"); + assert.equal(score.profile_status, "recommended"); + assert.ok( + review.interaction_implications.primary_structure.includes( + "Persistent artifact", + ), + ); + + const profiles = recommendUiWorkflowProfiles(ARTIFACT_ACTIVITY); + const artifactProfile = workflowProfile(profiles, "artifact-inspector-ui"); + assert.deepEqual(profiles.recommended_profile_ids, ["artifact-inspector-ui"]); + assert.equal(artifactProfile.status, "recommended"); + assert.equal(artifactProfile.pattern_id, "artifact-inspector"); + assert.equal(artifactProfile.trigger_match_count, 3); + assert.deepEqual( + artifactProfile.matched_triggers.slice(0, 3), + MANDATORY_EVIDENCE_IDS, + ); +} + +const ADDITIONAL_POSITIVE_FIXTURES = [ + ` + A fact checker inspects one rendered document that remains the primary + artifact. They must select a passage inside the document. A source-backed + correction attaches to that selected passage. They preview the correction + and verify the local result beside the passage. + `, + ` + An analyst inspects one rendered diagram that remains the primary artifact. + They must select a specific node. The rule and evidence that produced it + attach to that selected node. They preview the relation and verify the local + result beside the diagram. + `, + ` + A designer inspects one rendered composition that remains the primary + artifact. They must mark a specific region. Evidence and a bounded change + attach to that selected region. They preview the change and verify its local + result beside the composition. + `, +]; + +for (const fixture of ADDITIONAL_POSITIVE_FIXTURES) { + const first = recommendSurfaceTypes(fixture); + const second = recommendSurfaceTypes(fixture); + + assert.equal(first.recommended_surface_type, "artifact_inspector"); + assert.deepEqual( + artifactEvidence(first).matched_mandatory_evidence, + MANDATORY_EVIDENCE_IDS, + ); + assert.deepEqual( + second, + first, + "Repeated routing from the same fixture must remain deterministic.", + ); +} + +const NEGATIVE_ROUTING_FIXTURES = [ + [ + "operator_review", + `A release lead reviews a queue of AI-generated cases. The queue is the + primary work surface. They compare evidence and risk, approve, reject, + return, or hand off each case, and leave an audit receipt.`, + ], + [ + "workbench", + `A studio lead uses a creation workspace with a canvas and persistent tools + to compare multiple objects, decide their arrangement, edit the + composition, and leave a project handoff.`, + ], + [ + "content_report", + `A policy analyst reads a linear evidence memo. The activity is + understanding the narrative, citing references, and sharing the memo. + Completion means reading and sharing the report.`, + ], + [ + "conversation", + `A support agent handles an open-ended live chat with attachments. + Participants send messages, reply with context, and keep the conversation + thread active until it can be closed.`, + ], + [ + "dashboard_monitor", + `An operations lead monitors a status dashboard across many items. The + activity is tracking health, trends, and alerts. Completion means status + awareness and knowing whether follow-up is needed.`, + ], + [ + "form_flow", + `An intake coordinator completes a structured submission form. The activity + is entering required fields, resolving validation errors, submitting the + record, and seeing confirmation.`, + ], + [ + "form_flow", + `An operations admin updates a structured record-entry form while an + incidental rendered artifact preview remains visible. The activity is + entering required fields, resolving validation errors, submitting the + record, and seeing confirmation; no artifact locus is selected.`, + ], + [ + "setup_debug_tool", + `A platform engineer uses a setup and debugging tool for an integration. + The activity is configuring connection details, inspecting a JSON schema + and API endpoint, testing the connection, resolving setup errors, and + saving a validated configuration.`, + ], +]; + +for (const [expectedSurfaceType, fixture] of NEGATIVE_ROUTING_FIXTURES) { + const review = recommendSurfaceTypes(fixture); + + assert.equal(review.recommended_surface_type, expectedSurfaceType); + assert.notEqual(review.recommended_surface_type, "artifact_inspector"); + assert.equal(surfaceScore(review, "artifact_inspector"), undefined); +} + +{ + const incidentalSelectablePreview = ` + A clinic coordinator completes a structured intake form that is the primary + work surface. Completion means required field entry, validation, and + submission of the intake record. An incidental rendered-interface preview + remains visible; the coordinator may select a control in that preview and + supporting evidence attaches to the selected control, but the preview does + not determine completion. + `; + const first = recommendSurfaceTypes(incidentalSelectablePreview); + const second = recommendSurfaceTypes(incidentalSelectablePreview); + const profiles = recommendUiWorkflowProfiles(incidentalSelectablePreview); + const evidence = artifactEvidence(first); + const renderedPrimary = evidence.positives.find( + (entry) => entry.id === "rendered_artifact_is_primary", + ); + + assert.equal(first.recommended_surface_type, "form_flow"); + assert.notEqual(first.recommended_surface_type, "artifact_inspector"); + assert.equal(renderedPrimary.matched, false); + assert.ok( + evidence.missing_mandatory_evidence.includes( + "rendered_artifact_is_primary", + ), + ); + assert.ok( + !profiles.recommended_profile_ids.includes("artifact-inspector-ui"), + ); + assert.deepEqual( + second, + first, + "An incidental selectable preview must route deterministically.", + ); +} + +{ + const partialActivity = ` + Build an artifact inspector for one rendered interface that remains the + primary artifact. The specialist must select a specific control. Supporting + reference material is shown in a detached global library with no relation to + the selected control. + `; + const review = recommendSurfaceTypes(partialActivity); + const evidence = artifactEvidence(review); + + assert.ok(evidence, "Explicit inspector intent should expose partial evidence."); + assert.equal(evidence.status, "partial"); + assert.equal(evidence.mandatory_evidence_ids.length, 3); + assert.ok( + evidence.missing_mandatory_evidence.includes( + "support_context_is_locus_relative", + ), + ); + assert.notEqual(review.recommended_surface_type, "artifact_inspector"); + assert.equal( + surfaceScore(review, "artifact_inspector").profile_status, + "not_recommended", + ); + + const profiles = recommendUiWorkflowProfiles(partialActivity); + assert.equal( + workflowProfile(profiles, "artifact-inspector-ui").status, + "not_recommended", + ); + assert.ok(!profiles.recommended_profile_ids.includes("artifact-inspector-ui")); +} + +{ + const threadWordOnly = `${ARTIFACT_ACTIVITY} + The verified receipt is also named in the project thread for later follow-up. + `; + const review = recommendSurfaceTypes(threadWordOnly); + const evidence = artifactEvidence(review); + const conversationExclusion = evidence.exclusions.find( + (entry) => entry.id === "conversation_turns_are_primary", + ); + + assert.equal(review.recommended_surface_type, "artifact_inspector"); + assert.equal(conversationExclusion.matched, false); + assert.equal( + evidence.matched_exclusion_evidence.includes( + "conversation_turns_are_primary", + ), + false, + ); + assert.equal(surfaceScore(review, "conversation").trigger_match_count, 0); +} + +const EXCLUSION_CASES = [ + [ + "queue_or_case_is_primary", + "A review queue is the primary work surface and the team works through that queue.", + ], + [ + "many_items_are_primary", + "Multiple artifacts are primary peers and must be reviewed side by side.", + ], + [ + "open_ended_creation_is_primary", + "The primary activity is freely creating and editing the artifact.", + ], + [ + "conversation_turns_are_primary", + "The activity is an open-ended live chat where participants send messages, reply with context, and keep the conversation thread active.", + ], + [ + "linear_reading_is_completion", + "Completion means reading, understanding, citing, and sharing the report.", + ], + [ + "monitoring_is_completion", + "The primary activity is monitoring status and tracking trends.", + ], + [ + "configuration_is_completion", + "The primary activity is configuration and debugging; completion means a valid setup.", + ], +]; + +for (const [exclusionId, conflictingStatement] of EXCLUSION_CASES) { + const conflictingBrief = `${ARTIFACT_ACTIVITY}\n${conflictingStatement}`; + const review = recommendSurfaceTypes(conflictingBrief); + const evidence = artifactEvidence(review); + + assert.equal( + review.status, + "review_required", + `${exclusionId} must force explicit routing review.`, + ); + assert.equal( + review.recommended_surface_type, + null, + `${exclusionId} must not be resolved by a keyword tie-break.`, + ); + assert.equal(review.routing_conflict.status, "review_required"); + assert.deepEqual( + review.routing_conflict.matched_mandatory_evidence, + MANDATORY_EVIDENCE_IDS, + ); + assert.ok( + review.routing_conflict.matched_exclusion_evidence.includes(exclusionId), + `${exclusionId} must appear in the conflict packet.`, + ); + assert.equal(evidence.status, "review_required"); + assert.equal(evidence.conflict, true); + assert.deepEqual(review.interaction_implications, {}); + assert.deepEqual(review.disclosure_implications, {}); + assert.deepEqual(review.frontend_posture, {}); + + const profiles = recommendUiWorkflowProfiles(conflictingBrief); + const artifactProfile = workflowProfile(profiles, "artifact-inspector-ui"); + assert.equal(artifactProfile.status, "review_required"); + assert.ok(artifactProfile.matched_exclusions.includes(exclusionId)); + assert.deepEqual(profiles.review_required_profile_ids, [ + "artifact-inspector-ui", + ]); + assert.ok(!profiles.recommended_profile_ids.includes("artifact-inspector-ui")); +} + +{ + const selectedCaseDetailArtifact = ` + A release lead works through a review queue that is the primary work surface. + For the selected case, one rendered interface is central inside the + selected-case detail so the lead can inspect that case. They compare case + evidence, approve or return each case, and leave an audit receipt. + `; + const review = recommendSurfaceTypes(selectedCaseDetailArtifact); + + assert.equal(review.recommended_surface_type, "workbench"); + assert.equal(review.evidence.artifact_inspector, undefined); + assert.equal( + review.interaction_implications.primary_structure, + "Item selection, detail evidence, decision controls, and completion state.", + "An interface that is central only within selected-case detail must not displace the explicitly primary queue.", + ); +} + +{ + const selectedCaseDetailPaneArtifact = ` + A release lead works through a review queue that is the primary work surface. + Within the detail pane for the selected case, one rendered interface remains + central so the lead can inspect that case. They compare case evidence, + approve or return each case, and leave an audit receipt. + `; + const review = recommendSurfaceTypes(selectedCaseDetailPaneArtifact); + + assert.equal(review.recommended_surface_type, "workbench"); + assert.equal(review.evidence.artifact_inspector, undefined); +} + +{ + const explicitlySecondaryCentralArtifact = ` + A growth marketer creates a public landing page for prospects. The primary + activity is explaining the offer and helping visitors request a demo. A + secondary rendered interface remains central within its demo card, but it is + not the primary object. Visitors may select a control and evidence attaches + there. Completion is the demo request. + `; + const review = recommendSurfaceTypes(explicitlySecondaryCentralArtifact); + + assert.equal(review.recommended_surface_type, "marketing"); + assert.notEqual(review.recommended_surface_type, "artifact_inspector"); +} + +const SECONDARY_ARTIFACT_MARKETING_BRIEFS = [ + ` + A growth marketer creates a public landing page for prospects. The primary + activity is explaining the offer, proof, and benefits, then helping visitors + request a demo. A secondary rendered interface remains visible. Visitors may + select a specific control, and supporting evidence attaches to that selected + control, but the interface only supports the offer. Completion is a qualified + demo request. + `, + ` + A growth marketer creates a public landing page for prospects. The primary + activity is explaining the offer and helping visitors request a demo. A + rendered interface remains visible as supporting context. Visitors may select + a control and evidence attaches there, but completion is the demo request. + `, + ` + A growth marketer creates a public landing page for prospects. The primary + activity is explaining the offer and helping visitors request a demo. A + rendered interface remains visible but is secondary to the offer. Visitors + may select a control and evidence attaches there. Completion is the request. + `, + ` + A growth marketer creates a public landing page for prospects. The primary + activity is explaining the offer and helping visitors request a demo. A + rendered interface serves only as supporting context. Visitors may select a + control and evidence attaches there. Completion is the request. + `, + ` + A growth marketer creates a public landing page for prospects. The primary + activity is explaining the offer and helping visitors request a demo. A + rendered interface remains visible only as supporting context. Visitors may + select a control and evidence attaches there. Completion is the request. + `, + ` + A growth marketer creates a public landing page for prospects. The primary + activity is explaining the offer and helping visitors request a demo. A + rendered interface is merely supporting context. Visitors may select a + control and evidence attaches there. Completion is the request. + `, + ` + A growth marketer creates a public landing page for prospects. The primary + activity is explaining the offer and helping visitors request a demo. A + rendered interface remains visible; it only supports the offer. Visitors may + select a control and evidence attaches there. Completion is the request. + `, + ` + A growth marketer creates a public landing page for prospects. The primary + activity is explaining the offer and helping visitors request a demo. A + rendered interface supports the offer rather than serving as the primary + object. Visitors may select a control and evidence attaches there. + `, +]; + +for (const secondaryArtifactMarketingBrief of SECONDARY_ARTIFACT_MARKETING_BRIEFS) { + const review = recommendSurfaceTypes(secondaryArtifactMarketingBrief); + const evidence = artifactEvidence(review); + + assert.equal(review.recommended_surface_type, "marketing"); + if (evidence) { + const renderedPrimary = evidence.positives.find( + (entry) => entry.id === "rendered_artifact_is_primary", + ); + assert.equal(renderedPrimary.matched, false); + assert.equal( + evidence.matched_mandatory_evidence.includes( + "rendered_artifact_is_primary", + ), + false, + ); + assert.ok( + evidence.missing_mandatory_evidence.includes( + "rendered_artifact_is_primary", + ), + ); + assert.equal(surfaceScore(review, "artifact_inspector").score, 0); + } else { + assert.equal(surfaceScore(review, "artifact_inspector"), undefined); + } +} + +{ + const review = recommendSurfaceTypes(`${ARTIFACT_ACTIVITY} + A separate secondary rendered diagram remains visible as supporting context. + `); + + assert.equal(review.recommended_surface_type, "artifact_inspector"); + assert.deepEqual( + artifactEvidence(review).matched_mandatory_evidence, + MANDATORY_EVIDENCE_IDS, + "A distinct secondary artifact must not erase an explicitly primary rendered artifact.", + ); +} + +{ + const legacyMarketingBrief = ` + A growth marketer is creating a public landing page for prospects. The + activity is explaining the offer and proof, then helping visitors request a + demo. The outcome is a qualified demo request. + `; + const review = recommendSurfaceTypes(legacyMarketingBrief); + + assert.equal(review.recommended_surface_type, "marketing"); + assert.equal(review.evidence.artifact_inspector, undefined); + assert.deepEqual( + review.evidence.surface_type_scores.map((entry) => entry.surface_type), + [ + "marketing", + "workbench", + "operator_review", + "form_flow", + "dashboard_monitor", + "content_report", + "setup_debug_tool", + "conversation", + ], + "Unrelated legacy routing must not gain an Artifact Inspector score.", + ); +} + +console.log("artifact inspector routing checks passed."); diff --git a/tests/artifact-inspector-surface-profile.test.mjs b/tests/artifact-inspector-surface-profile.test.mjs new file mode 100644 index 0000000..e23c287 --- /dev/null +++ b/tests/artifact-inspector-surface-profile.test.mjs @@ -0,0 +1,277 @@ +import assert from "node:assert/strict"; +import { createHash } from "node:crypto"; + +import { + ARTIFACT_INSPECTOR_SURFACE_PROFILE, + ARTIFACT_INSPECTOR_SURFACE_PROFILE_ID, + WORKBENCH_SURFACE_PROFILE, + cloneArtifactInspectorSurfaceProfile, + cloneSurfacePresentationProfile, + cloneWorkbenchSurfaceProfile, + getSurfacePresentationProfile, + listSurfacePresentationProfiles, +} from "../src/surface-presentation-profiles.mjs"; + +const EXPECTED_PROFILE_ID = "judgmentkit.artifact-inspector.v1"; +const EXPECTED_COMPONENT_ROLES = [ + "ArtifactViewport", + "ArtifactBoundary", + "ArtifactStatus", + "ObservationMarker", + "LocusSelection", + "ContextAnchor", + "AuthorityAnchor", + "AnchorRail", + "RelationPreview", + "RelationConnector", + "InlineReason", + "ContextTray", + "CommitBoundary", + "ReceiptMarker", + "BackAction", + "ResetAction", + "ZoomAndPanControls", +]; +const EXPECTED_CORE_STATES = [ + "artifact loading", + "artifact ready", + "artifact unavailable or failed", + "no active locus", + "locus focused or selected", + "context loading", + "context ready", + "relation or action preview", + "supported", + "incompatible", + "unavailable", + "stale", + "ambiguous", + "blocked", + "cancelled or Back", + "local error and retry", +]; + +function profileHash(profile) { + return createHash("sha256") + .update(JSON.stringify(profile)) + .digest("hex"); +} + +function scope(profile, scopeId) { + return profile.authority.design_system_scopes.find( + (entry) => entry.scope_id === scopeId, + ); +} + +assert.equal( + ARTIFACT_INSPECTOR_SURFACE_PROFILE_ID, + EXPECTED_PROFILE_ID, +); +assert.equal(ARTIFACT_INSPECTOR_SURFACE_PROFILE.id, EXPECTED_PROFILE_ID); +assert.equal( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.surface_type, + "artifact_inspector", +); +assert.equal( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.workflow_profile_id, + "artifact-inspector-ui", +); +assert.equal( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.interaction_topology_kind, + "artifact_centered", +); +assert.equal(ARTIFACT_INSPECTOR_SURFACE_PROFILE.status, "proposed"); +assert.equal( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.provenance.promotion_status, + "proposed", +); +assert.equal( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.composition.hierarchy, + "artifact_dominant", +); +assert.ok( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.composition.rules.some((rule) => + rule.includes("largest and most persistent visual region"), + ), +); +assert.ok( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.composition.avoid_by_default.includes( + "master-detail", + ), +); +assert.deepEqual( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.state_coverage, + EXPECTED_CORE_STATES, +); +assert.ok( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.responsive.wide.includes( + "artifact central and persistent", + ), +); +assert.ok( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.responsive.narrow.includes( + "artifact primary", + ), +); +assert.ok( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.responsive.invariant.includes( + "same state machine", + ), +); +assert.deepEqual( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.component_roles.map((role) => role.id), + EXPECTED_COMPONENT_ROLES, +); + +const chromeScope = scope( + ARTIFACT_INSPECTOR_SURFACE_PROFILE, + "inspector_chrome", +); +const overlayScope = scope( + ARTIFACT_INSPECTOR_SURFACE_PROFILE, + "inspection_overlay", +); +const artifactScope = scope( + ARTIFACT_INSPECTOR_SURFACE_PROFILE, + "primary_artifact", +); +const boundary = + ARTIFACT_INSPECTOR_SURFACE_PROFILE.authority.boundary_contracts[0]; + +assert.deepEqual(chromeScope, { + scope_id: "inspector_chrome", + root_selector: "[data-jk-scope='inspector-chrome']", + authority: "judgmentkit_default", + enforcement: "required", + style_isolation: "required", +}); +assert.deepEqual(overlayScope, { + scope_id: "inspection_overlay", + root_selector: "[data-jk-scope='inspection-overlay']", + authority: "judgmentkit_default", + enforcement: "required", + style_isolation: "required", +}); +assert.deepEqual(artifactScope, { + scope_id: "primary_artifact", + root_selector: "[data-artifact-root]", + authority: "external_declared", + enforcement: "external_not_reviewed", + style_isolation: "required", +}); +assert.deepEqual(boundary, { + from_scope: "inspection_overlay", + to_scope: "primary_artifact", + allowed_roles: [ + "locus_target", + "annotation_overlay", + "connector_endpoint", + ], + event_contract_required: true, +}); +assert.ok( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.authority.review_result_policy.includes( + "never describe the external artifact as JudgmentKit-conformant", + ), +); +assert.ok( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.evidence_expectations.some((entry) => + entry.includes("style isolation in both directions"), + ), +); +assert.ok( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.evidence_expectations.some((entry) => + entry.includes("artifact render fingerprint"), + ), +); +assert.ok( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.evidence_expectations.some((entry) => + entry.includes("report chrome conformance") && + entry.includes("external artifact preservation"), + ), +); +assert.equal( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.component_role_authority, + "semantic_contract_only", +); +assert.equal( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.provenance.runtime_evidence_policy, + "deferred_interactive_attestation_required", +); +assert.equal( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.provenance.runtime_evidence_producer, + "unavailable_in_this_release", +); + +assert.ok(Object.isFrozen(ARTIFACT_INSPECTOR_SURFACE_PROFILE)); +assert.ok(Object.isFrozen(ARTIFACT_INSPECTOR_SURFACE_PROFILE.authority)); +assert.ok( + Object.isFrozen( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.authority.design_system_scopes, + ), +); +assert.ok(Object.isFrozen(artifactScope)); +assert.ok( + Object.isFrozen(ARTIFACT_INSPECTOR_SURFACE_PROFILE.component_roles[0]), +); + +const clonedArtifactProfile = cloneArtifactInspectorSurfaceProfile(); +const clonedById = cloneSurfacePresentationProfile(EXPECTED_PROFILE_ID); +const lookedUpProfile = getSurfacePresentationProfile( + ` ${EXPECTED_PROFILE_ID} `, +); + +for (const candidate of [clonedArtifactProfile, clonedById, lookedUpProfile]) { + assert.deepEqual(candidate, ARTIFACT_INSPECTOR_SURFACE_PROFILE); + assert.notStrictEqual(candidate, ARTIFACT_INSPECTOR_SURFACE_PROFILE); + assert.notStrictEqual( + candidate.authority, + ARTIFACT_INSPECTOR_SURFACE_PROFILE.authority, + ); + assert.notStrictEqual( + candidate.authority.design_system_scopes, + ARTIFACT_INSPECTOR_SURFACE_PROFILE.authority.design_system_scopes, + ); +} + +clonedArtifactProfile.name = "Mutated clone"; +clonedArtifactProfile.authority.design_system_scopes[0].authority = + "mutated-authority"; +assert.equal( + ARTIFACT_INSPECTOR_SURFACE_PROFILE.name, + "JudgmentKit Artifact Inspector", +); +assert.equal( + scope(ARTIFACT_INSPECTOR_SURFACE_PROFILE, "inspector_chrome").authority, + "judgmentkit_default", +); +assert.equal(cloneSurfacePresentationProfile("unknown.profile"), null); +assert.equal(getSurfacePresentationProfile(null), null); + +const listedProfiles = listSurfacePresentationProfiles(); +assert.deepEqual( + listedProfiles.map((profile) => profile.id), + [WORKBENCH_SURFACE_PROFILE.id, EXPECTED_PROFILE_ID], +); +assert.notStrictEqual(listedProfiles[0], WORKBENCH_SURFACE_PROFILE); +assert.notStrictEqual( + listedProfiles[1], + ARTIFACT_INSPECTOR_SURFACE_PROFILE, +); +listedProfiles[1].component_roles[0].id = "MutatedRole"; +assert.equal( + listSurfacePresentationProfiles()[1].component_roles[0].id, + "ArtifactViewport", +); + +const clonedWorkbench = cloneWorkbenchSurfaceProfile(); +assert.deepEqual(clonedWorkbench, WORKBENCH_SURFACE_PROFILE); +assert.notStrictEqual(clonedWorkbench, WORKBENCH_SURFACE_PROFILE); +assert.equal(JSON.stringify(WORKBENCH_SURFACE_PROFILE).length, 5463); +assert.equal( + profileHash(WORKBENCH_SURFACE_PROFILE), + "e602ac05657defdfd247221b3d97a9e9454460c28202b1e47475f3d58cf56dbb", + "The existing Workbench profile must remain byte-compatible.", +); + +console.log("artifact inspector surface profile checks passed."); diff --git a/tests/artifact-inspector-workflow.test.mjs b/tests/artifact-inspector-workflow.test.mjs new file mode 100644 index 0000000..848dd17 --- /dev/null +++ b/tests/artifact-inspector-workflow.test.mjs @@ -0,0 +1,2562 @@ +import assert from "node:assert/strict"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +import { + JudgmentKitInputError, + buildUiWorkflowCandidateRequest, + createActivityModelReview, + createFrontendGenerationContext, + createFrontendImplementationSkillContext, + createUiGenerationHandoff, + createUiImplementationContract, + recommendSurfaceTypes, + reviewUiWorkflowCandidate, +} from "../src/index.mjs"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const root = path.resolve(__dirname, ".."); +const contract = JSON.parse( + fs.readFileSync( + path.join(root, "contracts/ai-ui-generation.activity-contract.json"), + "utf8", + ), +); +const model = contract.interaction_models.artifact_inspector; + +const ARTIFACT_ACTIVITY = ` + An accessibility specialist inspects one rendered interface that remains the + primary artifact during an accessibility audit. They must select a specific + control inside the artifact. Evidence and corrective actions attach to that + selected control. They preview the correction, decide whether it is supported, + complete the correction, and verify the local result beside the artifact. The + outcome is a verified local result and a handoff receipt for the accessibility + team. The artifact retains its own independent visual authority while + implementation details remain diagnostic. +`; + +const WORKBENCH_ACTIVITY = ` + A dispatch lead repeatedly reviews service exceptions in a work queue, + compares route and customer evidence, decides whether to reassign, hold, or + escalate each visit, and leaves a handoff receipt for the next owner. +`; + +const activityReview = createActivityModelReview(ARTIFACT_ACTIVITY); +const surfaceReview = recommendSurfaceTypes(ARTIFACT_ACTIVITY, { + activity_review: activityReview, +}); + +assert.equal(activityReview.review_status, "ready_for_review"); +assert.equal(surfaceReview.status, "ready"); +assert.equal(surfaceReview.recommended_surface_type, "artifact_inspector"); + +function createCandidate() { + return { + workflow: { + surface_name: "Accessibility review", + topology: structuredClone(model.topology), + work_units: structuredClone(model.work_units), + artifact: { + id: "artifact", + boundary: "Rendered interface under audit", + }, + target_model: { + ...structuredClone(model.target_model), + artifact_id: "artifact", + }, + state_groups: { + core: structuredClone(model.state_groups.core), + }, + primary_actions: [ + "Select control", + "Preview correction", + "Apply correction", + "Verify result", + "Back", + ], + decision_points: ["Is the correction supported?"], + completion_state: + "Verified result is visible beside the selected control.", + }, + surface_set: [ + { + name: "Accessibility review", + purpose: "Inspect the rendered interface in place.", + sections: [ + "Rendered interface", + "Control context", + "Local result", + ], + controls: [ + "Select control", + "Preview correction", + "Apply correction", + "Back", + ], + relationship_to_workflow: + "Keeps context and the local result attached to the interface.", + }, + ], + handoff: { + next_owner: "Accessibility team", + reason: "Correction was verified locally.", + next_action: "Review the receipt.", + }, + diagnostics: { + implementation_terms: [], + reveal_contexts: ["auditing"], + }, + }; +} + +function renamePrimaryArtifact(workflow, id = "renamed_artifact") { + const topology = + workflow.topology && typeof workflow.topology === "object" + ? workflow.topology + : workflow.topology_contract; + topology.primary_object_id = id; + workflow.artifact.id = id; + workflow.target_model.artifact_id = id; +} + +function createWorkbenchWorkflowReview() { + const workbenchActivityReview = createActivityModelReview( + WORKBENCH_ACTIVITY, + ); + const workbenchSurfaceReview = recommendSurfaceTypes(WORKBENCH_ACTIVITY, { + activity_review: workbenchActivityReview, + }); + const review = reviewUiWorkflowCandidate( + WORKBENCH_ACTIVITY, + { + workflow: { + surface_name: "Service exception workspace", + topology: "workspace", + work_units: [ + "Inspect evidence", + "Choose action", + "Leave handoff", + ], + primary_actions: ["Reassign", "Hold", "Escalate"], + decision_points: ["Choose the next operational action."], + completion_state: "The next owner receives a reasoned handoff.", + }, + surface_set: [ + { + name: "Service exception workspace", + purpose: + "Keep the selected exception, evidence, decision, and handoff together.", + sections: [ + "Work queue", + "Detail workspace", + "Evidence", + "Handoff", + ], + controls: [ + "Select exception", + "Choose action", + "Complete handoff", + ], + relationship_to_workflow: + "Supports repeated exception review.", + }, + ], + product_terms: ["Exception", "Evidence", "Handoff"], + handoff: { + next_owner: "dispatch coordinator", + reason: "The exception needs the selected operational action.", + next_action: "Complete the handoff.", + }, + diagnostics: { + implementation_terms: [], + reveal_contexts: ["debugging", "auditing"], + }, + }, + { + activity_review: workbenchActivityReview, + surface_review: workbenchSurfaceReview, + }, + ); + + assert.equal(review.review_status, "ready_for_review"); + assert.equal(review.surface_type, "workbench"); + return review; +} + +function completeExternalDesignSystemAdapter() { + return { + design_system_name: "External UI", + design_system_package: "@example/ui", + token_guidance: { + token_families: ["color"], + css_custom_properties: [ + { + name: "--external-surface", + role: "surface", + family: "color", + value: "#ffffff", + usage: "External UI surfaces", + }, + ], + }, + font_guidance: { + font_roles: { + body: { + stack: "system-ui", + usage: "External UI body typography", + }, + }, + }, + icon_guidance: { + icon_roles: ["status"], + icon_catalog: { + source: "external_design_system", + library: "example-icons", + package: "@example/icons", + version: "1.0.0", + icon_count: 1, + license: "MIT", + notice: "Repo-approved external icon adapter.", + mcp_tools: [], + }, + }, + components: ["Button"], + }; +} + +function disguiseExternalDesignAuthority(implementationContract) { + implementationContract.design_system_source = { + ...implementationContract.design_system_source, + mode: "judgmentkit_default", + id: "external-ui.source-v1", + name: "External UI", + package: "@example/ui", + definition_point: "caller_serialized_contract", + token_prefixes: ["--external-"], + renderer_components: ["ExternalButton"], + }; + implementationContract.visual_token_adapter = { + ...implementationContract.visual_token_adapter, + css_custom_properties: [ + { + name: "--external-surface", + role: "surface", + family: "color", + value: "#ffffff", + usage: "External UI surfaces", + }, + ], + }; + implementationContract.default_ai_native_design_system = { + ...implementationContract.default_ai_native_design_system, + component_contracts: [ + { + ...implementationContract.default_ai_native_design_system + .component_contracts[0], + id: "ExternalButton", + label: "External button", + purpose: "Supply external chrome authority", + }, + ], + }; +} + +function reviewCandidate(candidate) { + return reviewUiWorkflowCandidate(ARTIFACT_ACTIVITY, candidate, { + activity_review: activityReview, + profile_id: "artifact-inspector-ui", + surface_review: surfaceReview, + }); +} + +function createAutomationWorkflowReview() { + const automationActivity = `${ARTIFACT_ACTIVITY} + A declared automation performs automatic resolution for an exact match and + returns every uncertain result to human review. + `; + const automationActivityReview = createActivityModelReview( + automationActivity, + ); + const automationSurfaceReview = recommendSurfaceTypes(automationActivity, { + activity_review: automationActivityReview, + }); + const automationCandidate = createCandidate(); + automationCandidate.workflow.surface_name = "Automated accessibility review"; + automationCandidate.workflow.state_groups.automation = structuredClone( + model.state_groups.automation, + ); + automationCandidate.handoff.next_action = + "Review the automated-resolution receipt."; + + return reviewUiWorkflowCandidate( + automationActivity, + automationCandidate, + { + activity_review: automationActivityReview, + profile_id: "artifact-inspector-ui", + surface_review: automationSurfaceReview, + }, + ); +} + +const validWorkflowReview = reviewCandidate(createCandidate()); + +{ + const automationWorkflowReview = createAutomationWorkflowReview(); + assert.equal(automationWorkflowReview.review_status, "ready_for_review"); + assert.deepEqual( + automationWorkflowReview.guardrails.artifact_inspector.active_state_groups, + ["core", "automation"], + ); + + const mixedWorkflowReview = structuredClone(validWorkflowReview); + mixedWorkflowReview.source = structuredClone( + automationWorkflowReview.source, + ); + mixedWorkflowReview.candidate.workflow.state_groups.automation = + structuredClone(model.state_groups.automation); + mixedWorkflowReview.review.evidence.artifact_inspector + .active_state_groups = ["core", "automation"]; + mixedWorkflowReview.guardrails.artifact_inspector.active_state_groups = [ + "core", + "automation", + ]; + assert.throws( + () => createUiGenerationHandoff(mixedWorkflowReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.ok( + error.details.failures.some( + (failure) => + failure.field === + "source.artifact_inspector_review_integrity", + ), + ); + return true; + }, + "A seal from a different valid review cannot authorize a mixed activity, workflow, surface, or authority packet.", + ); + + const coreHandoff = createUiGenerationHandoff(validWorkflowReview); + const automationHandoff = createUiGenerationHandoff( + automationWorkflowReview, + ); + const mixedHandoff = structuredClone(coreHandoff); + mixedHandoff.source = structuredClone(automationHandoff.source); + mixedHandoff.workflow.state_groups.automation = structuredClone( + model.state_groups.automation, + ); + mixedHandoff.implementation_contract.artifact_inspector + .active_state_groups = ["core", "automation"]; + mixedHandoff.artifact_inspector.registry.active_state_groups = [ + "core", + "automation", + ]; + mixedHandoff.artifact_inspector.state_groups.automation = structuredClone( + model.state_groups.automation, + ); + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: mixedHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "frontend_context_blocked"); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "A handoff seal from a different valid packet cannot authorize mixed workflow and authority fields.", + ); + + const coreFrontendContext = createFrontendGenerationContext({ + ui_generation_handoff: JSON.parse(JSON.stringify(coreHandoff)), + }); + const automationFrontendContext = createFrontendGenerationContext({ + ui_generation_handoff: JSON.parse(JSON.stringify(automationHandoff)), + }); + assert.notEqual( + coreHandoff.source.artifact_inspector_boundary_integrity, + coreFrontendContext.source.artifact_inspector_boundary_integrity, + "The frontend boundary must issue a stage-specific seal instead of copying the handoff seal.", + ); + assert.equal( + createFrontendImplementationSkillContext({ + frontend_generation_context: JSON.parse( + JSON.stringify(coreFrontendContext), + ), + target_client: "codex", + }).skill_context_status, + "ready", + "JSON round trips must preserve a legitimate frontend packet and its opaque seal.", + ); + assert.equal( + createFrontendImplementationSkillContext({ + frontend_generation_context: automationFrontendContext, + target_client: "codex", + }).skill_context_status, + "ready", + "A complete legitimate automation packet remains accepted.", + ); + + const mixedFrontendContext = structuredClone(coreFrontendContext); + mixedFrontendContext.source = structuredClone( + automationFrontendContext.source, + ); + mixedFrontendContext.workflow.state_groups.automation = structuredClone( + model.state_groups.automation, + ); + mixedFrontendContext.implementation_contract.artifact_inspector + .active_state_groups = ["core", "automation"]; + mixedFrontendContext.implementation_guidance.artifact_inspector + .active_state_groups = ["core", "automation"]; + mixedFrontendContext.implementation_guidance.artifact_inspector + .registry.active_state_groups = ["core", "automation"]; + mixedFrontendContext.implementation_guidance.artifact_inspector + .state_groups.automation = structuredClone(model.state_groups.automation); + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: mixedFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "A frontend seal from a different valid packet cannot authorize mixed workflow and guidance fields.", + ); +} + +{ + const contradictoryReview = structuredClone(validWorkflowReview); + contradictoryReview.candidate.workflow.topology = "workspace"; + + assert.throws( + () => createUiGenerationHandoff(contradictoryReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal(error.details.field, "workflow.topology"); + assert.equal(error.details.topology, "workspace"); + assert.equal( + error.details.topology_contract_kind, + "artifact_centered", + ); + assert.equal( + error.details.diagnostic_code, + "JK_ARTIFACT_INSPECTOR_TOPOLOGY_KIND_INVALID", + ); + return true; + }, + "Handoff must reject contradictory serialized topology representations.", + ); + + const objectOnlyTopologyReview = structuredClone(validWorkflowReview); + objectOnlyTopologyReview.candidate.workflow.topology = structuredClone( + objectOnlyTopologyReview.candidate.workflow.topology_contract, + ); + delete objectOnlyTopologyReview.candidate.workflow.topology_contract; + assert.throws( + () => createUiGenerationHandoff(objectOnlyTopologyReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal( + error.details.field, + "artifact_inspector.boundary_consistency", + ); + assert.equal(error.details.observed.topology, "artifact_centered"); + assert.equal(error.details.observed.topology_representation, "object"); + assert.equal(error.details.observed.topology_contract_kind, null); + assert.equal(error.details.observed.canonical_topology_shape, false); + return true; + }, + "Handoff must reject an object-only Artifact Inspector topology that its serializer would drop.", + ); + + const missingArtifactReview = structuredClone(validWorkflowReview); + delete missingArtifactReview.candidate.workflow.artifact; + assert.throws( + () => createUiGenerationHandoff(missingArtifactReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal(error.details.field, "workflow.artifact"); + assert.equal( + error.details.diagnostic_code, + "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + ); + assert.equal( + error.details.reason, + "artifact_inspector_required_structure_invalid", + ); + return true; + }, + "Handoff must reject a ready packet whose reviewed artifact identity was removed after review.", + ); + + const contradictoryProfileReview = structuredClone(validWorkflowReview); + contradictoryProfileReview.guidance_profile.profile_id = + "operator-review-ui"; + assert.throws( + () => createUiGenerationHandoff(contradictoryProfileReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal( + error.details.field, + "artifact_inspector.boundary_consistency", + ); + assert.deepEqual(error.details.observed.workflow_profile_ids, [ + "operator-review-ui", + ]); + assert.equal( + error.details.expected.workflow_profile, + "artifact-inspector-ui", + ); + return true; + }, + "Handoff must reject a conflicting profile id on an otherwise canonical Artifact Inspector review.", + ); + + for (const [label, mutate] of [ + [ + "nested activity review status", + (review) => { + review.activity_review.review_status = "needs_source_context"; + }, + ], + [ + "retained activity guardrail status", + (review) => { + review.guardrails.activity_review_status = "needs_source_context"; + }, + ], + [ + "reviewed Artifact Inspector validity", + (review) => { + review.review.evidence.artifact_inspector.valid = false; + }, + ], + [ + "guardrail Artifact Inspector validity", + (review) => { + review.guardrails.artifact_inspector.valid = false; + }, + ], + ]) { + const tamperedReview = structuredClone(validWorkflowReview); + mutate(tamperedReview); + assert.throws( + () => createUiGenerationHandoff(tamperedReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal(error.details.reason, "review_packet_no_longer_ready"); + return true; + }, + `${label} cannot be relabeled into a ready handoff.`, + ); + } + + const erasedActivityReview = structuredClone(validWorkflowReview); + erasedActivityReview.activity_review.candidate.activity_model = { + activity: "", + participants: [], + objective: "", + outcomes: [], + domain_vocabulary: [], + }; + erasedActivityReview.activity_review.candidate.interaction_contract = { + primary_decision: "", + next_actions: [], + completion: "", + make_easy: [], + }; + assert.throws( + () => createUiGenerationHandoff(erasedActivityReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal(error.details.reason, "review_packet_no_longer_ready"); + const failure = error.details.failures.find( + (entry) => entry.field === "activity_review.candidate", + ); + assert.ok(failure); + assert.equal(failure.observed.activity, true); + assert.equal(failure.observed.primary_decision, true); + assert.equal(failure.observed.completion_or_outcome, true); + return true; + }, + "Erasing the nested reviewed activity must not produce a ready handoff.", + ); + + const renamedPrimaryArtifactReview = structuredClone(validWorkflowReview); + renamePrimaryArtifact(renamedPrimaryArtifactReview.candidate.workflow); + assert.throws( + () => createUiGenerationHandoff(renamedPrimaryArtifactReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal( + error.details.field, + "workflow.topology_contract.primary_object_id", + ); + assert.equal(error.details.expected, "artifact"); + assert.equal(error.details.observed, "renamed_artifact"); + return true; + }, + "A caller cannot coherently rename the canonical primary artifact after review.", + ); + + const workbenchGuidanceReview = structuredClone(validWorkflowReview); + workbenchGuidanceReview.surface_guidance.interaction_implications = { + primary_structure: "Workbench queue-detail", + }; + workbenchGuidanceReview.surface_guidance.disclosure_implications = { + product_ui_rule: "Expose queue machinery", + }; + workbenchGuidanceReview.surface_guidance.frontend_posture = { + navigation_shape: "queue-detail", + }; + assert.throws( + () => createUiGenerationHandoff(workbenchGuidanceReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.ok( + error.details.failures.some( + (failure) => + failure.field === + "source.artifact_inspector_review_integrity", + ), + ); + return true; + }, + "Caller-replaced surface guidance cannot be canonicalized under a seal issued for different reviewed guidance.", + ); + + const jointlyBroadenedStateReview = structuredClone(validWorkflowReview); + jointlyBroadenedStateReview.candidate.workflow.state_groups.automation = + structuredClone(model.state_groups.automation); + jointlyBroadenedStateReview.review.evidence.artifact_inspector + .active_state_groups = ["core", "automation"]; + jointlyBroadenedStateReview.guardrails.artifact_inspector + .active_state_groups = ["core", "automation"]; + assert.throws( + () => createUiGenerationHandoff(jointlyBroadenedStateReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal(error.details.reason, "review_packet_no_longer_ready"); + assert.ok( + error.details.failures.some( + (failure) => + failure.field === + "guardrails.artifact_inspector.active_state_groups", + ), + ); + return true; + }, + "Mutating the workflow and both duplicated review arrays together must not activate a group absent from grounded activity evidence.", + ); + + const forgedReviewedSource = structuredClone(validWorkflowReview); + forgedReviewedSource.source.reviewed_activity_input += + " Automation uses exact match and automatic resolution."; + forgedReviewedSource.candidate.workflow.state_groups.automation = + structuredClone(model.state_groups.automation); + forgedReviewedSource.review.evidence.artifact_inspector + .active_state_groups = ["core", "automation"]; + forgedReviewedSource.guardrails.artifact_inspector.active_state_groups = [ + "core", + "automation", + ]; + assert.throws( + () => createUiGenerationHandoff(forgedReviewedSource), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal(error.details.reason, "review_packet_no_longer_ready"); + assert.ok( + error.details.failures.some( + (failure) => + failure.field === + "source.artifact_inspector_review_integrity", + ), + ); + return true; + }, + "A caller cannot rewrite both the reviewed source and its state ceiling.", + ); +} + +{ + const workbenchReview = createWorkbenchWorkflowReview(); + const artifactContract = createUiImplementationContract({ + surface_type: "artifact_inspector", + }).implementation_contract; + + assert.throws( + () => + createUiGenerationHandoff(workbenchReview, { + implementation_contract: artifactContract, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal( + error.details.field, + "artifact_inspector.boundary_consistency", + ); + assert.deepEqual(error.details.observed.surface_types, ["workbench"]); + assert.equal(error.details.observed.topology, "workspace"); + assert.equal(error.details.observed.authority_bundle_active, true); + return true; + }, + "Handoff must reject Artifact Inspector authority attached to a Workbench workflow.", + ); + + const workbenchHandoff = createUiGenerationHandoff(workbenchReview); + const legacyGuidanceReview = structuredClone(workbenchReview); + const legacyInteractionSentinel = { + primary_structure: "Legacy Workbench interaction sentinel", + }; + const legacyDisclosureSentinel = { + product_ui_rule: "Legacy Workbench disclosure sentinel", + }; + legacyGuidanceReview.surface_guidance.interaction_implications = + legacyInteractionSentinel; + legacyGuidanceReview.surface_guidance.disclosure_implications = + legacyDisclosureSentinel; + const legacyGuidanceHandoff = createUiGenerationHandoff( + legacyGuidanceReview, + ); + assert.deepEqual( + legacyGuidanceHandoff.surface_guidance.interaction_implications, + legacyInteractionSentinel, + ); + assert.deepEqual( + legacyGuidanceHandoff.surface_guidance.disclosure_implications, + legacyDisclosureSentinel, + ); + const legacyGuidanceFrontendContext = createFrontendGenerationContext({ + ui_generation_handoff: legacyGuidanceHandoff, + }); + assert.deepEqual( + legacyGuidanceFrontendContext.implementation_guidance + .interaction_implications, + legacyInteractionSentinel, + ); + assert.deepEqual( + legacyGuidanceFrontendContext.implementation_guidance + .disclosure_implications, + legacyDisclosureSentinel, + ); + const legacyGuidanceSkillContext = createFrontendImplementationSkillContext({ + frontend_generation_context: legacyGuidanceFrontendContext, + target_client: "codex", + }); + assert.deepEqual( + legacyGuidanceSkillContext.surface_type_guidance.interaction_implications, + legacyInteractionSentinel, + ); + assert.deepEqual( + legacyGuidanceSkillContext.surface_type_guidance.disclosure_implications, + legacyDisclosureSentinel, + ); + const authorityLeakingHandoff = structuredClone(workbenchHandoff); + authorityLeakingHandoff.implementation_contract = structuredClone( + artifactContract, + ); + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: authorityLeakingHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "frontend_context_blocked"); + assert.deepEqual(error.details.observed.surface_types, ["workbench"]); + assert.equal(error.details.observed.topology, "workspace"); + assert.equal(error.details.observed.authority_bundle_active, true); + return true; + }, + "Frontend generation must reject Artifact Inspector authority attached to serialized Workbench handoff.", + ); + + const workbenchFrontendContext = createFrontendGenerationContext({ + ui_generation_handoff: workbenchHandoff, + }); + const authorityLeakingFrontendContext = structuredClone( + workbenchFrontendContext, + ); + authorityLeakingFrontendContext.implementation_contract = structuredClone( + artifactContract, + ); + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: authorityLeakingFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.deepEqual(error.details.observed.surface_types, ["workbench"]); + assert.equal(error.details.observed.topology, "workspace"); + assert.equal(error.details.observed.authority_bundle_active, true); + return true; + }, + "Skill compilation must reject Artifact Inspector authority attached to serialized Workbench context.", + ); +} + +{ + const review = validWorkflowReview; + const artifactGuardrail = review.guardrails.artifact_inspector; + + assert.equal(review.review_status, "ready_for_review"); + assert.equal(review.source.reviewed_activity_input, ARTIFACT_ACTIVITY.trim()); + assert.equal( + typeof review.source.artifact_inspector_review_integrity, + "string", + ); + assert.equal(artifactGuardrail.selected, true); + assert.equal(artifactGuardrail.valid, true); + assert.deepEqual(artifactGuardrail.diagnostics, []); + assert.equal(artifactGuardrail.surface_type, "artifact_inspector"); + assert.equal(artifactGuardrail.workflow_profile, "artifact-inspector-ui"); + assert.equal(artifactGuardrail.topology_kind, "artifact_centered"); + + assert.equal(review.candidate.workflow.topology, "artifact_centered"); + assert.deepEqual( + review.candidate.workflow.topology_contract, + model.topology, + "The structured candidate topology must remain available beside the compatibility string.", + ); + assert.deepEqual( + review.candidate.workflow.work_units.map((entry) => entry.id), + [ + "orient", + "select_locus", + "inspect_context", + "preview", + "validate", + "complete", + "verify_result", + "recover", + ], + ); + assert.equal(review.candidate.workflow.artifact.id, "artifact"); + assert.equal( + review.candidate.workflow.target_model.artifact_id, + "artifact", + ); + assert.deepEqual( + review.candidate.workflow.target_model.target_kinds, + model.target_model.target_kinds, + ); + assert.deepEqual( + Object.keys(review.candidate.workflow.state_groups), + ["core"], + "Conditional state groups must remain omitted when the activity does not use them.", + ); +} + +{ + const topologyDerivedReview = reviewUiWorkflowCandidate( + ARTIFACT_ACTIVITY, + createCandidate(), + { activity_review: activityReview }, + ); + const handoff = createUiGenerationHandoff(topologyDerivedReview); + + assert.equal(topologyDerivedReview.review_status, "ready_for_review"); + assert.equal(topologyDerivedReview.surface_type, "artifact_inspector"); + assert.equal( + topologyDerivedReview.surface_guidance.recommended_surface_type, + "artifact_inspector", + ); + assert.equal( + topologyDerivedReview.surface_guidance.confidence, + "validated_workflow", + ); + assert.equal(handoff.surface_type, "artifact_inspector"); + assert.deepEqual( + handoff.implementation_contract.design_system_scopes, + model.design_system.scopes, + "Validated artifact topology must carry scoped authority even without caller-supplied surface evidence.", + ); + + const emptySurfaceReview = reviewUiWorkflowCandidate( + ARTIFACT_ACTIVITY, + createCandidate(), + { + activity_review: activityReview, + surface_review: {}, + }, + ); + assert.equal(emptySurfaceReview.review_status, "ready_for_review"); + assert.equal(emptySurfaceReview.surface_type, "artifact_inspector"); + assert.equal( + createUiGenerationHandoff(emptySurfaceReview).surface_type, + "artifact_inspector", + "An empty optional surface review must not suppress canonical topology-derived routing.", + ); + + const readyReviewWithoutSurfaceMetadata = structuredClone( + topologyDerivedReview, + ); + delete readyReviewWithoutSurfaceMetadata.surface_type; + delete readyReviewWithoutSurfaceMetadata.surface_guidance; + assert.throws( + () => createUiGenerationHandoff(readyReviewWithoutSurfaceMetadata), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.ok( + error.details.failures.some( + (failure) => + failure.field === + "source.artifact_inspector_review_integrity", + ), + ); + return true; + }, + "Handoff must reject a reviewed packet whose canonical surface metadata was removed after review.", + ); + + const internallyConflictingReview = structuredClone(topologyDerivedReview); + internallyConflictingReview.surface_guidance = { + ...internallyConflictingReview.surface_guidance, + recommended_surface_type: "workbench", + }; + assert.throws( + () => createUiGenerationHandoff(internallyConflictingReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal(error.details.surface_type, "artifact_inspector"); + assert.equal(error.details.surface_guidance_type, "workbench"); + return true; + }, + "Handoff must reconcile both reviewed surface fields before deriving authority.", + ); + + const conflictingHandoffReview = structuredClone(topologyDerivedReview); + conflictingHandoffReview.surface_type = "workbench"; + conflictingHandoffReview.surface_guidance = { + ...conflictingHandoffReview.surface_guidance, + recommended_surface_type: "workbench", + }; + + assert.throws( + () => createUiGenerationHandoff(conflictingHandoffReview), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.equal(error.details.expected_surface_type, "artifact_inspector"); + assert.equal(error.details.observed_surface_type, "workbench"); + assert.equal(error.details.workflow_topology, "artifact_centered"); + return true; + }, + "Handoff must defensively reject a conflicting surface on an artifact-centered reviewed workflow.", + ); + + assert.throws( + () => + createUiGenerationHandoff(topologyDerivedReview, { + implementation_contract: "not-an-object", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal(error.details.field, "implementation_contract"); + return true; + }, + "Malformed caller contract input must not remove the scoped authority bundle.", + ); + + const readyReviewWithDuplicateWorkUnit = structuredClone( + topologyDerivedReview, + ); + readyReviewWithDuplicateWorkUnit.candidate.workflow.work_units.push({ + ...structuredClone( + readyReviewWithDuplicateWorkUnit.candidate.workflow.work_units[0], + ), + participant_intent: "Orient to an unrelated secondary artifact.", + }); + assert.throws( + () => createUiGenerationHandoff(readyReviewWithDuplicateWorkUnit), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + assert.deepEqual(error.details.duplicate_work_unit_ids, ["orient"]); + return true; + }, + "A serialized ready review cannot add a divergent duplicate work-unit id before handoff.", + ); +} + +{ + const conflictingActivity = `${ARTIFACT_ACTIVITY} + The primary activity is freely creating and editing the artifact. + `; + const strippedActivityReview = structuredClone(activityReview); + delete strippedActivityReview.review.evidence.artifact_inspector; + delete strippedActivityReview.guardrails.artifact_inspector; + const review = reviewUiWorkflowCandidate( + conflictingActivity, + createCandidate(), + { + activity_review: strippedActivityReview, + profile_id: "artifact-inspector-ui", + }, + ); + const diagnostic = review.guardrails.artifact_inspector.diagnostics.find( + (entry) => + entry.code === "JK_ARTIFACT_INSPECTOR_KEYWORD_ROUTING_CONFLICT", + ); + + assert.equal(review.review_status, "needs_source_context"); + assert.equal(review.guardrails.artifact_inspector.valid, false); + assert.ok( + diagnostic, + "Grounded source evidence must restore a routing conflict stripped from supplied review metadata.", + ); + assert.equal(diagnostic.field, "artifact_inspector.routing"); + assert.equal(diagnostic.observed.activity_conflict, true); + assert.ok( + diagnostic.observed.matched_exclusion_evidence.includes( + "open_ended_creation_is_primary", + ), + ); +} + +{ + const legacyQueueActivity = ` + A support lead reviews refund cases in a shared queue during daily triage. + They decide whether each case should be approved, escalated to policy, or + returned for missing evidence. Completion is a clear case handoff with a + reason and next owner. + `; + const legacyActivityReview = createActivityModelReview(legacyQueueActivity); + const review = reviewUiWorkflowCandidate( + legacyQueueActivity, + createCandidate(), + { activity_review: legacyActivityReview }, + ); + const diagnostic = review.guardrails.artifact_inspector.diagnostics.find( + (entry) => + entry.code === "JK_ARTIFACT_INSPECTOR_KEYWORD_ROUTING_CONFLICT", + ); + + assert.equal(legacyActivityReview.review_status, "ready_for_review"); + assert.equal(review.review_status, "needs_source_context"); + assert.equal(review.guardrails.artifact_inspector.valid, false); + assert.equal(diagnostic.observed.mandatory_evidence_satisfied, false); + assert.ok( + diagnostic.observed.missing_mandatory_evidence.includes( + "rendered_artifact_is_primary", + ), + ); +} + +{ + const genericCandidate = createCandidate(); + genericCandidate.workflow.topology = "workspace"; + const review = reviewUiWorkflowCandidate( + ARTIFACT_ACTIVITY, + genericCandidate, + { activity_review: activityReview }, + ); + + assert.equal(review.review_status, "needs_source_context"); + assert.equal(review.guardrails.artifact_inspector.selected, true); + assert.equal(review.guardrails.artifact_inspector.valid, false); + assert.ok( + review.guardrails.artifact_inspector.diagnostics.some( + (entry) => + entry.code === "JK_ARTIFACT_INSPECTOR_TOPOLOGY_CONTRACT_MISSING" || + entry.code === "JK_ARTIFACT_INSPECTOR_TOPOLOGY_KIND_INVALID", + ), + "Grounded Artifact Inspector activity must require artifact topology and scoped authority.", + ); + assert.throws( + () => createUiGenerationHandoff(review), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "handoff_blocked"); + return true; + }, + ); +} + +{ + const handoff = createUiGenerationHandoff(validWorkflowReview); + const frontendContext = createFrontendGenerationContext({ + ui_generation_handoff: handoff, + frontend_context: { + target_runtime: "browser", + ui_library: "none", + }, + verification: { + commands: ["npm test"], + browser_checks: ["desktop artifact inspection", "narrow artifact inspection"], + states_to_verify: ["artifact ready", "locus focused or selected"], + }, + }); + const skillContext = createFrontendImplementationSkillContext({ + frontend_generation_context: frontendContext, + target_client: "codex", + }); + const renamedPrimaryArtifactHandoff = structuredClone(handoff); + renamePrimaryArtifact(renamedPrimaryArtifactHandoff.workflow); + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: renamedPrimaryArtifactHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "frontend_context_blocked"); + assert.equal( + error.details.field, + "workflow.topology_contract.primary_object_id", + ); + return true; + }, + "Frontend generation must reject a coherently renamed primary artifact.", + ); + const renamedPrimaryArtifactFrontendContext = structuredClone( + frontendContext, + ); + renamePrimaryArtifact(renamedPrimaryArtifactFrontendContext.workflow); + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: renamedPrimaryArtifactFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal( + error.details.field, + "workflow.topology_contract.primary_object_id", + ); + return true; + }, + "Skill compilation must reject a coherently renamed primary artifact.", + ); + + const workbenchGuidanceHandoff = structuredClone(handoff); + workbenchGuidanceHandoff.surface_guidance.interaction_implications = { + primary_structure: "Workbench queue-detail", + }; + workbenchGuidanceHandoff.surface_guidance.disclosure_implications = { + product_ui_rule: "Expose queue machinery", + }; + workbenchGuidanceHandoff.surface_guidance.frontend_posture = { + navigation_shape: "queue-detail", + }; + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: workbenchGuidanceHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "frontend_context_blocked"); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "Frontend generation cannot canonicalize caller-replaced surface guidance under a seal issued for different handoff guidance.", + ); + + const workbenchGuidanceFrontendContext = structuredClone(frontendContext); + workbenchGuidanceFrontendContext.implementation_guidance + .interaction_implications = { + primary_structure: "Workbench queue-detail", + }; + workbenchGuidanceFrontendContext.implementation_guidance + .disclosure_implications = { + product_ui_rule: "Expose queue machinery", + }; + workbenchGuidanceFrontendContext.implementation_guidance.frontend_posture = { + navigation_shape: "queue-detail", + }; + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: workbenchGuidanceFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "Skill compilation cannot canonicalize caller-replaced guidance under a seal issued for different frontend guidance.", + ); + const contradictoryHandoff = structuredClone(handoff); + contradictoryHandoff.workflow.topology = "workspace"; + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: contradictoryHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "frontend_context_blocked"); + assert.equal(error.details.field, "workflow.topology"); + assert.equal(error.details.topology, "workspace"); + assert.equal( + error.details.topology_contract_kind, + "artifact_centered", + ); + return true; + }, + "Frontend generation must reject contradictory serialized topology representations.", + ); + + const objectOnlyTopologyHandoff = structuredClone(handoff); + objectOnlyTopologyHandoff.workflow.topology = structuredClone( + objectOnlyTopologyHandoff.workflow.topology_contract, + ); + delete objectOnlyTopologyHandoff.workflow.topology_contract; + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: objectOnlyTopologyHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "frontend_context_blocked"); + assert.equal(error.details.observed.topology, "artifact_centered"); + assert.equal(error.details.observed.topology_representation, "object"); + assert.equal(error.details.observed.topology_contract_kind, null); + assert.equal(error.details.observed.canonical_topology_shape, false); + return true; + }, + "Frontend generation must reject object-only Artifact Inspector topology packets.", + ); + + const missingTargetModelHandoff = structuredClone(handoff); + delete missingTargetModelHandoff.workflow.target_model; + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: missingTargetModelHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "frontend_context_blocked"); + assert.equal(error.details.field, "workflow.target_model"); + assert.equal( + error.details.diagnostic_code, + "JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING", + ); + return true; + }, + "Frontend generation must reject an Artifact Inspector handoff without its locus model.", + ); + + const contradictoryFrontendContext = structuredClone(frontendContext); + contradictoryFrontendContext.workflow.topology = "workspace"; + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: contradictoryFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal(error.details.field, "workflow.topology"); + assert.equal(error.details.topology, "workspace"); + assert.equal( + error.details.topology_contract_kind, + "artifact_centered", + ); + return true; + }, + "Skill compilation must reject contradictory serialized topology representations.", + ); + + const objectOnlyTopologyFrontendContext = structuredClone(frontendContext); + objectOnlyTopologyFrontendContext.workflow.topology = structuredClone( + objectOnlyTopologyFrontendContext.workflow.topology_contract, + ); + delete objectOnlyTopologyFrontendContext.workflow.topology_contract; + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: objectOnlyTopologyFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal(error.details.observed.topology, "artifact_centered"); + assert.equal(error.details.observed.topology_representation, "object"); + assert.equal(error.details.observed.topology_contract_kind, null); + assert.equal(error.details.observed.canonical_topology_shape, false); + return true; + }, + "Skill compilation must reject object-only Artifact Inspector topology packets.", + ); + + const missingStateGroupsFrontendContext = structuredClone(frontendContext); + delete missingStateGroupsFrontendContext.workflow.state_groups; + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: missingStateGroupsFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal(error.details.field, "workflow.state_groups"); + assert.equal( + error.details.diagnostic_code, + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + ); + return true; + }, + "Skill compilation must reject an Artifact Inspector context without its active states.", + ); + const tamperedHandoffGuidance = structuredClone(handoff); + tamperedHandoffGuidance.artifact_inspector.registry + .external_artifact_review_status = "pass"; + tamperedHandoffGuidance.artifact_inspector.design_system_scopes = []; + tamperedHandoffGuidance.artifact_inspector.boundary_contracts = []; + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: tamperedHandoffGuidance, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "frontend_context_blocked"); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "Frontend generation must reject a caller-modified authority summary instead of accepting it under a seal for different handoff authority.", + ); + + assert.equal(handoff.handoff_status, "ready_for_generation"); + assert.equal(handoff.surface_type, "artifact_inspector"); + assert.equal(handoff.workflow.topology, "artifact_centered"); + assert.deepEqual(handoff.workflow.topology_contract, model.topology); + assert.deepEqual( + handoff.workflow.work_units.map((entry) => entry.id), + model.work_units.map((entry) => entry.id), + ); + assert.deepEqual(handoff.workflow.artifact, { + id: "artifact", + boundary: "Rendered interface under audit", + }); + assert.equal(handoff.workflow.target_model.artifact_id, "artifact"); + assert.deepEqual(Object.keys(handoff.workflow.state_groups), ["core"]); + assert.deepEqual( + handoff.implementation_contract.artifact_inspector.active_state_groups, + ["core"], + "Conditional state groups must not activate from the registry alone.", + ); + assert.deepEqual( + handoff.implementation_contract.design_system_scopes, + model.design_system.scopes, + "A default implementation contract must auto-activate scoped authority for the selected surface.", + ); + assert.deepEqual( + handoff.implementation_contract.boundary_contracts, + model.design_system.boundary_contracts, + ); + assert.equal( + handoff.implementation_contract.artifact_inspector + .external_artifact_review_status, + "external_not_reviewed", + ); + assert.deepEqual( + handoff.artifact_inspector.design_system_scopes, + model.design_system.scopes, + ); + assert.deepEqual( + handoff.artifact_inspector.boundary_contracts, + model.design_system.boundary_contracts, + ); + + assert.equal( + frontendContext.frontend_context_status, + "ready_for_frontend_implementation", + ); + assert.equal(frontendContext.surface_type, "artifact_inspector"); + assert.equal( + frontendContext.selected_surface_profile.id, + "judgmentkit.artifact-inspector.v1", + ); + assert.ok( + frontendContext.source.supported_surface_profiles.includes( + "judgmentkit.artifact-inspector.v1", + ), + "Omitting caller capabilities must use the built-in supported profile registry.", + ); + assert.deepEqual(frontendContext.workflow.topology_contract, model.topology); + assert.deepEqual( + frontendContext.workflow.work_units, + handoff.workflow.work_units, + ); + assert.deepEqual( + frontendContext.implementation_guidance.artifact_inspector.artifact, + handoff.workflow.artifact, + ); + assert.deepEqual( + frontendContext.implementation_guidance.artifact_inspector.target_model, + handoff.workflow.target_model, + ); + assert.deepEqual( + frontendContext.implementation_guidance.artifact_inspector.state_groups, + handoff.workflow.state_groups, + ); + assert.deepEqual( + frontendContext.implementation_guidance.artifact_inspector + .active_state_groups, + ["core"], + ); + assert.deepEqual( + frontendContext.implementation_guidance.artifact_inspector + .design_system_scopes, + model.design_system.scopes, + ); + assert.deepEqual( + frontendContext.implementation_guidance.artifact_inspector + .boundary_contracts, + model.design_system.boundary_contracts, + ); + assert.equal( + frontendContext.guardrails.artifact_inspector_authority + .external_artifact_review_status, + "external_not_reviewed", + ); + assert.equal( + frontendContext.guardrails.artifact_inspector_authority + .trusted_runtime_evidence_required, + true, + ); + + assert.equal(skillContext.skill_context_status, "ready"); + assert.equal( + skillContext.selected_surface_profile.id, + "judgmentkit.artifact-inspector.v1", + ); + assert.equal( + skillContext.surface_type_guidance.workflow_topology, + "artifact_centered", + ); + assert.deepEqual( + skillContext.surface_type_guidance.topology_contract, + model.topology, + ); + assert.deepEqual( + skillContext.surface_type_guidance.work_units, + handoff.workflow.work_units, + ); + assert.deepEqual( + skillContext.surface_type_guidance.artifact, + handoff.workflow.artifact, + ); + assert.deepEqual( + skillContext.surface_type_guidance.target_model, + handoff.workflow.target_model, + ); + assert.deepEqual( + skillContext.surface_type_guidance.state_groups, + handoff.workflow.state_groups, + ); + assert.deepEqual( + skillContext.artifact_inspector.artifact, + handoff.workflow.artifact, + ); + assert.deepEqual( + skillContext.artifact_inspector.target_model, + handoff.workflow.target_model, + ); + assert.deepEqual( + skillContext.artifact_inspector.state_groups, + handoff.workflow.state_groups, + ); + assert.deepEqual( + skillContext.artifact_inspector.active_state_groups, + ["core"], + ); + assert.deepEqual( + skillContext.artifact_inspector.design_system_scopes, + model.design_system.scopes, + ); + assert.deepEqual( + skillContext.artifact_inspector.boundary_contracts, + model.design_system.boundary_contracts, + ); + assert.equal( + skillContext.artifact_inspector.external_artifact_review_status, + "external_not_reviewed", + ); + assert.ok( + skillContext.instruction_markdown.includes("external_not_reviewed"), + ); + assert.ok( + skillContext.instruction_markdown.includes( + "deferred interactive attestation", + ), + ); + assert.ok( + skillContext.instruction_markdown.includes( + "artifact persistent; supporting context revealed from the active locus", + ), + "Skill serialization must consume the canonical singular navigation_shape key.", + ); + assert.ok( + skillContext.instruction_markdown.includes( + "Keep the artifact central and persistent", + ), + "Skill serialization must consume responsive.wide.", + ); + assert.ok( + skillContext.instruction_markdown.includes( + "Keep the artifact primary, move support into a temporary edge affordance", + ), + "Skill serialization must consume responsive.narrow.", + ); + assert.ok( + skillContext.instruction_markdown.includes("artifact internal semantics and controls"), + "Skill serialization must consume external_artifact_authority_owns.", + ); + assert.ok( + skillContext.verification_checklist.some((entry) => + entry.includes("deferred attestation requirements"), + ), + ); + + const omittedArtifactGuidanceContext = structuredClone(frontendContext); + delete omittedArtifactGuidanceContext.implementation_guidance + .artifact_inspector; + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: omittedArtifactGuidanceContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "Skill compilation must reject an authority-guidance omission under a seal for the complete frontend packet.", + ); + + const tamperedArtifactGuidanceContext = structuredClone(frontendContext); + tamperedArtifactGuidanceContext.implementation_guidance.artifact_inspector + .design_system_scopes = [ + structuredClone( + model.design_system.scopes.find( + (entry) => entry.scope_id === "primary_artifact", + ), + ), + ]; + tamperedArtifactGuidanceContext.implementation_guidance.artifact_inspector + .boundary_contracts = []; + tamperedArtifactGuidanceContext.implementation_guidance.artifact_inspector + .external_artifact_review_status = "pass"; + tamperedArtifactGuidanceContext.guardrails.artifact_inspector_authority + .external_artifact_review_status = "pass"; + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: tamperedArtifactGuidanceContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "Skill compilation must reject caller-modified authority guidance instead of reconstructing it under a seal for different content.", + ); + + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: frontendContext, + design_system_adapter: completeExternalDesignSystemAdapter(), + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal(error.details.field, "design_system_adapter"); + assert.deepEqual(error.details.judgmentkit_owned_scopes, [ + "inspector_chrome", + "inspection_overlay", + ]); + assert.equal(error.details.external_artifact_scope, "primary_artifact"); + return true; + }, + "A whole-context frontend adapter must not replace JudgmentKit authority inside Artifact Inspector.", + ); + + const serializedExternalHandoff = structuredClone(handoff); + serializedExternalHandoff.implementation_contract.design_system_source = { + ...serializedExternalHandoff.implementation_contract.design_system_source, + mode: "external_design_system", + name: "External UI", + package: "@example/ui", + }; + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: serializedExternalHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal(error.details.field, "design_system_source.mode"); + assert.equal(error.details.observed, "external_design_system"); + return true; + }, + "Serialized external authority must not replace Artifact Inspector chrome authority at the frontend-context boundary.", + ); + + const disguisedExternalHandoff = structuredClone(handoff); + disguiseExternalDesignAuthority( + disguisedExternalHandoff.implementation_contract, + ); + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: disguisedExternalHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "frontend_context_blocked"); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "Relabeling external authority as judgmentkit_default must invalidate the sealed handoff instead of preserving or canonicalizing caller-owned authority.", + ); + + const disguisedExternalContract = structuredClone(contract); + disguiseExternalDesignAuthority( + disguisedExternalContract.implementation_contract, + ); + const canonicalizedCustomContractHandoff = createUiGenerationHandoff( + validWorkflowReview, + { contract: disguisedExternalContract }, + ); + assert.deepEqual( + canonicalizedCustomContractHandoff.implementation_contract + .design_system_source, + handoff.implementation_contract.design_system_source, + ); + assert.deepEqual( + canonicalizedCustomContractHandoff.implementation_contract + .visual_token_adapter, + handoff.implementation_contract.visual_token_adapter, + ); + assert.deepEqual( + canonicalizedCustomContractHandoff.implementation_contract + .default_ai_native_design_system, + handoff.implementation_contract.default_ai_native_design_system, + "A caller-supplied activity contract must not redefine JudgmentKit-owned Artifact Inspector design authority.", + ); + + const canonicalizedCustomContractFrontend = + createFrontendGenerationContext({ + ui_generation_handoff: handoff, + contract: disguisedExternalContract, + }); + assert.deepEqual( + canonicalizedCustomContractFrontend.implementation_contract + .design_system_source, + handoff.implementation_contract.design_system_source, + ); + assert.deepEqual( + canonicalizedCustomContractFrontend.implementation_contract + .visual_token_adapter, + handoff.implementation_contract.visual_token_adapter, + ); + assert.equal( + canonicalizedCustomContractFrontend.implementation_guidance + .component_contracts.some((entry) => entry.id === "ExternalButton"), + false, + ); + + const relabeledArtifactHandoff = structuredClone( + serializedExternalHandoff, + ); + relabeledArtifactHandoff.surface_type = "workbench"; + relabeledArtifactHandoff.surface_guidance.recommended_surface_type = + "workbench"; + delete relabeledArtifactHandoff.implementation_contract + .design_system_scopes; + delete relabeledArtifactHandoff.implementation_contract.boundary_contracts; + delete relabeledArtifactHandoff.implementation_contract.artifact_inspector; + delete relabeledArtifactHandoff.artifact_inspector; + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: relabeledArtifactHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.details.surface_type_candidates[ + "ui_generation_handoff.workflow.topology" + ], + "artifact_inspector", + ); + return true; + }, + "Artifact-centered serialized handoffs cannot be relabeled to shed scoped authority.", + ); + + const serializedExternalFrontendContext = structuredClone(frontendContext); + serializedExternalFrontendContext.implementation_contract.design_system_source = { + ...serializedExternalFrontendContext.implementation_contract + .design_system_source, + mode: "external_design_system", + name: "External UI", + package: "@example/ui", + }; + serializedExternalFrontendContext.implementation_guidance.design_system_source = + structuredClone( + serializedExternalFrontendContext.implementation_contract + .design_system_source, + ); + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: serializedExternalFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal(error.details.field, "design_system_source.mode"); + assert.equal(error.details.observed, "external_design_system"); + return true; + }, + "Serialized frontend authority must not bypass the inline adapter guard.", + ); + + const disguisedExternalFrontendContext = structuredClone(frontendContext); + disguiseExternalDesignAuthority( + disguisedExternalFrontendContext.implementation_contract, + ); + disguisedExternalFrontendContext.implementation_guidance + .design_system_source = structuredClone( + disguisedExternalFrontendContext.implementation_contract + .design_system_source, + ); + disguisedExternalFrontendContext.implementation_guidance + .component_contracts = structuredClone( + disguisedExternalFrontendContext.implementation_contract + .default_ai_native_design_system.component_contracts, + ); + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: disguisedExternalFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "Skill compilation must reject disguised external authority under a seal for different frontend authority.", + ); + + const relabeledArtifactFrontendContext = structuredClone( + serializedExternalFrontendContext, + ); + relabeledArtifactFrontendContext.surface_type = "workbench"; + relabeledArtifactFrontendContext.surface_guidance.recommended_surface_type = + "workbench"; + relabeledArtifactFrontendContext.implementation_guidance.surface_type = + "workbench"; + delete relabeledArtifactFrontendContext.implementation_contract + .design_system_scopes; + delete relabeledArtifactFrontendContext.implementation_contract + .boundary_contracts; + delete relabeledArtifactFrontendContext.implementation_contract + .artifact_inspector; + delete relabeledArtifactFrontendContext.implementation_guidance + .artifact_inspector; + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: relabeledArtifactFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal( + error.details.expected.surface_type, + "artifact_inspector", + ); + assert.deepEqual(error.details.observed.surface_types, ["workbench"]); + assert.equal(error.details.observed.topology, "artifact_centered"); + assert.equal(error.details.observed.authority_bundle_active, false); + return true; + }, + "Artifact-centered serialized frontend contexts cannot be relabeled to shed scoped authority.", + ); + + const broadenedStateHandoff = structuredClone(handoff); + broadenedStateHandoff.activity_model.objective += + " Automatic resolution for exact matches."; + broadenedStateHandoff.workflow.state_groups.automation = structuredClone( + model.state_groups.automation, + ); + broadenedStateHandoff.implementation_contract.artifact_inspector + .active_state_groups = ["core", "automation"]; + broadenedStateHandoff.artifact_inspector.registry.active_state_groups = [ + "core", + "automation", + ]; + broadenedStateHandoff.artifact_inspector.state_groups.automation = + structuredClone(model.state_groups.automation); + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: broadenedStateHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "frontend_context_blocked", + ); + assert.equal( + error.details.diagnostic_code, + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + ); + assert.deepEqual(error.details.expected, ["core"]); + return true; + }, + "Serialized handoff metadata must not broaden reviewed Artifact Inspector state groups.", + ); + + const forgedStateHandoff = structuredClone(handoff); + forgedStateHandoff.source.reviewed_activity_input += + " Automation uses exact match and automatic resolution."; + forgedStateHandoff.source.reviewed_active_state_groups = [ + "core", + "automation", + ]; + forgedStateHandoff.workflow.state_groups.automation = structuredClone( + model.state_groups.automation, + ); + forgedStateHandoff.implementation_contract.artifact_inspector + .active_state_groups = ["core", "automation"]; + forgedStateHandoff.artifact_inspector.registry.active_state_groups = [ + "core", + "automation", + ]; + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: forgedStateHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "frontend_context_blocked"); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "Frontend generation must reject a jointly forged reviewed source and state ceiling.", + ); + + const broadenedStateFrontendContext = structuredClone(frontendContext); + broadenedStateFrontendContext.activity_model.objective += + " Automatic resolution for exact matches."; + broadenedStateFrontendContext.workflow.state_groups.automation = + structuredClone(model.state_groups.automation); + broadenedStateFrontendContext.implementation_contract.artifact_inspector + .active_state_groups = ["core", "automation"]; + broadenedStateFrontendContext.implementation_guidance.artifact_inspector + .active_state_groups = ["core", "automation"]; + broadenedStateFrontendContext.implementation_guidance.artifact_inspector + .registry.active_state_groups = ["core", "automation"]; + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: broadenedStateFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal( + error.details.diagnostic_code, + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + ); + assert.deepEqual(error.details.expected, ["core"]); + return true; + }, + "Serialized frontend metadata must not broaden reviewed Artifact Inspector state groups.", + ); + + const forgedStateFrontendContext = structuredClone(frontendContext); + forgedStateFrontendContext.source.reviewed_activity_input += + " Automation uses exact match and automatic resolution."; + forgedStateFrontendContext.source.reviewed_active_state_groups = [ + "core", + "automation", + ]; + forgedStateFrontendContext.workflow.state_groups.automation = + structuredClone(model.state_groups.automation); + forgedStateFrontendContext.implementation_contract.artifact_inspector + .active_state_groups = ["core", "automation"]; + forgedStateFrontendContext.implementation_guidance.artifact_inspector + .active_state_groups = ["core", "automation"]; + forgedStateFrontendContext.implementation_guidance.artifact_inspector + .registry.active_state_groups = ["core", "automation"]; + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: forgedStateFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal( + error.code, + "invalid_artifact_inspector_authority_contract", + ); + assert.equal( + error.details.field, + "source.artifact_inspector_boundary_integrity", + ); + return true; + }, + "Skill compilation must reject a jointly forged reviewed source and state ceiling.", + ); + + const duplicateWorkUnitHandoff = structuredClone(handoff); + duplicateWorkUnitHandoff.workflow.work_units.push({ + ...structuredClone(duplicateWorkUnitHandoff.workflow.work_units[0]), + participant_intent: "Orient to an unrelated secondary artifact.", + }); + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: duplicateWorkUnitHandoff, + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.deepEqual(error.details.duplicate_work_unit_ids, ["orient"]); + return true; + }, + "A serialized handoff cannot add a divergent duplicate work-unit id before frontend generation.", + ); + + const duplicateWorkUnitFrontendContext = structuredClone(frontendContext); + duplicateWorkUnitFrontendContext.workflow.work_units.push({ + ...structuredClone( + duplicateWorkUnitFrontendContext.workflow.work_units[0], + ), + participant_intent: "Orient to an unrelated secondary artifact.", + }); + assert.throws( + () => + createFrontendImplementationSkillContext({ + frontend_generation_context: duplicateWorkUnitFrontendContext, + target_client: "codex", + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.deepEqual(error.details.duplicate_work_unit_ids, ["orient"]); + return true; + }, + "A serialized frontend context cannot add a divergent duplicate work-unit id.", + ); + + assert.throws( + () => + createFrontendGenerationContext({ + ui_generation_handoff: handoff, + supported_surface_profiles: [ + "judgmentkit.workbench.operational-v1", + ], + }), + (error) => { + assert.ok(error instanceof JudgmentKitInputError); + assert.equal(error.code, "artifact_inspector_profile_unsupported"); + assert.equal(error.details.fallback_applied, false); + assert.equal( + error.details.required_surface_profile, + "judgmentkit.artifact-inspector.v1", + ); + return true; + }, + ); +} + +{ + const callerBroadenedContract = createUiImplementationContract({ + surface_type: "artifact_inspector", + artifact_inspector: { + active_state_groups: [ + "core", + "consequential", + "reusable_guidance", + "automation", + ], + }, + }).implementation_contract; + const handoff = createUiGenerationHandoff(validWorkflowReview, { + implementation_contract: callerBroadenedContract, + }); + const frontendContext = createFrontendGenerationContext({ + ui_generation_handoff: handoff, + }); + + assert.deepEqual( + callerBroadenedContract.artifact_inspector.active_state_groups, + ["core", "consequential", "reusable_guidance", "automation"], + ); + assert.deepEqual( + handoff.implementation_contract.artifact_inspector.active_state_groups, + ["core"], + "Caller implementation metadata must not activate groups absent from the reviewed workflow.", + ); + assert.deepEqual( + handoff.artifact_inspector.registry.active_state_groups, + ["core"], + ); + assert.deepEqual( + frontendContext.implementation_guidance.artifact_inspector + .active_state_groups, + ["core"], + ); +} + +{ + const candidate = createCandidate(); + candidate.artifact = structuredClone(candidate.workflow.artifact); + candidate.target_model = structuredClone(candidate.workflow.target_model); + delete candidate.workflow.artifact; + delete candidate.workflow.target_model; + const review = reviewCandidate(candidate); + const handoff = createUiGenerationHandoff(review); + + assert.equal(review.review_status, "ready_for_review"); + assert.deepEqual(review.candidate.workflow.artifact, candidate.artifact); + assert.deepEqual(review.candidate.workflow.target_model, candidate.target_model); + assert.equal("artifact" in review.candidate, false); + assert.equal("target_model" in review.candidate, false); + assert.equal(handoff.handoff_status, "ready_for_generation"); + assert.deepEqual(handoff.workflow.artifact, candidate.artifact); + assert.deepEqual(handoff.workflow.target_model, candidate.target_model); +} + +{ + const candidate = createCandidate(); + candidate.workflow.topology_contract = structuredClone( + candidate.workflow.topology, + ); + candidate.workflow.topology = "artifact_centered"; + const review = reviewCandidate(candidate); + + assert.equal(review.review_status, "ready_for_review"); + assert.equal(review.guardrails.artifact_inspector.valid, true); + assert.equal(review.candidate.workflow.topology, "artifact_centered"); + assert.deepEqual(review.candidate.workflow.topology_contract, model.topology); +} + +{ + const candidate = createCandidate(); + candidate.workflow.topology = "artifact_centered"; + const review = reviewCandidate(candidate); + const diagnostic = review.guardrails.artifact_inspector.diagnostics.find( + (entry) => + entry.code === "JK_ARTIFACT_INSPECTOR_TOPOLOGY_CONTRACT_MISSING", + ); + + assert.equal(review.review_status, "needs_source_context"); + assert.equal(review.guardrails.artifact_inspector.valid, false); + assert.ok(diagnostic); + assert.equal(diagnostic.field, "workflow.topology_contract"); + assert.equal(review.candidate.workflow.topology, "artifact_centered"); + assert.equal( + "topology_contract" in review.candidate.workflow, + false, + "The reviewer must not synthesize the normative topology from the registry.", + ); +} + +{ + const consequentialAutomationActivity = ` + A policy reviewer inspects one rendered policy document that remains the + primary artifact. They select a specific passage and supporting evidence + attaches to that selected passage. They explicitly approve and publish the + decision, then a declared automation automatically resolves exact matches. + They preview the relation and verify the immutable local receipt + beside the passage. + `; + const conditionalActivityReview = createActivityModelReview( + consequentialAutomationActivity, + ); + const conditionalSurfaceReview = recommendSurfaceTypes( + consequentialAutomationActivity, + { activity_review: conditionalActivityReview }, + ); + const candidate = createCandidate(); + candidate.workflow.state_groups = { + core: structuredClone(model.state_groups.core), + consequential: structuredClone(model.state_groups.consequential), + automation: structuredClone(model.state_groups.automation), + }; + const review = reviewUiWorkflowCandidate( + consequentialAutomationActivity, + candidate, + { + activity_review: conditionalActivityReview, + profile_id: "artifact-inspector-ui", + surface_review: conditionalSurfaceReview, + }, + ); + const coreOnlyImplementationContract = createUiImplementationContract({ + surface_type: "artifact_inspector", + }).implementation_contract; + assert.deepEqual( + coreOnlyImplementationContract.artifact_inspector.active_state_groups, + ["core"], + ); + const handoff = createUiGenerationHandoff(review, { + implementation_contract: coreOnlyImplementationContract, + }); + + assert.equal(review.review_status, "ready_for_review"); + assert.deepEqual( + review.guardrails.candidate_primary_meta_terms_detected, + [], + "The canonical consequential state 'outcome pending' is domain state, not review-packet leakage.", + ); + assert.deepEqual( + handoff.implementation_contract.artifact_inspector.active_state_groups, + ["core", "consequential", "automation"], + ); +} + +{ + const consequentialActivity = ` + A compliance reviewer inspects one rendered policy document that remains + the primary artifact. They must select a specific passage, and the evidence + for approval attaches to that selected passage. They preview the relation, + explicitly approve and publish the decision, then verify the immutable + receipt beside the passage. + `; + const consequentialActivityReview = createActivityModelReview( + consequentialActivity, + ); + const consequentialSurfaceReview = recommendSurfaceTypes( + consequentialActivity, + { activity_review: consequentialActivityReview }, + ); + const review = reviewUiWorkflowCandidate( + consequentialActivity, + createCandidate(), + { + activity_review: consequentialActivityReview, + profile_id: "artifact-inspector-ui", + surface_review: consequentialSurfaceReview, + }, + ); + const diagnostic = review.guardrails.artifact_inspector.diagnostics.find( + (entry) => + entry.code === + "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + ); + + assert.equal(review.review_status, "needs_source_context"); + assert.ok(diagnostic); + assert.equal(diagnostic.field, "workflow.state_groups"); + assert.ok(diagnostic.expected_contract.includes("consequential")); +} + +{ + const request = buildUiWorkflowCandidateRequest({ + brief: ARTIFACT_ACTIVITY, + activity_review: activityReview, + profile_id: "artifact-inspector-ui", + surface_review: surfaceReview, + }); + const payload = JSON.parse(request.messages.at(-1).content); + + assert.equal( + payload.candidate_shape.workflow.topology.kind, + "artifact_centered", + ); + assert.equal( + payload.candidate_shape.workflow.topology.primary_object_id, + "artifact", + ); + assert.deepEqual( + payload.candidate_shape.workflow.work_units.map((entry) => entry.id), + model.work_units.map((entry) => entry.id), + ); + assert.deepEqual( + payload.candidate_shape.workflow.target_model.target_kinds, + model.target_model.target_kinds, + ); + assert.deepEqual( + Object.keys(payload.candidate_shape.workflow.state_groups), + ["core"], + "The generated candidate shape must not activate every conditional state group by default.", + ); + assert.deepEqual( + payload.artifact_inspector_state_group_catalog, + model.state_groups, + "Conditional state definitions remain available without becoming active candidate state by default.", + ); + assert.ok( + request.messages[0].content.includes( + "stable structured work-unit ids", + ), + ); +} + +const MALFORMED_CASES = [ + { + label: "wrong topology kind", + mutate(candidate) { + candidate.workflow.topology.kind = "workspace"; + }, + code: "JK_ARTIFACT_INSPECTOR_TOPOLOGY_KIND_INVALID", + field: "workflow.topology.kind", + }, + { + label: "missing primary artifact reference", + mutate(candidate) { + delete candidate.workflow.topology.primary_object_id; + }, + code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + field: "workflow.topology.primary_object_id", + }, + { + label: "coherently renamed primary artifact", + mutate(candidate) { + renamePrimaryArtifact(candidate.workflow); + }, + code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + field: "workflow.topology.primary_object_id", + }, + { + label: "missing locus model", + mutate(candidate) { + delete candidate.workflow.target_model.target_kinds; + }, + code: "JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING", + field: "workflow.target_model.target_kinds", + }, + ...[ + "target_identity_sources", + "geometry_policy", + "label_sources", + "artifact_interactivity", + "native_interaction_precedence", + "artifact_id", + ].map((field) => ({ + label: `missing target model ${field}`, + mutate(candidate) { + delete candidate.workflow.target_model[field]; + }, + code: "JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING", + field: `workflow.target_model.${field}`, + })), + { + label: "noncanonical inferred target model", + mutate(candidate) { + candidate.workflow.target_model = { + target_kinds: ["pixel_guess"], + target_identity_sources: ["visual_inference"], + geometry_policy: "Infer the nearest element after every render.", + label_sources: ["model_generated"], + artifact_interactivity: ["live"], + native_interaction_precedence: + "The inspector always captures native actions.", + artifact_id: "artifact", + }; + }, + code: "JK_ARTIFACT_INSPECTOR_LOCUS_MODEL_MISSING", + field: "workflow.target_model.target_kinds", + }, + { + label: "missing stable work-unit id", + mutate(candidate) { + delete candidate.workflow.work_units[0].id; + }, + code: "JK_ARTIFACT_INSPECTOR_WORK_UNIT_ID_MISSING", + field: "workflow.work_units[0].id", + }, + { + label: "missing required work units", + mutate(candidate) { + candidate.workflow.work_units = candidate.workflow.work_units.filter( + (workUnit) => ["orient", "select_locus", "recover"].includes(workUnit.id), + ); + candidate.workflow.topology.entry_work_unit_id = "orient"; + candidate.workflow.topology.completion_work_unit_ids = ["orient"]; + candidate.workflow.topology.transitions = [ + { from: "orient", to: "select_locus" }, + { from: "select_locus", to: "recover" }, + { from: "recover", to: "orient" }, + ]; + }, + code: "JK_ARTIFACT_INSPECTOR_WORK_UNIT_ID_MISSING", + field: "workflow.work_units", + }, + { + label: "divergent duplicate work-unit id", + mutate(candidate) { + candidate.workflow.work_units.push({ + ...structuredClone(candidate.workflow.work_units[0]), + participant_intent: "Orient to an unrelated secondary artifact.", + }); + }, + code: "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + field: "workflow.work_units", + }, + { + label: "invalid work-unit contract", + mutate(candidate) { + candidate.workflow.work_units[0].participant_intent = + "Open a generic workspace."; + }, + code: "JK_ARTIFACT_INSPECTOR_WORK_UNIT_CONTRACT_INVALID", + field: "workflow.work_units[0].participant_intent", + }, + { + label: "missing artifact declaration", + mutate(candidate) { + delete candidate.workflow.artifact; + }, + code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + field: "workflow.artifact.id", + }, + { + label: "missing artifact boundary", + mutate(candidate) { + delete candidate.workflow.artifact.boundary; + }, + code: "JK_ARTIFACT_INSPECTOR_PRIMARY_ARTIFACT_MISSING", + field: "workflow.artifact.boundary", + }, + { + label: "invalid entry reference", + mutate(candidate) { + candidate.workflow.topology.entry_work_unit_id = "missing_entry"; + }, + code: "JK_ARTIFACT_INSPECTOR_ENTRY_REFERENCE_INVALID", + field: "workflow.topology.entry_work_unit_id", + }, + { + label: "invalid completion reference", + mutate(candidate) { + candidate.workflow.topology.completion_work_unit_ids = [ + "missing_completion", + ]; + }, + code: "JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID", + field: "workflow.topology.completion_work_unit_ids", + }, + { + label: "completion omits artifact-local verification", + mutate(candidate) { + candidate.workflow.topology.completion_work_unit_ids = ["orient"]; + }, + code: "JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID", + field: "workflow.topology.completion_work_unit_ids", + }, + { + label: "invalid transition reference", + mutate(candidate) { + candidate.workflow.topology.transitions[0].from = "missing_work_unit"; + }, + code: "JK_ARTIFACT_INSPECTOR_TRANSITION_REFERENCE_INVALID", + field: "workflow.topology.transitions", + }, + { + label: "disconnected canonical topology", + mutate(candidate) { + candidate.workflow.topology.transitions = [ + { from: "orient", to: "recover" }, + { from: "recover", to: "orient" }, + ]; + }, + code: "JK_ARTIFACT_INSPECTOR_TRANSITION_REFERENCE_INVALID", + field: "workflow.topology.transitions", + }, + { + label: "missing recovery path", + mutate(candidate) { + candidate.workflow.topology.transitions = + candidate.workflow.topology.transitions.filter( + (transition) => + transition.from !== "recover" && transition.to !== "recover", + ); + }, + code: "JK_ARTIFACT_INSPECTOR_RECOVERY_PATH_MISSING", + field: "workflow.topology.transitions", + }, + { + label: "missing state-group contract", + mutate(candidate) { + delete candidate.workflow.state_groups; + }, + code: "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + field: "workflow.state_groups", + }, + { + label: "invalid core state set", + mutate(candidate) { + candidate.workflow.state_groups.core = ["artifact ready"]; + }, + code: "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + field: "workflow.state_groups.core", + }, + { + label: "inactive conditional state groups", + mutate(candidate) { + candidate.workflow.state_groups = structuredClone(model.state_groups); + }, + code: "JK_ARTIFACT_INSPECTOR_STATE_GROUP_CONTRACT_INVALID", + field: "workflow.state_groups", + }, +]; + +for (const malformedCase of MALFORMED_CASES) { + const candidate = createCandidate(); + malformedCase.mutate(candidate); + const review = reviewCandidate(candidate); + const diagnostics = review.guardrails.artifact_inspector.diagnostics; + const diagnostic = diagnostics.find( + (entry) => entry.code === malformedCase.code, + ); + + assert.equal( + review.review_status, + "needs_source_context", + `${malformedCase.label} must block workflow acceptance.`, + ); + assert.equal(review.guardrails.artifact_inspector.valid, false); + assert.ok( + diagnostic, + `${malformedCase.label} must emit ${malformedCase.code}.`, + ); + assert.equal(diagnostic.field, malformedCase.field); + assert.notEqual(diagnostic.expected_contract, undefined); + assert.equal(typeof diagnostic.repair_instruction, "string"); + assert.ok(diagnostic.repair_instruction.length > 0); + assert.ok( + review.review.targeted_questions.includes( + diagnostic.repair_instruction, + ), + `${malformedCase.label} repair must remain user-actionable.`, + ); +} + +console.log("artifact inspector workflow checks passed."); diff --git a/tests/kernel-contract.test.mjs b/tests/kernel-contract.test.mjs index 2750dad..ea63cf1 100644 --- a/tests/kernel-contract.test.mjs +++ b/tests/kernel-contract.test.mjs @@ -280,7 +280,7 @@ assert.equal( contract.implementation_contract.default_ai_native_design_system.component_contracts .length, 17, - "The default AI-native system must include core UI component contracts.", + "Artifact Inspector semantic roles must not be promoted into unimplemented component contracts.", ); assert.ok( contract.implementation_contract.default_ai_native_design_system.component_contracts.some( @@ -425,7 +425,7 @@ assert.deepEqual( assert.equal( contract.implementation_contract.default_ai_native_design_system.pattern_contracts .length, - 8, + 9, "The default AI-native system must include one pattern contract per surface type.", ); assert.ok( @@ -1211,6 +1211,7 @@ assert.deepEqual(contract.workflow.topology_policy.allowed_topologies, [ "dashboard", "report", "conversation", + "artifact_centered", ]); assert.equal(contract.workflow.topology_policy.preferred_default, "workspace"); assert.equal( @@ -1255,6 +1256,7 @@ assert.deepEqual(Object.keys(contract.surface_types), [ "marketing", "workbench", "operator_review", + "artifact_inspector", "form_flow", "dashboard_monitor", "content_report", diff --git a/tests/mcp.test.mjs b/tests/mcp.test.mjs index d9c5dde..1bd5fc5 100644 --- a/tests/mcp.test.mjs +++ b/tests/mcp.test.mjs @@ -473,6 +473,18 @@ assert.equal(toolByName.create_ui_implementation_contract.inputSchema.properties 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(toolByName.create_ui_implementation_contract.inputSchema.properties.visual_token_adapter.type, "object"); +for (const callerAuthorityField of [ + "design_system_scopes", + "boundary_contracts", + "artifact_inspector", +]) { + assert.equal( + callerAuthorityField in + toolByName.create_ui_implementation_contract.inputSchema.properties, + false, + `${callerAuthorityField} must not be caller-authored through the public MCP contract tool.`, + ); +} assert.equal( toolByName.create_ui_implementation_contract.inputSchema.properties.visual_composition_policy.type, "object", @@ -498,6 +510,16 @@ assert.equal(toolByName.review_ui_implementation_candidate.inputSchema.propertie assert.equal(toolByName.review_ui_implementation_candidate.inputSchema.properties.surfaceType.type, "string"); assert.equal(toolByName.review_ui_implementation_candidate.inputSchema.properties.surface_review.type, "object"); assert.equal(toolByName.review_ui_implementation_candidate.inputSchema.properties.surfaceReview.type, "object"); +assert.equal( + "trustedRuntimeEvidence" in + toolByName.review_ui_implementation_candidate.inputSchema.properties, + false, +); +assert.equal( + "trusted_runtime_evidence" in + toolByName.review_ui_implementation_candidate.inputSchema.properties, + false, +); assert.equal( toolByName.review_ui_implementation_candidate.inputSchema.properties.frontend_generation_context.type, "object", @@ -1738,6 +1760,30 @@ MCP endpoint: http://127.0.0.1:3333/mcp`; formatPlanningCard(missingProvenanceReview).includes("This is not an artifact"), ); + const artifactInspectorReviewRequiredCard = formatPlanningCard({ + implementation_review_status: "review_required", + candidate_artifact_status: "review_required", + design_system_acceptance_status: "review_required", + next_agent_action: "none", + findings: [], + checks: { + artifact_inspector: { status: "review_required" }, + }, + }); + assert.match( + artifactInspectorReviewRequiredCard, + /\*\*Status:\*\* Review required; interactive attestation deferred/, + ); + assert.ok( + artifactInspectorReviewRequiredCard.includes( + "keep the external artifact external_not_reviewed", + ), + ); + assert.equal( + artifactInspectorReviewRequiredCard.includes("Repair the failed gates"), + false, + ); + const implementationReview = await handleToolCall("review_ui_implementation_candidate", { implementation_contract: implementationContract, candidate: withNoApplicableVisualComposition({ diff --git a/tests/site.test.mjs b/tests/site.test.mjs index 84e5e47..a8c43cc 100644 --- a/tests/site.test.mjs +++ b/tests/site.test.mjs @@ -2403,7 +2403,7 @@ assert.ok( 'data-surface-presentation-profile="judgmentkit.workbench.operational-v1"', ), ); -assert.ok(designSystemPatterns.includes("Supported surface presentation profiles")); +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"')); assert.ok(designSystemPatterns.includes('data-pattern-control="decision-action"')); @@ -2744,8 +2744,11 @@ assert.deepEqual( surfacePresentationProfilesExport.profiles, listSurfacePresentationProfiles(), ); -assert.equal(surfacePresentationProfilesExport.profiles.length, 1); -const workbenchPresentationProfile = surfacePresentationProfilesExport.profiles[0]; +assert.equal(surfacePresentationProfilesExport.profiles.length, 2); +const workbenchPresentationProfile = surfacePresentationProfilesExport.profiles.find( + (entry) => entry.id === "judgmentkit.workbench.operational-v1", +); +assert.ok(workbenchPresentationProfile); assert.equal(workbenchPresentationProfile.id, "judgmentkit.workbench.operational-v1"); assert.equal(workbenchPresentationProfile.status, "supported"); assert.equal(workbenchPresentationProfile.surface_type, "workbench"); @@ -2760,6 +2763,23 @@ assert.ok( ), "the supported Workbench presentation profile must bind to the public Workbench pattern contract", ); +const artifactInspectorPresentationProfile = + surfacePresentationProfilesExport.profiles.find( + (entry) => entry.id === "judgmentkit.artifact-inspector.v1", + ); +assert.ok(artifactInspectorPresentationProfile); +assert.equal(artifactInspectorPresentationProfile.status, "proposed"); +assert.equal(artifactInspectorPresentationProfile.surface_type, "artifact_inspector"); +assert.equal(artifactInspectorPresentationProfile.authority.public_contract, true); +assert.equal(artifactInspectorPresentationProfile.authority.runtime_renderer, false); +assert.equal( + artifactInspectorPresentationProfile.authority.pattern_contract_id, + "artifact-inspector", +); +assert.equal( + artifactInspectorPresentationProfile.provenance.external_artifact_review_status, + "external_not_reviewed", +); const contractIds = componentContractsExport.contracts.map((entry) => entry.id); const registryIds = componentRegistryExport.registry.map( (entry) => entry.contract_id, diff --git a/tests/workbench-surface-profile.test.mjs b/tests/workbench-surface-profile.test.mjs index b0705a3..59296ff 100644 --- a/tests/workbench-surface-profile.test.mjs +++ b/tests/workbench-surface-profile.test.mjs @@ -722,7 +722,12 @@ for (const invalidId of [undefined, "auto", "none"]) { assert.deepEqual( new Set(properties.surface_profile.enum), - new Set(["auto", "none", EXPECTED_WORKBENCH_PROFILE_ID]), + new Set([ + "auto", + "none", + EXPECTED_WORKBENCH_PROFILE_ID, + "judgmentkit.artifact-inspector.v1", + ]), ); assert.equal("experimental_surface_profile" in properties, false); From 0fa800f2a530cef0b6a8ff65159dcf8ff078c259 Mon Sep 17 00:00:00 2001 From: Mike Long Date: Sun, 30 Aug 2026 14:21:28 -0700 Subject: [PATCH 2/4] Prepare JudgmentKit 0.8.0 release --- CHANGELOG.md | 10 +++++++ .../ai-ui-generation.activity-contract.json | 2 +- docs/daily-agent-workflows.md | 2 +- docs/releases/v0.8.0.md | 23 ++++++++++++++++ evals/run-mcp-pilot-evals.mjs | 2 +- .../canonical-examples.json | 2 +- .../ai-native-design-system/first-use.json | 2 +- package-lock.json | 4 +-- package.json | 2 +- scripts/verify-public-release.mjs | 26 ++++++++++++++++--- src/mcp.mjs | 2 +- .../ai-native-design-system-release.test.mjs | 2 +- tests/eval-rerun-guardrails.test.mjs | 4 +-- tests/mcp.test.mjs | 2 +- tests/site.test.mjs | 25 +++++++++++++++--- 15 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 docs/releases/v0.8.0.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c14c60..4994ca2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ ## Unreleased +## 0.8.0 - 2026-08-30 + +- Added Artifact Inspector as a versioned public interaction-model contract for grounded, artifact-primary review work. +- Publishes the `artifact_inspector` surface, `artifact-inspector-ui` workflow profile, `artifact_centered` topology, and `judgmentkit.artifact-inspector.v1` presentation profile through the package and MCP APIs. +- Carries the canonical work units, artifact identity, target model, active states, and scoped JudgmentKit authority through the workflow, handoff, and frontend boundaries. +- Keeps legacy Workbench and marketing routing isolated from Artifact Inspector authority. +- Keeps implementation review fail-closed at `review_required`; the primary artifact remains external and is not reviewed by JudgmentKit. +- Keeps the Artifact Inspector surface and presentation profile at `proposed` promotion status while the runtime proof path remains deferred. +- Defers trusted interactive runtime attestation to a separate release. This release does not expose an action or result that claims complete runtime boundary proof. + ## 0.7.0 - 2026-08-08 - Added the supported `judgmentkit.workbench.operational-v1` surface-presentation profile for grounded Workbench activity. diff --git a/contracts/ai-ui-generation.activity-contract.json b/contracts/ai-ui-generation.activity-contract.json index eaaf93f..c3b8578 100644 --- a/contracts/ai-ui-generation.activity-contract.json +++ b/contracts/ai-ui-generation.activity-contract.json @@ -1,7 +1,7 @@ { "$schema": "./judgmentkit-kernel.schema.json", "id": "judgmentkit.ai-ui-generation.activity-contract", - "version": "0.7.0", + "version": "0.8.0", "source_model": "fresh_start", "quality_order": [ "activity fit", diff --git a/docs/daily-agent-workflows.md b/docs/daily-agent-workflows.md index c18cb48..c05599c 100644 --- a/docs/daily-agent-workflows.md +++ b/docs/daily-agent-workflows.md @@ -39,7 +39,7 @@ This rebuilds `site/dist`, serves the static website, and routes localhost `/mcp Use the hosted surface canary after classifier changes or when checking the deployed MCP surface-routing contract: ```bash -npm run mcp:smoke:hosted-surface -- --endpoint https://judgmentkit.ai/mcp --expected-version 0.7.0 +npm run mcp:smoke:hosted-surface -- --endpoint https://judgmentkit.ai/mcp --expected-version 0.8.0 ``` This is a surface-routing smoke, not a full product-workflow readiness check. The command prints `review_status` and `activity_review_ready` for each canary, but fails by default only when metadata, tool availability, or `recommended_surface_type` is wrong. Add `--require-ready-review` when the smoke should also fail on `needs_source_context`. diff --git a/docs/releases/v0.8.0.md b/docs/releases/v0.8.0.md new file mode 100644 index 0000000..aa68dd0 --- /dev/null +++ b/docs/releases/v0.8.0.md @@ -0,0 +1,23 @@ +# JudgmentKit 0.8.0 + +Released: 2026-08-30 + +JudgmentKit 0.8.0 adds the Artifact Inspector interaction model and contract as a versioned public API. + +## Improvements + +- Added `artifact_inspector`, `artifact-inspector-ui`, `artifact_centered`, and `judgmentkit.artifact-inspector.v1` as canonical public identifiers. +- Added the canonical Artifact Inspector work-unit topology, artifact identity, target model, active-state contract, and scoped authority boundaries. +- Carries the reviewed contract through UI generation handoff, frontend generation context, and compiled implementation guidance with stage-specific integrity checks. +- Publishes the surface, workflow profile, schemas, contracts, and MCP tools through the supported package interfaces. +- Preserves Workbench and marketing behavior when Artifact Inspector activity evidence is absent or conflicting. + +## Boundaries + +- This is a contract and interaction-model release, not a trusted interactive runtime attestation release. +- The Artifact Inspector surface and presentation profile remain `proposed`; this release does not promote them to supported runtime status. +- Missing or incomplete runtime evidence remains `review_required`; static roots, metadata, and unchanged fingerprints cannot establish full boundary proof. +- JudgmentKit authority is limited to inspector chrome and the inspection overlay. The primary artifact remains external and is reported as `external_not_reviewed`. +- Trusted interactive attestation is deferred to a separate project. It must observe real input and accessibility crossings, focus order and return, overlay occlusion, semantic re-anchoring, native-action precedence, and the required state and viewport matrix. +- This release exposes no action or output that claims those deferred runtime checks have passed. +- The latest committed UI-generation eval remains immutable 0.7.0 historical evidence; this release does not relabel it as 0.8.0 evidence. diff --git a/evals/run-mcp-pilot-evals.mjs b/evals/run-mcp-pilot-evals.mjs index 2866f57..bb863c1 100644 --- a/evals/run-mcp-pilot-evals.mjs +++ b/evals/run-mcp-pilot-evals.mjs @@ -26,7 +26,7 @@ export const CATALOG_JSON_FILENAME = "index.json"; export const CATALOG_HTML_FILENAME = "index.html"; export const EVAL_ID = "judgmentkit-mcp-private-pilot-v1"; export const CATALOG_ID = "judgmentkit-mcp-private-pilot-runs"; -export const REQUIRED_MCP_VERSION = "0.7.0"; +export const REQUIRED_MCP_VERSION = "0.8.0"; export const MODEL_ID = "gpt-5.5"; export const REASONING_EFFORT = "xhigh"; export const CODEX_MODEL_CONFIG_ID = "gpt-5.5-codex"; diff --git a/examples/ai-native-design-system/canonical-examples.json b/examples/ai-native-design-system/canonical-examples.json index bb1d420..e0952b9 100644 --- a/examples/ai-native-design-system/canonical-examples.json +++ b/examples/ai-native-design-system/canonical-examples.json @@ -1,6 +1,6 @@ { "id": "judgmentkit-ai-native-design-system-canonical-examples-v1", - "release_target": "0.7.0", + "release_target": "0.8.0", "purpose": "Replayable examples for the contract-governed AI-native design system before renderer work.", "examples": [ { diff --git a/examples/ai-native-design-system/first-use.json b/examples/ai-native-design-system/first-use.json index 9f4616b..2559cd2 100644 --- a/examples/ai-native-design-system/first-use.json +++ b/examples/ai-native-design-system/first-use.json @@ -1,6 +1,6 @@ { "id": "judgmentkit-first-use-repair-loop-v1", - "release_target": "0.7.0", + "release_target": "0.8.0", "target_time_minutes": 10, "claim": "Install JudgmentKit, review a generated UI candidate, repair the failed contract area, and resubmit to acceptance.", "brief": "A support lead is reviewing refund requests during the daily triage workflow. The activity is deciding whether a case should be approved, sent to policy review, or returned to the agent for missing evidence. The outcome is a clear handoff with the next action and the reason for the decision.", diff --git a/package-lock.json b/package-lock.json index ef2debd..5b2551f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "judgmentkit", - "version": "0.7.0", + "version": "0.8.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "judgmentkit", - "version": "0.7.0", + "version": "0.8.0", "dependencies": { "@emotion/cache": "^11.14.0", "@emotion/react": "^11.14.0", diff --git a/package.json b/package.json index ba71ff7..ded6f59 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "judgmentkit", - "version": "0.7.0", + "version": "0.8.0", "private": true, "type": "module", "files": [ diff --git a/scripts/verify-public-release.mjs b/scripts/verify-public-release.mjs index 1305fa1..8345c7c 100644 --- a/scripts/verify-public-release.mjs +++ b/scripts/verify-public-release.mjs @@ -561,10 +561,24 @@ async function verifyEvalArchive(baseUrl, analyticsScriptSrc, expectedPackageVer assert.ok(catalog.latest, "eval catalog should include latest run"); assert.ok(Array.isArray(catalog.runs), "eval catalog should include runs"); assert.ok(catalog.runs.length > 0, "eval catalog should include at least one run"); - assert.equal( + assert.match( catalog.latest.mcp_release, - expectedPackageVersion, - "latest public UI eval should match the current hosted MCP release", + /^\d+\.\d+\.\d+$/, + "latest public UI eval should identify its historical MCP release", + ); + assert.equal( + catalog.latest.mcp_release_segment, + `mcp-${catalog.latest.mcp_release}`, + "latest public UI eval release segment should match its historical MCP release", + ); + assert.ok( + catalog.runs.some( + (run) => + run.run_path === catalog.latest.run_path && + run.json_report === catalog.latest.json_report && + run.html_report === catalog.latest.html_report, + ), + "latest public UI eval should be present in the immutable run catalog", ); assertIncludes( index.text, @@ -638,7 +652,11 @@ async function verifyEvalArchive(baseUrl, analyticsScriptSrc, expectedPackageVer const latestJson = JSON.parse((await fetchText(baseUrl, latestJsonRoute)).text); assert.equal(latestJson.eval_id, "judgmentkit-ui-generation-paired-artifact-v1"); - assert.equal(latestJson.run.mcp_release, expectedPackageVersion); + assert.equal( + latestJson.run.mcp_release, + catalog.latest.mcp_release, + "latest UI eval report should match its cataloged historical MCP release", + ); assert.equal(latestJson.run.html_report, catalog.latest.html_report); assert.equal(latestJson.run.json_report, catalog.latest.json_report); assert.equal(latestJson.visual_evidence.capture_engine, "chrome_devtools_protocol"); diff --git a/src/mcp.mjs b/src/mcp.mjs index fb62500..299319b 100644 --- a/src/mcp.mjs +++ b/src/mcp.mjs @@ -37,7 +37,7 @@ import { } from "./presentation-theme/index.mjs"; const MCP_SERVER_NAME = "JudgmentKit"; -const MCP_SERVER_VERSION = "0.7.0"; +const MCP_SERVER_VERSION = "0.8.0"; const SLIDE_DECK_SCHEMA = "judgmentkit.mcp.slide-deck/v1"; const SLIDE_DECK_RECEIPT_SCHEMA = "judgmentkit.mcp.slide-deck.provenance-receipt/v1"; const MAX_SLIDE_DECK_SLIDES = 24; diff --git a/tests/ai-native-design-system-release.test.mjs b/tests/ai-native-design-system-release.test.mjs index 80c6f0e..d9ac97c 100644 --- a/tests/ai-native-design-system-release.test.mjs +++ b/tests/ai-native-design-system-release.test.mjs @@ -149,7 +149,7 @@ const firstUse = readJson("examples/ai-native-design-system/first-use.json"); const canonicalExamples = readJson("examples/ai-native-design-system/canonical-examples.json"); const EXPECTED_RELEASE_VERSION = packageJson.version; -assert.equal(packageJson.version, "0.7.0"); +assert.equal(packageJson.version, "0.8.0"); assert.equal(activityContract.version, EXPECTED_RELEASE_VERSION); assert.equal(getMcpMetadata("streamable-http").version, EXPECTED_RELEASE_VERSION); assert.equal( diff --git a/tests/eval-rerun-guardrails.test.mjs b/tests/eval-rerun-guardrails.test.mjs index 20469a0..5a1c526 100644 --- a/tests/eval-rerun-guardrails.test.mjs +++ b/tests/eval-rerun-guardrails.test.mjs @@ -300,7 +300,7 @@ const uiCases = readJson("evals/ui-generation-cases.json"); const activityContract = readJson("contracts/ai-ui-generation.activity-contract.json"); const mcpPilotCatalog = readJson("evals/reports/mcp-pilot/index.json"); -assert.equal(activityContract.version, "0.7.0"); +assert.equal(activityContract.version, "0.8.0"); const filesWithAxisCoverage = new Set(); const activeContractAxisCommitments = [ @@ -801,7 +801,7 @@ for (const testCase of visualTokenProofCases) { ); } -assert.equal(REQUIRED_MCP_VERSION, "0.7.0"); +assert.equal(REQUIRED_MCP_VERSION, "0.8.0"); function allRequiredTerms(testCase) { return [ diff --git a/tests/mcp.test.mjs b/tests/mcp.test.mjs index 1bd5fc5..385e433 100644 --- a/tests/mcp.test.mjs +++ b/tests/mcp.test.mjs @@ -251,7 +251,7 @@ assert.deepEqual( ], ); assert.equal(metadata.name, "JudgmentKit"); -assert.equal(metadata.version, "0.7.0"); +assert.equal(metadata.version, "0.8.0"); assert.deepEqual(metadata.capabilities.prompts, []); { diff --git a/tests/site.test.mjs b/tests/site.test.mjs index a8c43cc..54a95a2 100644 --- a/tests/site.test.mjs +++ b/tests/site.test.mjs @@ -3611,10 +3611,24 @@ assert.ok(siteCss.includes(".evals-table-shell {\n max-width: 100%;")); assert.equal(evalCatalog.catalog_id, "judgmentkit-ui-generation-eval-runs"); assert.ok(evalCatalog.latest, "eval catalog should expose latest run"); -assert.equal( +assert.match( evalCatalog.latest.mcp_release, - packageJson.version, - "latest public UI eval should match the current package version", + /^\d+\.\d+\.\d+$/, + "latest public UI eval should identify its historical MCP release", +); +assert.equal( + evalCatalog.latest.mcp_release_segment, + `mcp-${evalCatalog.latest.mcp_release}`, + "latest public UI eval release segment should match its historical MCP release", +); +assert.ok( + evalCatalog.runs.some( + (run) => + run.run_path === evalCatalog.latest.run_path && + run.json_report === evalCatalog.latest.json_report && + run.html_report === evalCatalog.latest.html_report, + ), + "latest public UI eval should be present in the immutable run catalog", ); assert.ok(evalCatalog.latest.html_report.endsWith("/ui-generation-report.html")); assert.ok(evalCatalog.latest.json_report.endsWith("/ui-generation-report.json")); @@ -3631,6 +3645,11 @@ assert.equal( const latestEvalReport = JSON.parse( fs.readFileSync(path.join(tempDir, "evals", evalCatalog.latest.json_report), "utf8"), ); +assert.equal( + latestEvalReport.run.mcp_release, + evalCatalog.latest.mcp_release, + "latest UI eval report should match its cataloged historical MCP release", +); const latestScreenshotPath = latestEvalReport.results[0].variants[0].screenshots[0].path; assert.ok(latestScreenshotPath.endsWith(".png")); assert.equal( From 395ff73a708c308c3fc261a3a14a56c79cccedd8 Mon Sep 17 00:00:00 2001 From: Mike Long Date: Sun, 30 Aug 2026 14:27:10 -0700 Subject: [PATCH 3/4] Refresh 0.8.0 model UI fixtures --- ...deterministic-judgmentkit-material-ui.html | 8 +- .../deterministic-with-judgmentkit.html | 8 +- .../gemma4-lms-judgmentkit-material-ui.html | 4 +- ...5-xhigh-codex-judgmentkit-material-ui.html | 4 +- ...sol-low-codex-judgmentkit-material-ui.html | 4 +- .../gpt56-sol-low-codex-with-judgmentkit.html | 4 +- ...l-ultra-codex-judgmentkit-material-ui.html | 4 +- ...pt56-sol-ultra-codex-with-judgmentkit.html | 4 +- .../gemma4-lms-judgmentkit-material-ui.json | 2 +- .../captures/gemma4-lms-with-judgmentkit.json | 2 +- ...5-xhigh-codex-judgmentkit-material-ui.json | 2 +- .../gpt55-xhigh-codex-with-judgmentkit.json | 2 +- ...sol-low-codex-judgmentkit-material-ui.json | 2 +- .../gpt56-sol-low-codex-with-judgmentkit.json | 2 +- ...l-ultra-codex-judgmentkit-material-ui.json | 2 +- ...pt56-sol-ultra-codex-with-judgmentkit.json | 2 +- .../model-ui/b2b-renewal-risk/manifest.json | 88 +++++++++---------- .../reviewed-handoff.fixture.json | 2 +- ...deterministic-judgmentkit-material-ui.html | 8 +- .../deterministic-with-judgmentkit.html | 8 +- .../gemma4-lms-judgmentkit-material-ui.html | 4 +- ...5-xhigh-codex-judgmentkit-material-ui.html | 4 +- ...sol-low-codex-judgmentkit-material-ui.html | 4 +- .../gpt56-sol-low-codex-with-judgmentkit.html | 4 +- ...l-ultra-codex-judgmentkit-material-ui.html | 4 +- ...pt56-sol-ultra-codex-with-judgmentkit.html | 4 +- .../gemma4-lms-judgmentkit-material-ui.json | 2 +- .../captures/gemma4-lms-with-judgmentkit.json | 2 +- ...5-xhigh-codex-judgmentkit-material-ui.json | 2 +- .../gpt55-xhigh-codex-with-judgmentkit.json | 2 +- ...sol-low-codex-judgmentkit-material-ui.json | 2 +- .../gpt56-sol-low-codex-with-judgmentkit.json | 2 +- ...l-ultra-codex-judgmentkit-material-ui.json | 2 +- ...pt56-sol-ultra-codex-with-judgmentkit.json | 2 +- .../clinical-intake-review/manifest.json | 88 +++++++++---------- .../reviewed-handoff.fixture.json | 2 +- ...deterministic-judgmentkit-material-ui.html | 8 +- .../deterministic-with-judgmentkit.html | 8 +- .../gemma4-lms-judgmentkit-material-ui.html | 4 +- ...5-xhigh-codex-judgmentkit-material-ui.html | 4 +- ...sol-low-codex-judgmentkit-material-ui.html | 4 +- .../gpt56-sol-low-codex-with-judgmentkit.html | 4 +- ...l-ultra-codex-judgmentkit-material-ui.html | 4 +- ...pt56-sol-ultra-codex-with-judgmentkit.html | 4 +- .../gemma4-lms-judgmentkit-material-ui.json | 2 +- .../captures/gemma4-lms-with-judgmentkit.json | 2 +- ...5-xhigh-codex-judgmentkit-material-ui.json | 2 +- .../gpt55-xhigh-codex-with-judgmentkit.json | 2 +- ...sol-low-codex-judgmentkit-material-ui.json | 2 +- .../gpt56-sol-low-codex-with-judgmentkit.json | 2 +- ...l-ultra-codex-judgmentkit-material-ui.json | 2 +- ...pt56-sol-ultra-codex-with-judgmentkit.json | 2 +- .../field-service-dispatch/manifest.json | 88 +++++++++---------- .../reviewed-handoff.fixture.json | 2 +- ...deterministic-judgmentkit-material-ui.html | 8 +- .../deterministic-with-judgmentkit.html | 8 +- .../gemma4-lms-judgmentkit-material-ui.html | 4 +- ...5-xhigh-codex-judgmentkit-material-ui.html | 4 +- ...sol-low-codex-judgmentkit-material-ui.html | 4 +- .../gpt56-sol-low-codex-with-judgmentkit.html | 4 +- ...l-ultra-codex-judgmentkit-material-ui.html | 4 +- ...pt56-sol-ultra-codex-with-judgmentkit.html | 4 +- .../gemma4-lms-judgmentkit-material-ui.json | 2 +- .../captures/gemma4-lms-with-judgmentkit.json | 2 +- ...5-xhigh-codex-judgmentkit-material-ui.json | 2 +- .../gpt55-xhigh-codex-with-judgmentkit.json | 2 +- ...sol-low-codex-judgmentkit-material-ui.json | 2 +- .../gpt56-sol-low-codex-with-judgmentkit.json | 2 +- ...l-ultra-codex-judgmentkit-material-ui.json | 2 +- ...pt56-sol-ultra-codex-with-judgmentkit.json | 2 +- .../model-ui/refund-system-map/manifest.json | 88 +++++++++---------- .../reviewed-handoff.fixture.json | 2 +- 72 files changed, 292 insertions(+), 292 deletions(-) diff --git a/examples/model-ui/b2b-renewal-risk/artifacts/deterministic-judgmentkit-material-ui.html b/examples/model-ui/b2b-renewal-risk/artifacts/deterministic-judgmentkit-material-ui.html index 9b81b12..4d1ab78 100644 --- a/examples/model-ui/b2b-renewal-risk/artifacts/deterministic-judgmentkit-material-ui.html +++ b/examples/model-ui/b2b-renewal-risk/artifacts/deterministic-judgmentkit-material-ui.html @@ -286,8 +286,8 @@ "handoff_source": "examples/model-ui/b2b-renewal-risk/reviewed-handoff.fixture.json", "design_system_adapter_file": "examples/model-ui/b2b-renewal-risk/design-system-adapter.json", "capture_file": null, - "source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", - "current_source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", + "source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", + "current_source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", "source_context_status": "current", "model_response_summary": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -352,8 +352,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", - "accepted_source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", + "current_source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", + "accepted_source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." diff --git a/examples/model-ui/b2b-renewal-risk/artifacts/deterministic-with-judgmentkit.html b/examples/model-ui/b2b-renewal-risk/artifacts/deterministic-with-judgmentkit.html index beeedeb..8355f1c 100644 --- a/examples/model-ui/b2b-renewal-risk/artifacts/deterministic-with-judgmentkit.html +++ b/examples/model-ui/b2b-renewal-risk/artifacts/deterministic-with-judgmentkit.html @@ -379,8 +379,8 @@

Customer success manager

"handoff_source": "examples/model-ui/b2b-renewal-risk/reviewed-handoff.fixture.json", "design_system_adapter_file": null, "capture_file": null, - "source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", - "current_source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", + "source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", + "current_source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", "source_context_status": "current", "model_response_summary": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -445,8 +445,8 @@

Customer success manager

"frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", - "accepted_source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", + "current_source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", + "accepted_source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." diff --git a/examples/model-ui/b2b-renewal-risk/artifacts/gemma4-lms-judgmentkit-material-ui.html b/examples/model-ui/b2b-renewal-risk/artifacts/gemma4-lms-judgmentkit-material-ui.html index c65d13e..987455c 100644 --- a/examples/model-ui/b2b-renewal-risk/artifacts/gemma4-lms-judgmentkit-material-ui.html +++ b/examples/model-ui/b2b-renewal-risk/artifacts/gemma4-lms-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/b2b-renewal-risk/design-system-adapter.json", "capture_file": "captures/gemma4-lms-judgmentkit-material-ui.json", "source_context_sha256": "a483867d11be61bf08b4476245dee6142ebd2336536dd2df5d94f106ffc39d80", - "current_source_context_sha256": "0f3398c233558f666868db226e25746bed1ff05f87c6421b081e7b0303048a1b", + "current_source_context_sha256": "0751165bc2d4c96fb8e2b0359e750341737889389943b01647caaf36a25a4100", "source_context_status": "legacy_accepted", "model_response_summary": "Reviewing renewal risk for Northstar Labs due to champion change and missing procurement timing.", "frontend_context_status": "ready_for_frontend_implementation", @@ -358,7 +358,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "0f3398c233558f666868db226e25746bed1ff05f87c6421b081e7b0303048a1b", + "current_source_context_sha256": "0751165bc2d4c96fb8e2b0359e750341737889389943b01647caaf36a25a4100", "accepted_source_context_sha256": "a483867d11be61bf08b4476245dee6142ebd2336536dd2df5d94f106ffc39d80", "captured_source_context_sha256": "a483867d11be61bf08b4476245dee6142ebd2336536dd2df5d94f106ffc39d80", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/b2b-renewal-risk/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html b/examples/model-ui/b2b-renewal-risk/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html index a6cccb5..335fb2d 100644 --- a/examples/model-ui/b2b-renewal-risk/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/b2b-renewal-risk/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/b2b-renewal-risk/design-system-adapter.json", "capture_file": "captures/gpt55-xhigh-codex-judgmentkit-material-ui.json", "source_context_sha256": "3d993909500cc785a741819d4cf7058d5444a2773bbb5bd7249c80683e1b74ec", - "current_source_context_sha256": "6b254c14c1e25066fe57233c84b16e8ebfd2b71da449ae672e24ef285ff89a8e", + "current_source_context_sha256": "94e29bd92605feb1001c9290324130153d5ea2c0d23281fcc769951d616797a9", "source_context_status": "legacy_accepted", "model_response_summary": "Surface data represents the renewal risk review and handoff for Northstar Labs without exposing implementation details.", "frontend_context_status": "ready_for_frontend_implementation", @@ -352,7 +352,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "6b254c14c1e25066fe57233c84b16e8ebfd2b71da449ae672e24ef285ff89a8e", + "current_source_context_sha256": "94e29bd92605feb1001c9290324130153d5ea2c0d23281fcc769951d616797a9", "accepted_source_context_sha256": "3d993909500cc785a741819d4cf7058d5444a2773bbb5bd7249c80683e1b74ec", "captured_source_context_sha256": "3d993909500cc785a741819d4cf7058d5444a2773bbb5bd7249c80683e1b74ec", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html b/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html index 4e6b6f3..5f7e353 100644 --- a/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/b2b-renewal-risk/design-system-adapter.json", "capture_file": "captures/gpt56-sol-low-codex-judgmentkit-material-ui.json", "source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", - "current_source_context_sha256": "c2637a96d0fbc8cbfd0a6dd95699e66301fd936ba9b909fdf1e6a3b005c61db4", + "current_source_context_sha256": "f6d2452aa7665601f65225ce963086a7eaffabbccf7ead26a09eb93bcb158585", "source_context_status": "legacy_accepted", "model_response_summary": "A renewal risk workspace for reviewing account evidence, choosing the next path, and sending a clear handoff.", "frontend_context_status": "ready_for_frontend_implementation", @@ -365,7 +365,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "c2637a96d0fbc8cbfd0a6dd95699e66301fd936ba9b909fdf1e6a3b005c61db4", + "current_source_context_sha256": "f6d2452aa7665601f65225ce963086a7eaffabbccf7ead26a09eb93bcb158585", "accepted_source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", "captured_source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-low-codex-with-judgmentkit.html b/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-low-codex-with-judgmentkit.html index f0cb957..31d4af8 100644 --- a/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-low-codex-with-judgmentkit.html +++ b/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-low-codex-with-judgmentkit.html @@ -310,7 +310,7 @@ "design_system_adapter_file": null, "capture_file": "captures/gpt56-sol-low-codex-with-judgmentkit.json", "source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", - "current_source_context_sha256": "f2ab26e56aea5dd1faf1bbfc5b78c942a5eb7b81db338efa362aeca5104eda11", + "current_source_context_sha256": "39e9791d849b129aee5dd04ee32faf475a51af55859ecc1881f5b69e9bb1d4bd", "source_context_status": "legacy_accepted", "model_response_summary": "A static renewal risk workbench that keeps account evidence, the recommended decision, and the handoff action visible together.", "frontend_context_status": "ready_for_frontend_implementation", @@ -415,7 +415,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "f2ab26e56aea5dd1faf1bbfc5b78c942a5eb7b81db338efa362aeca5104eda11", + "current_source_context_sha256": "39e9791d849b129aee5dd04ee32faf475a51af55859ecc1881f5b69e9bb1d4bd", "accepted_source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", "captured_source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html b/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html index a38dd8a..1735f14 100644 --- a/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/b2b-renewal-risk/design-system-adapter.json", "capture_file": "captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json", "source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", - "current_source_context_sha256": "2a472eac5128251cd68de435997c0a8a5d1a57b8c0117c1a77495f3b587b7d00", + "current_source_context_sha256": "f0b94bbb4cda6df38a2153bf198e69b798c8fef514245f5aec688b9180990d43", "source_context_status": "legacy_accepted", "model_response_summary": "Review Northstar Labs’ renewal risk, resolve the missing procurement timeline, and send a clear handoff.", "frontend_context_status": "ready_for_frontend_implementation", @@ -365,7 +365,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "2a472eac5128251cd68de435997c0a8a5d1a57b8c0117c1a77495f3b587b7d00", + "current_source_context_sha256": "f0b94bbb4cda6df38a2153bf198e69b798c8fef514245f5aec688b9180990d43", "accepted_source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", "captured_source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html b/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html index 74d0cb0..dbb554e 100644 --- a/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html +++ b/examples/model-ui/b2b-renewal-risk/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html @@ -1049,7 +1049,7 @@

Renewal handoff

"design_system_adapter_file": null, "capture_file": "captures/gpt56-sol-ultra-codex-with-judgmentkit.json", "source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", - "current_source_context_sha256": "33806038a689c7a7b1d67e88de6363dc43e179579fe0749860b58488263e7ac1", + "current_source_context_sha256": "f8be82275e3fecbd9e17582246eb2290335fadcb8de9bc8c6b8285b9a18897ee", "source_context_status": "legacy_accepted", "model_response_summary": "A focused renewal-risk workbench coordinates account selection, evidence review, decision-making, and a ready-to-send handoff.", "frontend_context_status": "ready_for_frontend_implementation", @@ -1154,7 +1154,7 @@

Renewal handoff

"status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "33806038a689c7a7b1d67e88de6363dc43e179579fe0749860b58488263e7ac1", + "current_source_context_sha256": "f8be82275e3fecbd9e17582246eb2290335fadcb8de9bc8c6b8285b9a18897ee", "accepted_source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", "captured_source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/b2b-renewal-risk/captures/gemma4-lms-judgmentkit-material-ui.json b/examples/model-ui/b2b-renewal-risk/captures/gemma4-lms-judgmentkit-material-ui.json index 41e69cd..11084b1 100644 --- a/examples/model-ui/b2b-renewal-risk/captures/gemma4-lms-judgmentkit-material-ui.json +++ b/examples/model-ui/b2b-renewal-risk/captures/gemma4-lms-judgmentkit-material-ui.json @@ -154,7 +154,7 @@ "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "0f3398c233558f666868db226e25746bed1ff05f87c6421b081e7b0303048a1b", + "current_source_context_sha256": "0751165bc2d4c96fb8e2b0359e750341737889389943b01647caaf36a25a4100", "accepted_source_context_sha256": "a483867d11be61bf08b4476245dee6142ebd2336536dd2df5d94f106ffc39d80", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/b2b-renewal-risk/captures/gemma4-lms-with-judgmentkit.json b/examples/model-ui/b2b-renewal-risk/captures/gemma4-lms-with-judgmentkit.json index e5588d5..6bcca50 100644 --- a/examples/model-ui/b2b-renewal-risk/captures/gemma4-lms-with-judgmentkit.json +++ b/examples/model-ui/b2b-renewal-risk/captures/gemma4-lms-with-judgmentkit.json @@ -104,7 +104,7 @@ "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "a0eb7bd208c6f6a2bc2f1309917bb70b625746af48b54867d4f1133a3f5482ca", + "current_source_context_sha256": "8e6f36407d98ac6cc3a1c326cba8278550d65d3a430b84467f36e5c81408aedf", "accepted_source_context_sha256": "5d1e5717fdc17d7e0422bb9f6eb641de1e03547c26ca8eeeb37561b7a183fd2b", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/b2b-renewal-risk/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json b/examples/model-ui/b2b-renewal-risk/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json index ab3e448..6fb205c 100644 --- a/examples/model-ui/b2b-renewal-risk/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/b2b-renewal-risk/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json @@ -151,7 +151,7 @@ "stderr_sha256": "df2d285a3aa458b3bb044cdd0b792ce0f8dd3502d0e436c39e5a22ec95d9837f" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "6b254c14c1e25066fe57233c84b16e8ebfd2b71da449ae672e24ef285ff89a8e", + "current_source_context_sha256": "94e29bd92605feb1001c9290324130153d5ea2c0d23281fcc769951d616797a9", "accepted_source_context_sha256": "3d993909500cc785a741819d4cf7058d5444a2773bbb5bd7249c80683e1b74ec", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/b2b-renewal-risk/captures/gpt55-xhigh-codex-with-judgmentkit.json b/examples/model-ui/b2b-renewal-risk/captures/gpt55-xhigh-codex-with-judgmentkit.json index eab060b..c1178c0 100644 --- a/examples/model-ui/b2b-renewal-risk/captures/gpt55-xhigh-codex-with-judgmentkit.json +++ b/examples/model-ui/b2b-renewal-risk/captures/gpt55-xhigh-codex-with-judgmentkit.json @@ -98,7 +98,7 @@ "stderr_sha256": "2baaf58716cc4c62ca8e2c7c5d9a65f510c6d1029d6f1ecf0593aba9e4c60620" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "14c5b477d315ab9a4551b6c05f03664d2c8c0ab31806355977085fce8eb243f8", + "current_source_context_sha256": "2445001d697daf4349b3c36f1ec73623cc59865b32368d02046532c28d5b003c", "accepted_source_context_sha256": "5319d99de384b5d55dbfb29a610d9f485d614add68150d4af8aaf084dee3e2e6", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json b/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json index e2bbb88..f116e0c 100644 --- a/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "c2637a96d0fbc8cbfd0a6dd95699e66301fd936ba9b909fdf1e6a3b005c61db4", + "current_source_context_sha256": "f6d2452aa7665601f65225ce963086a7eaffabbccf7ead26a09eb93bcb158585", "accepted_source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "dacbe29639309319ffbbe09def3d5e0b2d5fc08cd8ec762a63435a0f75b0810f", diff --git a/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-low-codex-with-judgmentkit.json b/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-low-codex-with-judgmentkit.json index 6019029..fca63d3 100644 --- a/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-low-codex-with-judgmentkit.json +++ b/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-low-codex-with-judgmentkit.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "f2ab26e56aea5dd1faf1bbfc5b78c942a5eb7b81db338efa362aeca5104eda11", + "current_source_context_sha256": "39e9791d849b129aee5dd04ee32faf475a51af55859ecc1881f5b69e9bb1d4bd", "accepted_source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "b4f960f232df84e6997ffa42798136b6c31f52680a401903242965380066a59b", diff --git a/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json b/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json index eccdbec..36ca0c4 100644 --- a/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "2a472eac5128251cd68de435997c0a8a5d1a57b8c0117c1a77495f3b587b7d00", + "current_source_context_sha256": "f0b94bbb4cda6df38a2153bf198e69b798c8fef514245f5aec688b9180990d43", "accepted_source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "dacbe29639309319ffbbe09def3d5e0b2d5fc08cd8ec762a63435a0f75b0810f", diff --git a/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-ultra-codex-with-judgmentkit.json b/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-ultra-codex-with-judgmentkit.json index 6e2a65d..51401f9 100644 --- a/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-ultra-codex-with-judgmentkit.json +++ b/examples/model-ui/b2b-renewal-risk/captures/gpt56-sol-ultra-codex-with-judgmentkit.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "33806038a689c7a7b1d67e88de6363dc43e179579fe0749860b58488263e7ac1", + "current_source_context_sha256": "f8be82275e3fecbd9e17582246eb2290335fadcb8de9bc8c6b8285b9a18897ee", "accepted_source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "b4f960f232df84e6997ffa42798136b6c31f52680a401903242965380066a59b", diff --git a/examples/model-ui/b2b-renewal-risk/manifest.json b/examples/model-ui/b2b-renewal-risk/manifest.json index 163db15..0089bf4 100644 --- a/examples/model-ui/b2b-renewal-risk/manifest.json +++ b/examples/model-ui/b2b-renewal-risk/manifest.json @@ -194,8 +194,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", - "accepted_source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", + "current_source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", + "accepted_source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -204,8 +204,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", - "current_source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", + "source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", + "current_source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -396,8 +396,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", - "accepted_source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", + "current_source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", + "accepted_source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -406,8 +406,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", - "current_source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", + "source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", + "current_source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -851,7 +851,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "0f3398c233558f666868db226e25746bed1ff05f87c6421b081e7b0303048a1b", + "current_source_context_sha256": "0751165bc2d4c96fb8e2b0359e750341737889389943b01647caaf36a25a4100", "accepted_source_context_sha256": "a483867d11be61bf08b4476245dee6142ebd2336536dd2df5d94f106ffc39d80", "captured_source_context_sha256": "a483867d11be61bf08b4476245dee6142ebd2336536dd2df5d94f106ffc39d80", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -872,7 +872,7 @@ "capture_quality": null, "prompt_sha256": "676e6f2caaa558ccd0afc6bdd4c25882d31a36725c95340d98fd2ee864c11ed1", "source_context_sha256": "a483867d11be61bf08b4476245dee6142ebd2336536dd2df5d94f106ffc39d80", - "current_source_context_sha256": "0f3398c233558f666868db226e25746bed1ff05f87c6421b081e7b0303048a1b", + "current_source_context_sha256": "0751165bc2d4c96fb8e2b0359e750341737889389943b01647caaf36a25a4100", "source_context_status": "legacy_accepted", "raw_response_sha256": "1e142506c7d8b197e3db46f85e1532e607e7d9d3e47742a508a091a411634833", "frontend_context_status": "ready_for_frontend_implementation", @@ -1269,7 +1269,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "6b254c14c1e25066fe57233c84b16e8ebfd2b71da449ae672e24ef285ff89a8e", + "current_source_context_sha256": "94e29bd92605feb1001c9290324130153d5ea2c0d23281fcc769951d616797a9", "accepted_source_context_sha256": "3d993909500cc785a741819d4cf7058d5444a2773bbb5bd7249c80683e1b74ec", "captured_source_context_sha256": "3d993909500cc785a741819d4cf7058d5444a2773bbb5bd7249c80683e1b74ec", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -1284,7 +1284,7 @@ "capture_quality": null, "prompt_sha256": "28a6f8a440d7192bdcbf3eaa16b527e11bbf2a5d878df9d1e574ff6a385d947a", "source_context_sha256": "3d993909500cc785a741819d4cf7058d5444a2773bbb5bd7249c80683e1b74ec", - "current_source_context_sha256": "6b254c14c1e25066fe57233c84b16e8ebfd2b71da449ae672e24ef285ff89a8e", + "current_source_context_sha256": "94e29bd92605feb1001c9290324130153d5ea2c0d23281fcc769951d616797a9", "source_context_status": "legacy_accepted", "raw_response_sha256": "4c82bc627f1955c309c73762cb2b8a3dad6d625d6075ad5af3fc2d2e14d322e1", "frontend_context_status": "ready_for_frontend_implementation", @@ -2386,7 +2386,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "f2ab26e56aea5dd1faf1bbfc5b78c942a5eb7b81db338efa362aeca5104eda11", + "current_source_context_sha256": "39e9791d849b129aee5dd04ee32faf475a51af55859ecc1881f5b69e9bb1d4bd", "accepted_source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", "captured_source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -2428,7 +2428,7 @@ }, "prompt_sha256": "b4f960f232df84e6997ffa42798136b6c31f52680a401903242965380066a59b", "source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", - "current_source_context_sha256": "f2ab26e56aea5dd1faf1bbfc5b78c942a5eb7b81db338efa362aeca5104eda11", + "current_source_context_sha256": "39e9791d849b129aee5dd04ee32faf475a51af55859ecc1881f5b69e9bb1d4bd", "source_context_status": "legacy_accepted", "raw_response_sha256": "78c4fa6a9a18bd0748ca688e89b7d99aab12e9cd96d8e975c5f6b7191154e6a9", "frontend_context_status": "ready_for_frontend_implementation", @@ -2651,7 +2651,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "c2637a96d0fbc8cbfd0a6dd95699e66301fd936ba9b909fdf1e6a3b005c61db4", + "current_source_context_sha256": "f6d2452aa7665601f65225ce963086a7eaffabbccf7ead26a09eb93bcb158585", "accepted_source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", "captured_source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -2666,7 +2666,7 @@ "capture_quality": null, "prompt_sha256": "dacbe29639309319ffbbe09def3d5e0b2d5fc08cd8ec762a63435a0f75b0810f", "source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", - "current_source_context_sha256": "c2637a96d0fbc8cbfd0a6dd95699e66301fd936ba9b909fdf1e6a3b005c61db4", + "current_source_context_sha256": "f6d2452aa7665601f65225ce963086a7eaffabbccf7ead26a09eb93bcb158585", "source_context_status": "legacy_accepted", "raw_response_sha256": "3d8cc172085cb57837f56786d0b1830caa19046e7df0770f6e67e41613fe804f", "frontend_context_status": "ready_for_frontend_implementation", @@ -3649,7 +3649,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "33806038a689c7a7b1d67e88de6363dc43e179579fe0749860b58488263e7ac1", + "current_source_context_sha256": "f8be82275e3fecbd9e17582246eb2290335fadcb8de9bc8c6b8285b9a18897ee", "accepted_source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", "captured_source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -3691,7 +3691,7 @@ }, "prompt_sha256": "b4f960f232df84e6997ffa42798136b6c31f52680a401903242965380066a59b", "source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", - "current_source_context_sha256": "33806038a689c7a7b1d67e88de6363dc43e179579fe0749860b58488263e7ac1", + "current_source_context_sha256": "f8be82275e3fecbd9e17582246eb2290335fadcb8de9bc8c6b8285b9a18897ee", "source_context_status": "legacy_accepted", "raw_response_sha256": "0138e7fb3b07b4bef7fc2faf5efcc69981c09a43ea3fd7c51c27a3c214e894aa", "frontend_context_status": "ready_for_frontend_implementation", @@ -3914,7 +3914,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "2a472eac5128251cd68de435997c0a8a5d1a57b8c0117c1a77495f3b587b7d00", + "current_source_context_sha256": "f0b94bbb4cda6df38a2153bf198e69b798c8fef514245f5aec688b9180990d43", "accepted_source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", "captured_source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -3929,7 +3929,7 @@ "capture_quality": null, "prompt_sha256": "dacbe29639309319ffbbe09def3d5e0b2d5fc08cd8ec762a63435a0f75b0810f", "source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", - "current_source_context_sha256": "2a472eac5128251cd68de435997c0a8a5d1a57b8c0117c1a77495f3b587b7d00", + "current_source_context_sha256": "f0b94bbb4cda6df38a2153bf198e69b798c8fef514245f5aec688b9180990d43", "source_context_status": "legacy_accepted", "raw_response_sha256": "55fb5664fcbcec1d542a5cb72f7edad1fd6bc90f136b38aa0a98d04eba099615", "frontend_context_status": "ready_for_frontend_implementation", @@ -4168,8 +4168,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", - "accepted_source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", + "current_source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", + "accepted_source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -4178,8 +4178,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", - "current_source_context_sha256": "1f2bd44be6450750c0229660cee0a55a8df0a8f4d2097c529577cbee3f44dceb", + "source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", + "current_source_context_sha256": "1f96b82f90a2d4f131fee12308a65ffd84a3ca141f698457d44fc3b0d5626877", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -4370,8 +4370,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", - "accepted_source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", + "current_source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", + "accepted_source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -4380,8 +4380,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", - "current_source_context_sha256": "0ab25e08df0c3545f6a8fae6e692b876bcfdbcb211e1c624fe43c3a300a05b69", + "source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", + "current_source_context_sha256": "1cb20755474c94f775218dfb2bd0b1675c9f1c4697be7849e785c7796b4aa235", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -4771,7 +4771,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "0f3398c233558f666868db226e25746bed1ff05f87c6421b081e7b0303048a1b", + "current_source_context_sha256": "0751165bc2d4c96fb8e2b0359e750341737889389943b01647caaf36a25a4100", "accepted_source_context_sha256": "a483867d11be61bf08b4476245dee6142ebd2336536dd2df5d94f106ffc39d80", "captured_source_context_sha256": "a483867d11be61bf08b4476245dee6142ebd2336536dd2df5d94f106ffc39d80", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -4792,7 +4792,7 @@ "capture_quality": null, "prompt_sha256": "676e6f2caaa558ccd0afc6bdd4c25882d31a36725c95340d98fd2ee864c11ed1", "source_context_sha256": "a483867d11be61bf08b4476245dee6142ebd2336536dd2df5d94f106ffc39d80", - "current_source_context_sha256": "0f3398c233558f666868db226e25746bed1ff05f87c6421b081e7b0303048a1b", + "current_source_context_sha256": "0751165bc2d4c96fb8e2b0359e750341737889389943b01647caaf36a25a4100", "source_context_status": "legacy_accepted", "raw_response_sha256": "1e142506c7d8b197e3db46f85e1532e607e7d9d3e47742a508a091a411634833", "frontend_context_status": "ready_for_frontend_implementation", @@ -5135,7 +5135,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "6b254c14c1e25066fe57233c84b16e8ebfd2b71da449ae672e24ef285ff89a8e", + "current_source_context_sha256": "94e29bd92605feb1001c9290324130153d5ea2c0d23281fcc769951d616797a9", "accepted_source_context_sha256": "3d993909500cc785a741819d4cf7058d5444a2773bbb5bd7249c80683e1b74ec", "captured_source_context_sha256": "3d993909500cc785a741819d4cf7058d5444a2773bbb5bd7249c80683e1b74ec", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -5150,7 +5150,7 @@ "capture_quality": null, "prompt_sha256": "28a6f8a440d7192bdcbf3eaa16b527e11bbf2a5d878df9d1e574ff6a385d947a", "source_context_sha256": "3d993909500cc785a741819d4cf7058d5444a2773bbb5bd7249c80683e1b74ec", - "current_source_context_sha256": "6b254c14c1e25066fe57233c84b16e8ebfd2b71da449ae672e24ef285ff89a8e", + "current_source_context_sha256": "94e29bd92605feb1001c9290324130153d5ea2c0d23281fcc769951d616797a9", "source_context_status": "legacy_accepted", "raw_response_sha256": "4c82bc627f1955c309c73762cb2b8a3dad6d625d6075ad5af3fc2d2e14d322e1", "frontend_context_status": "ready_for_frontend_implementation", @@ -6199,7 +6199,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "f2ab26e56aea5dd1faf1bbfc5b78c942a5eb7b81db338efa362aeca5104eda11", + "current_source_context_sha256": "39e9791d849b129aee5dd04ee32faf475a51af55859ecc1881f5b69e9bb1d4bd", "accepted_source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", "captured_source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -6241,7 +6241,7 @@ }, "prompt_sha256": "b4f960f232df84e6997ffa42798136b6c31f52680a401903242965380066a59b", "source_context_sha256": "7c0d6ad669f0e49243b9c8b0885f608f6676e8f65d1fbe0044b9070611785059", - "current_source_context_sha256": "f2ab26e56aea5dd1faf1bbfc5b78c942a5eb7b81db338efa362aeca5104eda11", + "current_source_context_sha256": "39e9791d849b129aee5dd04ee32faf475a51af55859ecc1881f5b69e9bb1d4bd", "source_context_status": "legacy_accepted", "raw_response_sha256": "78c4fa6a9a18bd0748ca688e89b7d99aab12e9cd96d8e975c5f6b7191154e6a9", "frontend_context_status": "ready_for_frontend_implementation", @@ -6464,7 +6464,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "c2637a96d0fbc8cbfd0a6dd95699e66301fd936ba9b909fdf1e6a3b005c61db4", + "current_source_context_sha256": "f6d2452aa7665601f65225ce963086a7eaffabbccf7ead26a09eb93bcb158585", "accepted_source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", "captured_source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -6479,7 +6479,7 @@ "capture_quality": null, "prompt_sha256": "dacbe29639309319ffbbe09def3d5e0b2d5fc08cd8ec762a63435a0f75b0810f", "source_context_sha256": "f67900634ececbc18fb821fd9009f40bfc0f1abcc82517a2b2b16f81f9216d41", - "current_source_context_sha256": "c2637a96d0fbc8cbfd0a6dd95699e66301fd936ba9b909fdf1e6a3b005c61db4", + "current_source_context_sha256": "f6d2452aa7665601f65225ce963086a7eaffabbccf7ead26a09eb93bcb158585", "source_context_status": "legacy_accepted", "raw_response_sha256": "3d8cc172085cb57837f56786d0b1830caa19046e7df0770f6e67e41613fe804f", "frontend_context_status": "ready_for_frontend_implementation", @@ -7409,7 +7409,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "33806038a689c7a7b1d67e88de6363dc43e179579fe0749860b58488263e7ac1", + "current_source_context_sha256": "f8be82275e3fecbd9e17582246eb2290335fadcb8de9bc8c6b8285b9a18897ee", "accepted_source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", "captured_source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -7451,7 +7451,7 @@ }, "prompt_sha256": "b4f960f232df84e6997ffa42798136b6c31f52680a401903242965380066a59b", "source_context_sha256": "1c0a8acbe007c991e439172c7f8046ec041a488a955d6e8a9fb98151fcbb2511", - "current_source_context_sha256": "33806038a689c7a7b1d67e88de6363dc43e179579fe0749860b58488263e7ac1", + "current_source_context_sha256": "f8be82275e3fecbd9e17582246eb2290335fadcb8de9bc8c6b8285b9a18897ee", "source_context_status": "legacy_accepted", "raw_response_sha256": "0138e7fb3b07b4bef7fc2faf5efcc69981c09a43ea3fd7c51c27a3c214e894aa", "frontend_context_status": "ready_for_frontend_implementation", @@ -7674,7 +7674,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "2a472eac5128251cd68de435997c0a8a5d1a57b8c0117c1a77495f3b587b7d00", + "current_source_context_sha256": "f0b94bbb4cda6df38a2153bf198e69b798c8fef514245f5aec688b9180990d43", "accepted_source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", "captured_source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -7689,7 +7689,7 @@ "capture_quality": null, "prompt_sha256": "dacbe29639309319ffbbe09def3d5e0b2d5fc08cd8ec762a63435a0f75b0810f", "source_context_sha256": "6dc36afbd9e41b9b95eba576728dba0c74a0eb824efe442f2cff6cfdb78612f7", - "current_source_context_sha256": "2a472eac5128251cd68de435997c0a8a5d1a57b8c0117c1a77495f3b587b7d00", + "current_source_context_sha256": "f0b94bbb4cda6df38a2153bf198e69b798c8fef514245f5aec688b9180990d43", "source_context_status": "legacy_accepted", "raw_response_sha256": "55fb5664fcbcec1d542a5cb72f7edad1fd6bc90f136b38aa0a98d04eba099615", "frontend_context_status": "ready_for_frontend_implementation", @@ -7844,7 +7844,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "a0eb7bd208c6f6a2bc2f1309917bb70b625746af48b54867d4f1133a3f5482ca", + "current_source_context_sha256": "8e6f36407d98ac6cc3a1c326cba8278550d65d3a430b84467f36e5c81408aedf", "accepted_source_context_sha256": "5d1e5717fdc17d7e0422bb9f6eb641de1e03547c26ca8eeeb37561b7a183fd2b", "captured_source_context_sha256": "5d1e5717fdc17d7e0422bb9f6eb641de1e03547c26ca8eeeb37561b7a183fd2b", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -8014,7 +8014,7 @@ }, "prompt_sha256": "5913c0aefa4cb8e7f0a4b02123c475f9b97354499c431d2c1dab7f758b004fd9", "source_context_sha256": "5d1e5717fdc17d7e0422bb9f6eb641de1e03547c26ca8eeeb37561b7a183fd2b", - "current_source_context_sha256": "a0eb7bd208c6f6a2bc2f1309917bb70b625746af48b54867d4f1133a3f5482ca", + "current_source_context_sha256": "8e6f36407d98ac6cc3a1c326cba8278550d65d3a430b84467f36e5c81408aedf", "source_context_status": "legacy_accepted", "raw_response_sha256": "845fcfe112be39405ea6c52a3562f61b1a4255239b1ed4051c7e53aa21b5b04e", "frontend_context_status": "ready_for_frontend_implementation", @@ -8148,7 +8148,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "14c5b477d315ab9a4551b6c05f03664d2c8c0ab31806355977085fce8eb243f8", + "current_source_context_sha256": "2445001d697daf4349b3c36f1ec73623cc59865b32368d02046532c28d5b003c", "accepted_source_context_sha256": "5319d99de384b5d55dbfb29a610d9f485d614add68150d4af8aaf084dee3e2e6", "captured_source_context_sha256": "5319d99de384b5d55dbfb29a610d9f485d614add68150d4af8aaf084dee3e2e6", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -8427,7 +8427,7 @@ }, "prompt_sha256": "1ef623f60b5ebcab5539d35f7dd5b8ccf6f5a72b5b88be9f693b344f1028748b", "source_context_sha256": "5319d99de384b5d55dbfb29a610d9f485d614add68150d4af8aaf084dee3e2e6", - "current_source_context_sha256": "14c5b477d315ab9a4551b6c05f03664d2c8c0ab31806355977085fce8eb243f8", + "current_source_context_sha256": "2445001d697daf4349b3c36f1ec73623cc59865b32368d02046532c28d5b003c", "source_context_status": "legacy_accepted", "raw_response_sha256": "c501c96597eb006318cd53f04dc6b98c5b60b48edaf1cd59d7ca9ed44328f96e", "frontend_context_status": "ready_for_frontend_implementation", 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 dafaca3..786988e 100644 --- a/examples/model-ui/b2b-renewal-risk/reviewed-handoff.fixture.json +++ b/examples/model-ui/b2b-renewal-risk/reviewed-handoff.fixture.json @@ -1,5 +1,5 @@ { - "version": "0.7.0", + "version": "0.8.0", "contract_id": "judgmentkit.ai-ui-generation.activity-contract", "handoff_status": "ready_for_generation", "source": { diff --git a/examples/model-ui/clinical-intake-review/artifacts/deterministic-judgmentkit-material-ui.html b/examples/model-ui/clinical-intake-review/artifacts/deterministic-judgmentkit-material-ui.html index e7bcbe8..fdb94d9 100644 --- a/examples/model-ui/clinical-intake-review/artifacts/deterministic-judgmentkit-material-ui.html +++ b/examples/model-ui/clinical-intake-review/artifacts/deterministic-judgmentkit-material-ui.html @@ -286,8 +286,8 @@ "handoff_source": "examples/model-ui/clinical-intake-review/reviewed-handoff.fixture.json", "design_system_adapter_file": "examples/model-ui/clinical-intake-review/design-system-adapter.json", "capture_file": null, - "source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", - "current_source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", + "source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", + "current_source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", "source_context_status": "current", "model_response_summary": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -352,8 +352,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", - "accepted_source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", + "current_source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", + "accepted_source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." diff --git a/examples/model-ui/clinical-intake-review/artifacts/deterministic-with-judgmentkit.html b/examples/model-ui/clinical-intake-review/artifacts/deterministic-with-judgmentkit.html index 789e185..4f12b44 100644 --- a/examples/model-ui/clinical-intake-review/artifacts/deterministic-with-judgmentkit.html +++ b/examples/model-ui/clinical-intake-review/artifacts/deterministic-with-judgmentkit.html @@ -379,8 +379,8 @@

Intake coordinator

"handoff_source": "examples/model-ui/clinical-intake-review/reviewed-handoff.fixture.json", "design_system_adapter_file": null, "capture_file": null, - "source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", - "current_source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", + "source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", + "current_source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", "source_context_status": "current", "model_response_summary": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -445,8 +445,8 @@

Intake coordinator

"frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", - "accepted_source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", + "current_source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", + "accepted_source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." diff --git a/examples/model-ui/clinical-intake-review/artifacts/gemma4-lms-judgmentkit-material-ui.html b/examples/model-ui/clinical-intake-review/artifacts/gemma4-lms-judgmentkit-material-ui.html index 9016f41..39e6cae 100644 --- a/examples/model-ui/clinical-intake-review/artifacts/gemma4-lms-judgmentkit-material-ui.html +++ b/examples/model-ui/clinical-intake-review/artifacts/gemma4-lms-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/clinical-intake-review/design-system-adapter.json", "capture_file": "captures/gemma4-lms-judgmentkit-material-ui.json", "source_context_sha256": "427d6cfcfc237d754bded9f86484085a018c60dfdeec52fd60966d25bb87abd8", - "current_source_context_sha256": "cc9c21a461613e17afb21a2a9ee6284908176b6fb78a6cb0b8dfefac42acba0c", + "current_source_context_sha256": "c87af931c2fbcf7ac3bc8e3c35dc12708471e3b8ee47ef3490708489650e33b8", "source_context_status": "legacy_accepted", "model_response_summary": "The intake packet for Avery Morgan is currently blocked because signed consent is missing, requiring a return for documentation completion.", "frontend_context_status": "ready_for_frontend_implementation", @@ -358,7 +358,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "cc9c21a461613e17afb21a2a9ee6284908176b6fb78a6cb0b8dfefac42acba0c", + "current_source_context_sha256": "c87af931c2fbcf7ac3bc8e3c35dc12708471e3b8ee47ef3490708489650e33b8", "accepted_source_context_sha256": "427d6cfcfc237d754bded9f86484085a018c60dfdeec52fd60966d25bb87abd8", "captured_source_context_sha256": "427d6cfcfc237d754bded9f86484085a018c60dfdeec52fd60966d25bb87abd8", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/clinical-intake-review/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html b/examples/model-ui/clinical-intake-review/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html index d38581d..7675f4c 100644 --- a/examples/model-ui/clinical-intake-review/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/clinical-intake-review/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/clinical-intake-review/design-system-adapter.json", "capture_file": "captures/gpt55-xhigh-codex-judgmentkit-material-ui.json", "source_context_sha256": "2b52c4cc0a027463e719fab11a27679fc575d9ef48e5ed9505336d6f78582a81", - "current_source_context_sha256": "353bf425adc797c8c73baea3b96f12dd758bdab6d4ee6387b4074786b1b94c31", + "current_source_context_sha256": "e038aa886ba15747b88ea0fa018cf8dafc174f8f407e9e98c08f1c6007c3b796", "source_context_status": "legacy_accepted", "model_response_summary": "Administrative intake readiness data for returning Avery Morgan's packet for signed consent before scheduling.", "frontend_context_status": "ready_for_frontend_implementation", @@ -352,7 +352,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "353bf425adc797c8c73baea3b96f12dd758bdab6d4ee6387b4074786b1b94c31", + "current_source_context_sha256": "e038aa886ba15747b88ea0fa018cf8dafc174f8f407e9e98c08f1c6007c3b796", "accepted_source_context_sha256": "2b52c4cc0a027463e719fab11a27679fc575d9ef48e5ed9505336d6f78582a81", "captured_source_context_sha256": "2b52c4cc0a027463e719fab11a27679fc575d9ef48e5ed9505336d6f78582a81", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html b/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html index 4de52fd..4ab4405 100644 --- a/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/clinical-intake-review/design-system-adapter.json", "capture_file": "captures/gpt56-sol-low-codex-judgmentkit-material-ui.json", "source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", - "current_source_context_sha256": "c6d46991540cb871dd0537d2c77c1fda3549b92ea8cd1dc7e6a0d1a4b4aa2357", + "current_source_context_sha256": "ffbd83942c6366f1edade1f61a6af55244f8faf79f8eb6dae954b90cc3ab119e", "source_context_status": "legacy_accepted", "model_response_summary": "Return Avery Morgan’s intake packet for signed consent before scheduling and keep it in administrative review.", "frontend_context_status": "ready_for_frontend_implementation", @@ -365,7 +365,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "c6d46991540cb871dd0537d2c77c1fda3549b92ea8cd1dc7e6a0d1a4b4aa2357", + "current_source_context_sha256": "ffbd83942c6366f1edade1f61a6af55244f8faf79f8eb6dae954b90cc3ab119e", "accepted_source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", "captured_source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-low-codex-with-judgmentkit.html b/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-low-codex-with-judgmentkit.html index ffb614b..b339ce8 100644 --- a/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-low-codex-with-judgmentkit.html +++ b/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-low-codex-with-judgmentkit.html @@ -749,7 +749,7 @@

Administrative handoff

"design_system_adapter_file": null, "capture_file": "captures/gpt56-sol-low-codex-with-judgmentkit.json", "source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", - "current_source_context_sha256": "d241b5f3e097fde8f8a72108179015e498d187e00de03e78a9e843449cdc0796", + "current_source_context_sha256": "b030eea0106bfffaab2c4b4ca5c92a42790f812db1d19801ed86d7a4fea64a57", "source_context_status": "legacy_accepted", "model_response_summary": "A static administrative intake workspace that keeps the selected packet, readiness evidence, decision path, and handoff reason visible together.", "frontend_context_status": "ready_for_frontend_implementation", @@ -854,7 +854,7 @@

Administrative handoff

"status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d241b5f3e097fde8f8a72108179015e498d187e00de03e78a9e843449cdc0796", + "current_source_context_sha256": "b030eea0106bfffaab2c4b4ca5c92a42790f812db1d19801ed86d7a4fea64a57", "accepted_source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", "captured_source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html b/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html index e2b6436..6c2f97d 100644 --- a/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/clinical-intake-review/design-system-adapter.json", "capture_file": "captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json", "source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", - "current_source_context_sha256": "d0f9df477ecdd5c3cc8d7c83a6cb4f93ca240c46ce80a0c8508f9bc229f46593", + "current_source_context_sha256": "b58fae3c0c6f63d1ec0bcccf4d485bed65ad6717417fa96097dda58e53fa6070", "source_context_status": "legacy_accepted", "model_response_summary": "Avery Morgan’s intake packet should be returned for signed consent before scheduling.", "frontend_context_status": "ready_for_frontend_implementation", @@ -365,7 +365,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d0f9df477ecdd5c3cc8d7c83a6cb4f93ca240c46ce80a0c8508f9bc229f46593", + "current_source_context_sha256": "b58fae3c0c6f63d1ec0bcccf4d485bed65ad6717417fa96097dda58e53fa6070", "accepted_source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", "captured_source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html b/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html index 21ad37e..7903c8d 100644 --- a/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html +++ b/examples/model-ui/clinical-intake-review/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html @@ -310,7 +310,7 @@ "design_system_adapter_file": null, "capture_file": "captures/gpt56-sol-ultra-codex-with-judgmentkit.json", "source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", - "current_source_context_sha256": "b8d91c183a5309986f4c625667c89d57bd65fee6afbc333d356cc25c1c701639", + "current_source_context_sha256": "534ed8de8816de0ca216acdbb17af10edc68a07931ee72fad8e69cc9b9e1ab99", "source_context_status": "legacy_accepted", "model_response_summary": "A compact administrative intake workspace keeps the selected packet, readiness evidence, decision path, and handoff reason visible together.", "frontend_context_status": "ready_for_frontend_implementation", @@ -415,7 +415,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "b8d91c183a5309986f4c625667c89d57bd65fee6afbc333d356cc25c1c701639", + "current_source_context_sha256": "534ed8de8816de0ca216acdbb17af10edc68a07931ee72fad8e69cc9b9e1ab99", "accepted_source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", "captured_source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/clinical-intake-review/captures/gemma4-lms-judgmentkit-material-ui.json b/examples/model-ui/clinical-intake-review/captures/gemma4-lms-judgmentkit-material-ui.json index 65fbdf7..72610d4 100644 --- a/examples/model-ui/clinical-intake-review/captures/gemma4-lms-judgmentkit-material-ui.json +++ b/examples/model-ui/clinical-intake-review/captures/gemma4-lms-judgmentkit-material-ui.json @@ -154,7 +154,7 @@ "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "cc9c21a461613e17afb21a2a9ee6284908176b6fb78a6cb0b8dfefac42acba0c", + "current_source_context_sha256": "c87af931c2fbcf7ac3bc8e3c35dc12708471e3b8ee47ef3490708489650e33b8", "accepted_source_context_sha256": "427d6cfcfc237d754bded9f86484085a018c60dfdeec52fd60966d25bb87abd8", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/clinical-intake-review/captures/gemma4-lms-with-judgmentkit.json b/examples/model-ui/clinical-intake-review/captures/gemma4-lms-with-judgmentkit.json index 3418534..ef8a5ae 100644 --- a/examples/model-ui/clinical-intake-review/captures/gemma4-lms-with-judgmentkit.json +++ b/examples/model-ui/clinical-intake-review/captures/gemma4-lms-with-judgmentkit.json @@ -104,7 +104,7 @@ "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "0c16c2ce4ef4ec4a27011dd7765baa4ca8686cf7a379876066f1cb5363df283f", + "current_source_context_sha256": "8d55347c829a4b78a3cb5ae265c2bbb7f7012425945781a5a3926aeeb48131ed", "accepted_source_context_sha256": "e4e80c9871678bd848afcd9b9c8201a2c5dd6584a09ccd3f8c5982503cafd8cc", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/clinical-intake-review/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json b/examples/model-ui/clinical-intake-review/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json index d2e360f..d20abdd 100644 --- a/examples/model-ui/clinical-intake-review/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/clinical-intake-review/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json @@ -154,7 +154,7 @@ "stderr_sha256": "1cf59e9eef126dfab7d1f5eff4f6813a94fbc2ec0c891fb827f5bc8a86cbd30c" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "353bf425adc797c8c73baea3b96f12dd758bdab6d4ee6387b4074786b1b94c31", + "current_source_context_sha256": "e038aa886ba15747b88ea0fa018cf8dafc174f8f407e9e98c08f1c6007c3b796", "accepted_source_context_sha256": "2b52c4cc0a027463e719fab11a27679fc575d9ef48e5ed9505336d6f78582a81", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/clinical-intake-review/captures/gpt55-xhigh-codex-with-judgmentkit.json b/examples/model-ui/clinical-intake-review/captures/gpt55-xhigh-codex-with-judgmentkit.json index 8174856..c88317d 100644 --- a/examples/model-ui/clinical-intake-review/captures/gpt55-xhigh-codex-with-judgmentkit.json +++ b/examples/model-ui/clinical-intake-review/captures/gpt55-xhigh-codex-with-judgmentkit.json @@ -98,7 +98,7 @@ "stderr_sha256": "a77100b68bca748188fac5ed01bf089eea699467a40f0b24cb660fbc3c01d491" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "524c66d1a316404126ce53585a98a10e3102c7e73a48a8b7e02dd442c3d8c057", + "current_source_context_sha256": "7d9d92abbd614c6d248f0a775243e41d68eff3101ec4288864e721980332cd06", "accepted_source_context_sha256": "9a2b1f3d5413202e4c0493ef2b2c8f8c601882b7154faff164eb7e3a53234180", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/clinical-intake-review/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json b/examples/model-ui/clinical-intake-review/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json index fcd8ef0..37b4727 100644 --- a/examples/model-ui/clinical-intake-review/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/clinical-intake-review/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "c6d46991540cb871dd0537d2c77c1fda3549b92ea8cd1dc7e6a0d1a4b4aa2357", + "current_source_context_sha256": "ffbd83942c6366f1edade1f61a6af55244f8faf79f8eb6dae954b90cc3ab119e", "accepted_source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "454e7461718fe7212f1389dfad79798a07f20bec0fa84b0e96696f1ea524289c", diff --git a/examples/model-ui/clinical-intake-review/captures/gpt56-sol-low-codex-with-judgmentkit.json b/examples/model-ui/clinical-intake-review/captures/gpt56-sol-low-codex-with-judgmentkit.json index 36b7263..aa93c84 100644 --- a/examples/model-ui/clinical-intake-review/captures/gpt56-sol-low-codex-with-judgmentkit.json +++ b/examples/model-ui/clinical-intake-review/captures/gpt56-sol-low-codex-with-judgmentkit.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d241b5f3e097fde8f8a72108179015e498d187e00de03e78a9e843449cdc0796", + "current_source_context_sha256": "b030eea0106bfffaab2c4b4ca5c92a42790f812db1d19801ed86d7a4fea64a57", "accepted_source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "0240434a93c2ae970cb00ca8ef4a0d068a169b65fdb6292805d0bf065e2943cb", diff --git a/examples/model-ui/clinical-intake-review/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json b/examples/model-ui/clinical-intake-review/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json index 382be4c..96aa1c1 100644 --- a/examples/model-ui/clinical-intake-review/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/clinical-intake-review/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d0f9df477ecdd5c3cc8d7c83a6cb4f93ca240c46ce80a0c8508f9bc229f46593", + "current_source_context_sha256": "b58fae3c0c6f63d1ec0bcccf4d485bed65ad6717417fa96097dda58e53fa6070", "accepted_source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "454e7461718fe7212f1389dfad79798a07f20bec0fa84b0e96696f1ea524289c", diff --git a/examples/model-ui/clinical-intake-review/captures/gpt56-sol-ultra-codex-with-judgmentkit.json b/examples/model-ui/clinical-intake-review/captures/gpt56-sol-ultra-codex-with-judgmentkit.json index a41d0c9..4fbdcdd 100644 --- a/examples/model-ui/clinical-intake-review/captures/gpt56-sol-ultra-codex-with-judgmentkit.json +++ b/examples/model-ui/clinical-intake-review/captures/gpt56-sol-ultra-codex-with-judgmentkit.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "b8d91c183a5309986f4c625667c89d57bd65fee6afbc333d356cc25c1c701639", + "current_source_context_sha256": "534ed8de8816de0ca216acdbb17af10edc68a07931ee72fad8e69cc9b9e1ab99", "accepted_source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "0240434a93c2ae970cb00ca8ef4a0d068a169b65fdb6292805d0bf065e2943cb", diff --git a/examples/model-ui/clinical-intake-review/manifest.json b/examples/model-ui/clinical-intake-review/manifest.json index 5738838..4a2b61d 100644 --- a/examples/model-ui/clinical-intake-review/manifest.json +++ b/examples/model-ui/clinical-intake-review/manifest.json @@ -194,8 +194,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", - "accepted_source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", + "current_source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", + "accepted_source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -204,8 +204,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", - "current_source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", + "source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", + "current_source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -396,8 +396,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", - "accepted_source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", + "current_source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", + "accepted_source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -406,8 +406,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", - "current_source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", + "source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", + "current_source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -851,7 +851,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "cc9c21a461613e17afb21a2a9ee6284908176b6fb78a6cb0b8dfefac42acba0c", + "current_source_context_sha256": "c87af931c2fbcf7ac3bc8e3c35dc12708471e3b8ee47ef3490708489650e33b8", "accepted_source_context_sha256": "427d6cfcfc237d754bded9f86484085a018c60dfdeec52fd60966d25bb87abd8", "captured_source_context_sha256": "427d6cfcfc237d754bded9f86484085a018c60dfdeec52fd60966d25bb87abd8", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -872,7 +872,7 @@ "capture_quality": null, "prompt_sha256": "cad3f77b87b0404e2e9897d56b9fb7480dafb4e1dd47fae165199c45b4b01c30", "source_context_sha256": "427d6cfcfc237d754bded9f86484085a018c60dfdeec52fd60966d25bb87abd8", - "current_source_context_sha256": "cc9c21a461613e17afb21a2a9ee6284908176b6fb78a6cb0b8dfefac42acba0c", + "current_source_context_sha256": "c87af931c2fbcf7ac3bc8e3c35dc12708471e3b8ee47ef3490708489650e33b8", "source_context_status": "legacy_accepted", "raw_response_sha256": "79720afd4bef165ee825344d7a677a8705df7cde6218a29e3925a21344cc3b71", "frontend_context_status": "ready_for_frontend_implementation", @@ -1269,7 +1269,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "353bf425adc797c8c73baea3b96f12dd758bdab6d4ee6387b4074786b1b94c31", + "current_source_context_sha256": "e038aa886ba15747b88ea0fa018cf8dafc174f8f407e9e98c08f1c6007c3b796", "accepted_source_context_sha256": "2b52c4cc0a027463e719fab11a27679fc575d9ef48e5ed9505336d6f78582a81", "captured_source_context_sha256": "2b52c4cc0a027463e719fab11a27679fc575d9ef48e5ed9505336d6f78582a81", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -1284,7 +1284,7 @@ "capture_quality": null, "prompt_sha256": "e97eec0233a651abde75a913160c34f301dc9626146d82365e318fba495a52a7", "source_context_sha256": "2b52c4cc0a027463e719fab11a27679fc575d9ef48e5ed9505336d6f78582a81", - "current_source_context_sha256": "353bf425adc797c8c73baea3b96f12dd758bdab6d4ee6387b4074786b1b94c31", + "current_source_context_sha256": "e038aa886ba15747b88ea0fa018cf8dafc174f8f407e9e98c08f1c6007c3b796", "source_context_status": "legacy_accepted", "raw_response_sha256": "718847ce36f037582caeb264b28e8c6a55b8a9ea852023db4708ccd7aac37ffc", "frontend_context_status": "ready_for_frontend_implementation", @@ -2434,7 +2434,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d241b5f3e097fde8f8a72108179015e498d187e00de03e78a9e843449cdc0796", + "current_source_context_sha256": "b030eea0106bfffaab2c4b4ca5c92a42790f812db1d19801ed86d7a4fea64a57", "accepted_source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", "captured_source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -2476,7 +2476,7 @@ }, "prompt_sha256": "0240434a93c2ae970cb00ca8ef4a0d068a169b65fdb6292805d0bf065e2943cb", "source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", - "current_source_context_sha256": "d241b5f3e097fde8f8a72108179015e498d187e00de03e78a9e843449cdc0796", + "current_source_context_sha256": "b030eea0106bfffaab2c4b4ca5c92a42790f812db1d19801ed86d7a4fea64a57", "source_context_status": "legacy_accepted", "raw_response_sha256": "4d5b1b2b62ac9ad797ce02b829e8e27a18d6e54cec73e2dea649b6883201a10c", "frontend_context_status": "ready_for_frontend_implementation", @@ -2699,7 +2699,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "c6d46991540cb871dd0537d2c77c1fda3549b92ea8cd1dc7e6a0d1a4b4aa2357", + "current_source_context_sha256": "ffbd83942c6366f1edade1f61a6af55244f8faf79f8eb6dae954b90cc3ab119e", "accepted_source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", "captured_source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -2714,7 +2714,7 @@ "capture_quality": null, "prompt_sha256": "454e7461718fe7212f1389dfad79798a07f20bec0fa84b0e96696f1ea524289c", "source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", - "current_source_context_sha256": "c6d46991540cb871dd0537d2c77c1fda3549b92ea8cd1dc7e6a0d1a4b4aa2357", + "current_source_context_sha256": "ffbd83942c6366f1edade1f61a6af55244f8faf79f8eb6dae954b90cc3ab119e", "source_context_status": "legacy_accepted", "raw_response_sha256": "d68db4a66cf8826b79adf000e0a75259304432e0cf477c648c46e91fbae98198", "frontend_context_status": "ready_for_frontend_implementation", @@ -2921,7 +2921,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "b8d91c183a5309986f4c625667c89d57bd65fee6afbc333d356cc25c1c701639", + "current_source_context_sha256": "534ed8de8816de0ca216acdbb17af10edc68a07931ee72fad8e69cc9b9e1ab99", "accepted_source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", "captured_source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -2963,7 +2963,7 @@ }, "prompt_sha256": "0240434a93c2ae970cb00ca8ef4a0d068a169b65fdb6292805d0bf065e2943cb", "source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", - "current_source_context_sha256": "b8d91c183a5309986f4c625667c89d57bd65fee6afbc333d356cc25c1c701639", + "current_source_context_sha256": "534ed8de8816de0ca216acdbb17af10edc68a07931ee72fad8e69cc9b9e1ab99", "source_context_status": "legacy_accepted", "raw_response_sha256": "6e4b471e674dbbbbc915680f03f99d590fd6a9292accc44b0daa5a1b2ee99271", "frontend_context_status": "ready_for_frontend_implementation", @@ -3186,7 +3186,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d0f9df477ecdd5c3cc8d7c83a6cb4f93ca240c46ce80a0c8508f9bc229f46593", + "current_source_context_sha256": "b58fae3c0c6f63d1ec0bcccf4d485bed65ad6717417fa96097dda58e53fa6070", "accepted_source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", "captured_source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -3201,7 +3201,7 @@ "capture_quality": null, "prompt_sha256": "454e7461718fe7212f1389dfad79798a07f20bec0fa84b0e96696f1ea524289c", "source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", - "current_source_context_sha256": "d0f9df477ecdd5c3cc8d7c83a6cb4f93ca240c46ce80a0c8508f9bc229f46593", + "current_source_context_sha256": "b58fae3c0c6f63d1ec0bcccf4d485bed65ad6717417fa96097dda58e53fa6070", "source_context_status": "legacy_accepted", "raw_response_sha256": "02d096219129901782280d8ba59522ba9c88024e19f680bc44816991e5797244", "frontend_context_status": "ready_for_frontend_implementation", @@ -3440,8 +3440,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", - "accepted_source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", + "current_source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", + "accepted_source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -3450,8 +3450,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", - "current_source_context_sha256": "192582791a3561c1020f7417ea77ccef24796a34313aa52c8f907af7d2cf3709", + "source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", + "current_source_context_sha256": "d42318842c92259c7967a9aaaa2326053ed3fbef914a53d7e869b3073471f11d", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -3642,8 +3642,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", - "accepted_source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", + "current_source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", + "accepted_source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -3652,8 +3652,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", - "current_source_context_sha256": "2c2f9b35475f409b733c8463776ab13681aa1bb6f790a8487c8f2367c2940ab5", + "source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", + "current_source_context_sha256": "4e5dc4bccab4d4f2427bee09d4df671aaa203af357fe0628a2ccbbe35e47d8e7", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -4043,7 +4043,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "cc9c21a461613e17afb21a2a9ee6284908176b6fb78a6cb0b8dfefac42acba0c", + "current_source_context_sha256": "c87af931c2fbcf7ac3bc8e3c35dc12708471e3b8ee47ef3490708489650e33b8", "accepted_source_context_sha256": "427d6cfcfc237d754bded9f86484085a018c60dfdeec52fd60966d25bb87abd8", "captured_source_context_sha256": "427d6cfcfc237d754bded9f86484085a018c60dfdeec52fd60966d25bb87abd8", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -4064,7 +4064,7 @@ "capture_quality": null, "prompt_sha256": "cad3f77b87b0404e2e9897d56b9fb7480dafb4e1dd47fae165199c45b4b01c30", "source_context_sha256": "427d6cfcfc237d754bded9f86484085a018c60dfdeec52fd60966d25bb87abd8", - "current_source_context_sha256": "cc9c21a461613e17afb21a2a9ee6284908176b6fb78a6cb0b8dfefac42acba0c", + "current_source_context_sha256": "c87af931c2fbcf7ac3bc8e3c35dc12708471e3b8ee47ef3490708489650e33b8", "source_context_status": "legacy_accepted", "raw_response_sha256": "79720afd4bef165ee825344d7a677a8705df7cde6218a29e3925a21344cc3b71", "frontend_context_status": "ready_for_frontend_implementation", @@ -4407,7 +4407,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "353bf425adc797c8c73baea3b96f12dd758bdab6d4ee6387b4074786b1b94c31", + "current_source_context_sha256": "e038aa886ba15747b88ea0fa018cf8dafc174f8f407e9e98c08f1c6007c3b796", "accepted_source_context_sha256": "2b52c4cc0a027463e719fab11a27679fc575d9ef48e5ed9505336d6f78582a81", "captured_source_context_sha256": "2b52c4cc0a027463e719fab11a27679fc575d9ef48e5ed9505336d6f78582a81", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -4422,7 +4422,7 @@ "capture_quality": null, "prompt_sha256": "e97eec0233a651abde75a913160c34f301dc9626146d82365e318fba495a52a7", "source_context_sha256": "2b52c4cc0a027463e719fab11a27679fc575d9ef48e5ed9505336d6f78582a81", - "current_source_context_sha256": "353bf425adc797c8c73baea3b96f12dd758bdab6d4ee6387b4074786b1b94c31", + "current_source_context_sha256": "e038aa886ba15747b88ea0fa018cf8dafc174f8f407e9e98c08f1c6007c3b796", "source_context_status": "legacy_accepted", "raw_response_sha256": "718847ce36f037582caeb264b28e8c6a55b8a9ea852023db4708ccd7aac37ffc", "frontend_context_status": "ready_for_frontend_implementation", @@ -5519,7 +5519,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d241b5f3e097fde8f8a72108179015e498d187e00de03e78a9e843449cdc0796", + "current_source_context_sha256": "b030eea0106bfffaab2c4b4ca5c92a42790f812db1d19801ed86d7a4fea64a57", "accepted_source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", "captured_source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -5561,7 +5561,7 @@ }, "prompt_sha256": "0240434a93c2ae970cb00ca8ef4a0d068a169b65fdb6292805d0bf065e2943cb", "source_context_sha256": "1ebfb3c6c933b2cc373f90ce8c501b9b21cbe70b00dbead8393d77e00a504bfb", - "current_source_context_sha256": "d241b5f3e097fde8f8a72108179015e498d187e00de03e78a9e843449cdc0796", + "current_source_context_sha256": "b030eea0106bfffaab2c4b4ca5c92a42790f812db1d19801ed86d7a4fea64a57", "source_context_status": "legacy_accepted", "raw_response_sha256": "4d5b1b2b62ac9ad797ce02b829e8e27a18d6e54cec73e2dea649b6883201a10c", "frontend_context_status": "ready_for_frontend_implementation", @@ -5784,7 +5784,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "c6d46991540cb871dd0537d2c77c1fda3549b92ea8cd1dc7e6a0d1a4b4aa2357", + "current_source_context_sha256": "ffbd83942c6366f1edade1f61a6af55244f8faf79f8eb6dae954b90cc3ab119e", "accepted_source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", "captured_source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -5799,7 +5799,7 @@ "capture_quality": null, "prompt_sha256": "454e7461718fe7212f1389dfad79798a07f20bec0fa84b0e96696f1ea524289c", "source_context_sha256": "c99cc6818fddd0756bcd3ab25087b1bff00a7c2305dc3a27badcadae5683b2e4", - "current_source_context_sha256": "c6d46991540cb871dd0537d2c77c1fda3549b92ea8cd1dc7e6a0d1a4b4aa2357", + "current_source_context_sha256": "ffbd83942c6366f1edade1f61a6af55244f8faf79f8eb6dae954b90cc3ab119e", "source_context_status": "legacy_accepted", "raw_response_sha256": "d68db4a66cf8826b79adf000e0a75259304432e0cf477c648c46e91fbae98198", "frontend_context_status": "ready_for_frontend_implementation", @@ -5952,7 +5952,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "b8d91c183a5309986f4c625667c89d57bd65fee6afbc333d356cc25c1c701639", + "current_source_context_sha256": "534ed8de8816de0ca216acdbb17af10edc68a07931ee72fad8e69cc9b9e1ab99", "accepted_source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", "captured_source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -5994,7 +5994,7 @@ }, "prompt_sha256": "0240434a93c2ae970cb00ca8ef4a0d068a169b65fdb6292805d0bf065e2943cb", "source_context_sha256": "a4d8b09c8e706cc16330b6f535db0dfb78efb0c5089a89b59ab429d04a855707", - "current_source_context_sha256": "b8d91c183a5309986f4c625667c89d57bd65fee6afbc333d356cc25c1c701639", + "current_source_context_sha256": "534ed8de8816de0ca216acdbb17af10edc68a07931ee72fad8e69cc9b9e1ab99", "source_context_status": "legacy_accepted", "raw_response_sha256": "6e4b471e674dbbbbc915680f03f99d590fd6a9292accc44b0daa5a1b2ee99271", "frontend_context_status": "ready_for_frontend_implementation", @@ -6217,7 +6217,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d0f9df477ecdd5c3cc8d7c83a6cb4f93ca240c46ce80a0c8508f9bc229f46593", + "current_source_context_sha256": "b58fae3c0c6f63d1ec0bcccf4d485bed65ad6717417fa96097dda58e53fa6070", "accepted_source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", "captured_source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -6232,7 +6232,7 @@ "capture_quality": null, "prompt_sha256": "454e7461718fe7212f1389dfad79798a07f20bec0fa84b0e96696f1ea524289c", "source_context_sha256": "a94bedc2a5a4d64fb02c35be8bbe31c45dd84a3e5691f4c3e1a4756a8770a5f1", - "current_source_context_sha256": "d0f9df477ecdd5c3cc8d7c83a6cb4f93ca240c46ce80a0c8508f9bc229f46593", + "current_source_context_sha256": "b58fae3c0c6f63d1ec0bcccf4d485bed65ad6717417fa96097dda58e53fa6070", "source_context_status": "legacy_accepted", "raw_response_sha256": "02d096219129901782280d8ba59522ba9c88024e19f680bc44816991e5797244", "frontend_context_status": "ready_for_frontend_implementation", @@ -6387,7 +6387,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "0c16c2ce4ef4ec4a27011dd7765baa4ca8686cf7a379876066f1cb5363df283f", + "current_source_context_sha256": "8d55347c829a4b78a3cb5ae265c2bbb7f7012425945781a5a3926aeeb48131ed", "accepted_source_context_sha256": "e4e80c9871678bd848afcd9b9c8201a2c5dd6584a09ccd3f8c5982503cafd8cc", "captured_source_context_sha256": "e4e80c9871678bd848afcd9b9c8201a2c5dd6584a09ccd3f8c5982503cafd8cc", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -6581,7 +6581,7 @@ }, "prompt_sha256": "a91777caa6325dd33080cf00ad3fd21324463b48ee1885b46b5bd1c64c68c2cf", "source_context_sha256": "e4e80c9871678bd848afcd9b9c8201a2c5dd6584a09ccd3f8c5982503cafd8cc", - "current_source_context_sha256": "0c16c2ce4ef4ec4a27011dd7765baa4ca8686cf7a379876066f1cb5363df283f", + "current_source_context_sha256": "8d55347c829a4b78a3cb5ae265c2bbb7f7012425945781a5a3926aeeb48131ed", "source_context_status": "legacy_accepted", "raw_response_sha256": "8cecff6cd10655fd28c0cd880795efa5739bed1158188cddf8e6c09a09919764", "frontend_context_status": "ready_for_frontend_implementation", @@ -6715,7 +6715,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "524c66d1a316404126ce53585a98a10e3102c7e73a48a8b7e02dd442c3d8c057", + "current_source_context_sha256": "7d9d92abbd614c6d248f0a775243e41d68eff3101ec4288864e721980332cd06", "accepted_source_context_sha256": "9a2b1f3d5413202e4c0493ef2b2c8f8c601882b7154faff164eb7e3a53234180", "captured_source_context_sha256": "9a2b1f3d5413202e4c0493ef2b2c8f8c601882b7154faff164eb7e3a53234180", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -7263,7 +7263,7 @@ }, "prompt_sha256": "b15808546b4dc9da234b29e697470794368e0deb298cf9a40582c4843572335e", "source_context_sha256": "9a2b1f3d5413202e4c0493ef2b2c8f8c601882b7154faff164eb7e3a53234180", - "current_source_context_sha256": "524c66d1a316404126ce53585a98a10e3102c7e73a48a8b7e02dd442c3d8c057", + "current_source_context_sha256": "7d9d92abbd614c6d248f0a775243e41d68eff3101ec4288864e721980332cd06", "source_context_status": "legacy_accepted", "raw_response_sha256": "aa03e621c0fdbe5f3b786d51100bdd815042013c1ec0693130c682c74e9c60f3", "frontend_context_status": "ready_for_frontend_implementation", 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 7169889..a91850a 100644 --- a/examples/model-ui/clinical-intake-review/reviewed-handoff.fixture.json +++ b/examples/model-ui/clinical-intake-review/reviewed-handoff.fixture.json @@ -1,5 +1,5 @@ { - "version": "0.7.0", + "version": "0.8.0", "contract_id": "judgmentkit.ai-ui-generation.activity-contract", "handoff_status": "ready_for_generation", "source": { diff --git a/examples/model-ui/field-service-dispatch/artifacts/deterministic-judgmentkit-material-ui.html b/examples/model-ui/field-service-dispatch/artifacts/deterministic-judgmentkit-material-ui.html index bc6696d..e78efa6 100644 --- a/examples/model-ui/field-service-dispatch/artifacts/deterministic-judgmentkit-material-ui.html +++ b/examples/model-ui/field-service-dispatch/artifacts/deterministic-judgmentkit-material-ui.html @@ -286,8 +286,8 @@ "handoff_source": "examples/model-ui/field-service-dispatch/reviewed-handoff.fixture.json", "design_system_adapter_file": "examples/model-ui/field-service-dispatch/design-system-adapter.json", "capture_file": null, - "source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", - "current_source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", + "source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", + "current_source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", "source_context_status": "current", "model_response_summary": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -352,8 +352,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", - "accepted_source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", + "current_source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", + "accepted_source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." diff --git a/examples/model-ui/field-service-dispatch/artifacts/deterministic-with-judgmentkit.html b/examples/model-ui/field-service-dispatch/artifacts/deterministic-with-judgmentkit.html index e4bc09f..9fcfe3d 100644 --- a/examples/model-ui/field-service-dispatch/artifacts/deterministic-with-judgmentkit.html +++ b/examples/model-ui/field-service-dispatch/artifacts/deterministic-with-judgmentkit.html @@ -379,8 +379,8 @@

Dispatch support

"handoff_source": "examples/model-ui/field-service-dispatch/reviewed-handoff.fixture.json", "design_system_adapter_file": null, "capture_file": null, - "source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", - "current_source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", + "source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", + "current_source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", "source_context_status": "current", "model_response_summary": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -445,8 +445,8 @@

Dispatch support

"frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", - "accepted_source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", + "current_source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", + "accepted_source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." diff --git a/examples/model-ui/field-service-dispatch/artifacts/gemma4-lms-judgmentkit-material-ui.html b/examples/model-ui/field-service-dispatch/artifacts/gemma4-lms-judgmentkit-material-ui.html index 613ca0b..bee1377 100644 --- a/examples/model-ui/field-service-dispatch/artifacts/gemma4-lms-judgmentkit-material-ui.html +++ b/examples/model-ui/field-service-dispatch/artifacts/gemma4-lms-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/field-service-dispatch/design-system-adapter.json", "capture_file": "captures/gemma4-lms-judgmentkit-material-ui.json", "source_context_sha256": "f2b04bf482eece25137b6269bb85fda5e6731c84c86fd57cba30878e038a4437", - "current_source_context_sha256": "4cb7db5a0a4c8e43993f3e3c8bab098fdf266afe231dfd04a27a11097a69c874", + "current_source_context_sha256": "f227470f13ed80d2316c002c3d332ca61481006b67b38e0018b28322bf1d9a06", "source_context_status": "legacy_accepted", "model_response_summary": "A parts check is required for visit V-2187 Mallory Chen because the necessary gate code is missing before assignment can be completed.", "frontend_context_status": "ready_for_frontend_implementation", @@ -358,7 +358,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "4cb7db5a0a4c8e43993f3e3c8bab098fdf266afe231dfd04a27a11097a69c874", + "current_source_context_sha256": "f227470f13ed80d2316c002c3d332ca61481006b67b38e0018b28322bf1d9a06", "accepted_source_context_sha256": "f2b04bf482eece25137b6269bb85fda5e6731c84c86fd57cba30878e038a4437", "captured_source_context_sha256": "f2b04bf482eece25137b6269bb85fda5e6731c84c86fd57cba30878e038a4437", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/field-service-dispatch/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html b/examples/model-ui/field-service-dispatch/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html index 63871a4..821696f 100644 --- a/examples/model-ui/field-service-dispatch/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/field-service-dispatch/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/field-service-dispatch/design-system-adapter.json", "capture_file": "captures/gpt55-xhigh-codex-judgmentkit-material-ui.json", "source_context_sha256": "5916d8bcbdef11f6f948873f3cf4a6a316d031628a15a9cf3047412190639136", - "current_source_context_sha256": "505dab25c7b36e8ce23a278c38e88b0a683f4548a36a4e7c2f3710e0607ab527", + "current_source_context_sha256": "6013725d108e285b15c59aa22e77f1e18e88fe72cb40bd24aa6b5cc54c705b98", "source_context_status": "legacy_accepted", "model_response_summary": "A dispatch review surface helps a field operations manager choose the next same-day repair visit action and prepare a dispatch handoff.", "frontend_context_status": "ready_for_frontend_implementation", @@ -352,7 +352,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "505dab25c7b36e8ce23a278c38e88b0a683f4548a36a4e7c2f3710e0607ab527", + "current_source_context_sha256": "6013725d108e285b15c59aa22e77f1e18e88fe72cb40bd24aa6b5cc54c705b98", "accepted_source_context_sha256": "5916d8bcbdef11f6f948873f3cf4a6a316d031628a15a9cf3047412190639136", "captured_source_context_sha256": "5916d8bcbdef11f6f948873f3cf4a6a316d031628a15a9cf3047412190639136", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html b/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html index 796c065..b4f16c1 100644 --- a/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/field-service-dispatch/design-system-adapter.json", "capture_file": "captures/gpt56-sol-low-codex-judgmentkit-material-ui.json", "source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", - "current_source_context_sha256": "d30eb3daf9f3d4b8aac786ab658e9c590072a769f7c3b6f2bf00fb4d05522cc4", + "current_source_context_sha256": "fb191b73ad9a3db0b190d13788fd20a33068c669ed5834e7b967af5dc6fea3a2", "source_context_status": "legacy_accepted", "model_response_summary": "Review the selected repair visit, request the missing gate code, and assign the qualified technician within the SLA window.", "frontend_context_status": "ready_for_frontend_implementation", @@ -365,7 +365,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d30eb3daf9f3d4b8aac786ab658e9c590072a769f7c3b6f2bf00fb4d05522cc4", + "current_source_context_sha256": "fb191b73ad9a3db0b190d13788fd20a33068c669ed5834e7b967af5dc6fea3a2", "accepted_source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", "captured_source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-low-codex-with-judgmentkit.html b/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-low-codex-with-judgmentkit.html index e11bfa5..0444b62 100644 --- a/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-low-codex-with-judgmentkit.html +++ b/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-low-codex-with-judgmentkit.html @@ -310,7 +310,7 @@ "design_system_adapter_file": null, "capture_file": "captures/gpt56-sol-low-codex-with-judgmentkit.json", "source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", - "current_source_context_sha256": "907bb6cd657fd8a2ee5145ecfd425f0a4b9dd11cb1ffc09200563b6da1ffcc0c", + "current_source_context_sha256": "6ec3c387ee64d24b73d5697d063cee223a99e1d973fdb60068b6429af1b65735", "source_context_status": "legacy_accepted", "model_response_summary": "A static dispatch workbench keeps the active repair visit, readiness evidence, decision paths, and next handoff visible in one coordinated view.", "frontend_context_status": "ready_for_frontend_implementation", @@ -415,7 +415,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "907bb6cd657fd8a2ee5145ecfd425f0a4b9dd11cb1ffc09200563b6da1ffcc0c", + "current_source_context_sha256": "6ec3c387ee64d24b73d5697d063cee223a99e1d973fdb60068b6429af1b65735", "accepted_source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", "captured_source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html b/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html index b68fc6c..d522c0a 100644 --- a/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/field-service-dispatch/design-system-adapter.json", "capture_file": "captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json", "source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", - "current_source_context_sha256": "6aa62dcb25a52d342de421b88f0f5e21a2a0000799972b1110d719cd2b2df998", + "current_source_context_sha256": "6ebe3119910ea6b07ce3486e8c5b62da011e5e0415a01e9024e579a136b1dc19", "source_context_status": "legacy_accepted", "model_response_summary": "Review same-day repair readiness, choose the dispatch path, and send a clear handoff.", "frontend_context_status": "ready_for_frontend_implementation", @@ -365,7 +365,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "6aa62dcb25a52d342de421b88f0f5e21a2a0000799972b1110d719cd2b2df998", + "current_source_context_sha256": "6ebe3119910ea6b07ce3486e8c5b62da011e5e0415a01e9024e579a136b1dc19", "accepted_source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", "captured_source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html b/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html index 363d8d9..3908d90 100644 --- a/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html +++ b/examples/model-ui/field-service-dispatch/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html @@ -310,7 +310,7 @@ "design_system_adapter_file": null, "capture_file": "captures/gpt56-sol-ultra-codex-with-judgmentkit.json", "source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", - "current_source_context_sha256": "ac67e51576f74561c51d5dd267e85552d6843b3b18dbc973ba9199d16255d54c", + "current_source_context_sha256": "5f649c8f8b1f4c7ab03bb06459e9b931665bf18e58a4eb4ce84f1cb6743ff701", "source_context_status": "legacy_accepted", "model_response_summary": "A focused same-day dispatch workbench that keeps visit selection, readiness evidence, decision controls, and the dispatch handoff together.", "frontend_context_status": "ready_for_frontend_implementation", @@ -415,7 +415,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "ac67e51576f74561c51d5dd267e85552d6843b3b18dbc973ba9199d16255d54c", + "current_source_context_sha256": "5f649c8f8b1f4c7ab03bb06459e9b931665bf18e58a4eb4ce84f1cb6743ff701", "accepted_source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", "captured_source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/field-service-dispatch/captures/gemma4-lms-judgmentkit-material-ui.json b/examples/model-ui/field-service-dispatch/captures/gemma4-lms-judgmentkit-material-ui.json index ec3709f..f9f1356 100644 --- a/examples/model-ui/field-service-dispatch/captures/gemma4-lms-judgmentkit-material-ui.json +++ b/examples/model-ui/field-service-dispatch/captures/gemma4-lms-judgmentkit-material-ui.json @@ -163,7 +163,7 @@ "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "4cb7db5a0a4c8e43993f3e3c8bab098fdf266afe231dfd04a27a11097a69c874", + "current_source_context_sha256": "f227470f13ed80d2316c002c3d332ca61481006b67b38e0018b28322bf1d9a06", "accepted_source_context_sha256": "f2b04bf482eece25137b6269bb85fda5e6731c84c86fd57cba30878e038a4437", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/field-service-dispatch/captures/gemma4-lms-with-judgmentkit.json b/examples/model-ui/field-service-dispatch/captures/gemma4-lms-with-judgmentkit.json index 0e75133..2842aa4 100644 --- a/examples/model-ui/field-service-dispatch/captures/gemma4-lms-with-judgmentkit.json +++ b/examples/model-ui/field-service-dispatch/captures/gemma4-lms-with-judgmentkit.json @@ -104,7 +104,7 @@ "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "7d2f320bcf48c8127ebbca8f89722695a2c31da249234d95997c265d048f43a9", + "current_source_context_sha256": "9c361bec476bc6eb0962c1d8a2bf1435f6471a6459ed3d13f10f7fcb8acb8747", "accepted_source_context_sha256": "5fb5bad62994a5ec45b69ce09b343eb3932725dd0be51369a850c027f8e4675b", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/field-service-dispatch/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json b/examples/model-ui/field-service-dispatch/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json index 98c37ca..5e720a9 100644 --- a/examples/model-ui/field-service-dispatch/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/field-service-dispatch/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json @@ -151,7 +151,7 @@ "stderr_sha256": "fc0697c6b0bf59fc6e6dfa0d535c7667173cf994408a424066f0ac1e6961fb87" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "505dab25c7b36e8ce23a278c38e88b0a683f4548a36a4e7c2f3710e0607ab527", + "current_source_context_sha256": "6013725d108e285b15c59aa22e77f1e18e88fe72cb40bd24aa6b5cc54c705b98", "accepted_source_context_sha256": "5916d8bcbdef11f6f948873f3cf4a6a316d031628a15a9cf3047412190639136", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/field-service-dispatch/captures/gpt55-xhigh-codex-with-judgmentkit.json b/examples/model-ui/field-service-dispatch/captures/gpt55-xhigh-codex-with-judgmentkit.json index 54c1e21..99ccf6d 100644 --- a/examples/model-ui/field-service-dispatch/captures/gpt55-xhigh-codex-with-judgmentkit.json +++ b/examples/model-ui/field-service-dispatch/captures/gpt55-xhigh-codex-with-judgmentkit.json @@ -98,7 +98,7 @@ "stderr_sha256": "6468c57b1ba30d668a84a9393508ae0b2902641a2fa75c4125d93c9064d963f6" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "4ad189477f46853a5c7f70420d255ae86e567af5ddd2fbdb1bef62c1589bd450", + "current_source_context_sha256": "c3b36bd021abc184c7498eb2e008d7388bd4aee9dbbf0751e9cc7252c1cb267b", "accepted_source_context_sha256": "84d7adc5190f3796a3fc4e61f40b3987ead81206cb9dc750b4098c36873bbacd", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/field-service-dispatch/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json b/examples/model-ui/field-service-dispatch/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json index b4b24cb..95f8dd0 100644 --- a/examples/model-ui/field-service-dispatch/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/field-service-dispatch/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d30eb3daf9f3d4b8aac786ab658e9c590072a769f7c3b6f2bf00fb4d05522cc4", + "current_source_context_sha256": "fb191b73ad9a3db0b190d13788fd20a33068c669ed5834e7b967af5dc6fea3a2", "accepted_source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "6f9155fcece89ba17aa7f6a815c031c8d12d24be0fa61cd11b88bb2259500039", diff --git a/examples/model-ui/field-service-dispatch/captures/gpt56-sol-low-codex-with-judgmentkit.json b/examples/model-ui/field-service-dispatch/captures/gpt56-sol-low-codex-with-judgmentkit.json index 1cf9125..ce6904f 100644 --- a/examples/model-ui/field-service-dispatch/captures/gpt56-sol-low-codex-with-judgmentkit.json +++ b/examples/model-ui/field-service-dispatch/captures/gpt56-sol-low-codex-with-judgmentkit.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "907bb6cd657fd8a2ee5145ecfd425f0a4b9dd11cb1ffc09200563b6da1ffcc0c", + "current_source_context_sha256": "6ec3c387ee64d24b73d5697d063cee223a99e1d973fdb60068b6429af1b65735", "accepted_source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "270596b1ddcbec5b8a1d7801a7592213667c27d570a1d0ec61f40f20d0e3933e", diff --git a/examples/model-ui/field-service-dispatch/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json b/examples/model-ui/field-service-dispatch/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json index 28c7a91..cb9d702 100644 --- a/examples/model-ui/field-service-dispatch/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/field-service-dispatch/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "6aa62dcb25a52d342de421b88f0f5e21a2a0000799972b1110d719cd2b2df998", + "current_source_context_sha256": "6ebe3119910ea6b07ce3486e8c5b62da011e5e0415a01e9024e579a136b1dc19", "accepted_source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "6f9155fcece89ba17aa7f6a815c031c8d12d24be0fa61cd11b88bb2259500039", diff --git a/examples/model-ui/field-service-dispatch/captures/gpt56-sol-ultra-codex-with-judgmentkit.json b/examples/model-ui/field-service-dispatch/captures/gpt56-sol-ultra-codex-with-judgmentkit.json index a4646e2..b769be5 100644 --- a/examples/model-ui/field-service-dispatch/captures/gpt56-sol-ultra-codex-with-judgmentkit.json +++ b/examples/model-ui/field-service-dispatch/captures/gpt56-sol-ultra-codex-with-judgmentkit.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "ac67e51576f74561c51d5dd267e85552d6843b3b18dbc973ba9199d16255d54c", + "current_source_context_sha256": "5f649c8f8b1f4c7ab03bb06459e9b931665bf18e58a4eb4ce84f1cb6743ff701", "accepted_source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "270596b1ddcbec5b8a1d7801a7592213667c27d570a1d0ec61f40f20d0e3933e", diff --git a/examples/model-ui/field-service-dispatch/manifest.json b/examples/model-ui/field-service-dispatch/manifest.json index d230610..c2ad1ca 100644 --- a/examples/model-ui/field-service-dispatch/manifest.json +++ b/examples/model-ui/field-service-dispatch/manifest.json @@ -194,8 +194,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", - "accepted_source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", + "current_source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", + "accepted_source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -204,8 +204,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", - "current_source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", + "source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", + "current_source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -396,8 +396,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", - "accepted_source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", + "current_source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", + "accepted_source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -406,8 +406,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", - "current_source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", + "source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", + "current_source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -851,7 +851,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "4cb7db5a0a4c8e43993f3e3c8bab098fdf266afe231dfd04a27a11097a69c874", + "current_source_context_sha256": "f227470f13ed80d2316c002c3d332ca61481006b67b38e0018b28322bf1d9a06", "accepted_source_context_sha256": "f2b04bf482eece25137b6269bb85fda5e6731c84c86fd57cba30878e038a4437", "captured_source_context_sha256": "f2b04bf482eece25137b6269bb85fda5e6731c84c86fd57cba30878e038a4437", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -872,7 +872,7 @@ "capture_quality": null, "prompt_sha256": "58ed27561801b0b4c6d4c8f2fc5d9c79f4700fa3d4f695ba684c95569f9ba215", "source_context_sha256": "f2b04bf482eece25137b6269bb85fda5e6731c84c86fd57cba30878e038a4437", - "current_source_context_sha256": "4cb7db5a0a4c8e43993f3e3c8bab098fdf266afe231dfd04a27a11097a69c874", + "current_source_context_sha256": "f227470f13ed80d2316c002c3d332ca61481006b67b38e0018b28322bf1d9a06", "source_context_status": "legacy_accepted", "raw_response_sha256": "64c67de16f37aa755c819761edabd4de112346242dc64bc8631ede6f3fe332d5", "frontend_context_status": "ready_for_frontend_implementation", @@ -1269,7 +1269,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "505dab25c7b36e8ce23a278c38e88b0a683f4548a36a4e7c2f3710e0607ab527", + "current_source_context_sha256": "6013725d108e285b15c59aa22e77f1e18e88fe72cb40bd24aa6b5cc54c705b98", "accepted_source_context_sha256": "5916d8bcbdef11f6f948873f3cf4a6a316d031628a15a9cf3047412190639136", "captured_source_context_sha256": "5916d8bcbdef11f6f948873f3cf4a6a316d031628a15a9cf3047412190639136", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -1284,7 +1284,7 @@ "capture_quality": null, "prompt_sha256": "1272c5429f39ff4e9c1a98f12ff3367a06c848ff5d711d25136ad3e6e77a76db", "source_context_sha256": "5916d8bcbdef11f6f948873f3cf4a6a316d031628a15a9cf3047412190639136", - "current_source_context_sha256": "505dab25c7b36e8ce23a278c38e88b0a683f4548a36a4e7c2f3710e0607ab527", + "current_source_context_sha256": "6013725d108e285b15c59aa22e77f1e18e88fe72cb40bd24aa6b5cc54c705b98", "source_context_status": "legacy_accepted", "raw_response_sha256": "f9b847c2bdfd7e2a095709a9cb7160a83e02ce414dcc1a87a7ad5982a8a6972f", "frontend_context_status": "ready_for_frontend_implementation", @@ -2350,7 +2350,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "907bb6cd657fd8a2ee5145ecfd425f0a4b9dd11cb1ffc09200563b6da1ffcc0c", + "current_source_context_sha256": "6ec3c387ee64d24b73d5697d063cee223a99e1d973fdb60068b6429af1b65735", "accepted_source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", "captured_source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -2392,7 +2392,7 @@ }, "prompt_sha256": "270596b1ddcbec5b8a1d7801a7592213667c27d570a1d0ec61f40f20d0e3933e", "source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", - "current_source_context_sha256": "907bb6cd657fd8a2ee5145ecfd425f0a4b9dd11cb1ffc09200563b6da1ffcc0c", + "current_source_context_sha256": "6ec3c387ee64d24b73d5697d063cee223a99e1d973fdb60068b6429af1b65735", "source_context_status": "legacy_accepted", "raw_response_sha256": "96707e618d0216f63d632951c128cfc4c2bce450947593b54a05674426dc99c4", "frontend_context_status": "ready_for_frontend_implementation", @@ -2615,7 +2615,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d30eb3daf9f3d4b8aac786ab658e9c590072a769f7c3b6f2bf00fb4d05522cc4", + "current_source_context_sha256": "fb191b73ad9a3db0b190d13788fd20a33068c669ed5834e7b967af5dc6fea3a2", "accepted_source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", "captured_source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -2630,7 +2630,7 @@ "capture_quality": null, "prompt_sha256": "6f9155fcece89ba17aa7f6a815c031c8d12d24be0fa61cd11b88bb2259500039", "source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", - "current_source_context_sha256": "d30eb3daf9f3d4b8aac786ab658e9c590072a769f7c3b6f2bf00fb4d05522cc4", + "current_source_context_sha256": "fb191b73ad9a3db0b190d13788fd20a33068c669ed5834e7b967af5dc6fea3a2", "source_context_status": "legacy_accepted", "raw_response_sha256": "c499b155c9c9411ac156248c95c1622e55e7d5d9a9e59eddc1d2fc2132174496", "frontend_context_status": "ready_for_frontend_implementation", @@ -4369,7 +4369,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "ac67e51576f74561c51d5dd267e85552d6843b3b18dbc973ba9199d16255d54c", + "current_source_context_sha256": "5f649c8f8b1f4c7ab03bb06459e9b931665bf18e58a4eb4ce84f1cb6743ff701", "accepted_source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", "captured_source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -4411,7 +4411,7 @@ }, "prompt_sha256": "270596b1ddcbec5b8a1d7801a7592213667c27d570a1d0ec61f40f20d0e3933e", "source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", - "current_source_context_sha256": "ac67e51576f74561c51d5dd267e85552d6843b3b18dbc973ba9199d16255d54c", + "current_source_context_sha256": "5f649c8f8b1f4c7ab03bb06459e9b931665bf18e58a4eb4ce84f1cb6743ff701", "source_context_status": "legacy_accepted", "raw_response_sha256": "4d5c6f8ee1e35d49192b94bebc52f7e1c00a0910d31e7a43ff44cdac07a570e0", "frontend_context_status": "ready_for_frontend_implementation", @@ -4634,7 +4634,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "6aa62dcb25a52d342de421b88f0f5e21a2a0000799972b1110d719cd2b2df998", + "current_source_context_sha256": "6ebe3119910ea6b07ce3486e8c5b62da011e5e0415a01e9024e579a136b1dc19", "accepted_source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", "captured_source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -4649,7 +4649,7 @@ "capture_quality": null, "prompt_sha256": "6f9155fcece89ba17aa7f6a815c031c8d12d24be0fa61cd11b88bb2259500039", "source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", - "current_source_context_sha256": "6aa62dcb25a52d342de421b88f0f5e21a2a0000799972b1110d719cd2b2df998", + "current_source_context_sha256": "6ebe3119910ea6b07ce3486e8c5b62da011e5e0415a01e9024e579a136b1dc19", "source_context_status": "legacy_accepted", "raw_response_sha256": "588b66ae373ddf7e35c6355b2eec0820f8a332189d68b012dc637aecc8770004", "frontend_context_status": "ready_for_frontend_implementation", @@ -4888,8 +4888,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", - "accepted_source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", + "current_source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", + "accepted_source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -4898,8 +4898,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", - "current_source_context_sha256": "bf87284c3aad06f993d608d4a9e928627371703ae6156af5acb1c4b0498ce727", + "source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", + "current_source_context_sha256": "6de8393c2291fc8c2a140196cffd8fa7071683f7fbb53e39e0280ef574feede6", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -5090,8 +5090,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", - "accepted_source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", + "current_source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", + "accepted_source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -5100,8 +5100,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", - "current_source_context_sha256": "693a5b3b42ff2eeaaf1344c6cefa9f1d8eb63a9288c49de79b096b9dd71360b2", + "source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", + "current_source_context_sha256": "5398a5f44bcdb7e7171548b53109c04bf83ef2af71f51da92dee48a677ee23b9", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -5491,7 +5491,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "4cb7db5a0a4c8e43993f3e3c8bab098fdf266afe231dfd04a27a11097a69c874", + "current_source_context_sha256": "f227470f13ed80d2316c002c3d332ca61481006b67b38e0018b28322bf1d9a06", "accepted_source_context_sha256": "f2b04bf482eece25137b6269bb85fda5e6731c84c86fd57cba30878e038a4437", "captured_source_context_sha256": "f2b04bf482eece25137b6269bb85fda5e6731c84c86fd57cba30878e038a4437", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -5512,7 +5512,7 @@ "capture_quality": null, "prompt_sha256": "58ed27561801b0b4c6d4c8f2fc5d9c79f4700fa3d4f695ba684c95569f9ba215", "source_context_sha256": "f2b04bf482eece25137b6269bb85fda5e6731c84c86fd57cba30878e038a4437", - "current_source_context_sha256": "4cb7db5a0a4c8e43993f3e3c8bab098fdf266afe231dfd04a27a11097a69c874", + "current_source_context_sha256": "f227470f13ed80d2316c002c3d332ca61481006b67b38e0018b28322bf1d9a06", "source_context_status": "legacy_accepted", "raw_response_sha256": "64c67de16f37aa755c819761edabd4de112346242dc64bc8631ede6f3fe332d5", "frontend_context_status": "ready_for_frontend_implementation", @@ -5855,7 +5855,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "505dab25c7b36e8ce23a278c38e88b0a683f4548a36a4e7c2f3710e0607ab527", + "current_source_context_sha256": "6013725d108e285b15c59aa22e77f1e18e88fe72cb40bd24aa6b5cc54c705b98", "accepted_source_context_sha256": "5916d8bcbdef11f6f948873f3cf4a6a316d031628a15a9cf3047412190639136", "captured_source_context_sha256": "5916d8bcbdef11f6f948873f3cf4a6a316d031628a15a9cf3047412190639136", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -5870,7 +5870,7 @@ "capture_quality": null, "prompt_sha256": "1272c5429f39ff4e9c1a98f12ff3367a06c848ff5d711d25136ad3e6e77a76db", "source_context_sha256": "5916d8bcbdef11f6f948873f3cf4a6a316d031628a15a9cf3047412190639136", - "current_source_context_sha256": "505dab25c7b36e8ce23a278c38e88b0a683f4548a36a4e7c2f3710e0607ab527", + "current_source_context_sha256": "6013725d108e285b15c59aa22e77f1e18e88fe72cb40bd24aa6b5cc54c705b98", "source_context_status": "legacy_accepted", "raw_response_sha256": "f9b847c2bdfd7e2a095709a9cb7160a83e02ce414dcc1a87a7ad5982a8a6972f", "frontend_context_status": "ready_for_frontend_implementation", @@ -6883,7 +6883,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "907bb6cd657fd8a2ee5145ecfd425f0a4b9dd11cb1ffc09200563b6da1ffcc0c", + "current_source_context_sha256": "6ec3c387ee64d24b73d5697d063cee223a99e1d973fdb60068b6429af1b65735", "accepted_source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", "captured_source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -6925,7 +6925,7 @@ }, "prompt_sha256": "270596b1ddcbec5b8a1d7801a7592213667c27d570a1d0ec61f40f20d0e3933e", "source_context_sha256": "e0231cd7685eba0fc284c5525089d7ffd889a89c94b25badfc564ca17b8eaf01", - "current_source_context_sha256": "907bb6cd657fd8a2ee5145ecfd425f0a4b9dd11cb1ffc09200563b6da1ffcc0c", + "current_source_context_sha256": "6ec3c387ee64d24b73d5697d063cee223a99e1d973fdb60068b6429af1b65735", "source_context_status": "legacy_accepted", "raw_response_sha256": "96707e618d0216f63d632951c128cfc4c2bce450947593b54a05674426dc99c4", "frontend_context_status": "ready_for_frontend_implementation", @@ -7148,7 +7148,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "d30eb3daf9f3d4b8aac786ab658e9c590072a769f7c3b6f2bf00fb4d05522cc4", + "current_source_context_sha256": "fb191b73ad9a3db0b190d13788fd20a33068c669ed5834e7b967af5dc6fea3a2", "accepted_source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", "captured_source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -7163,7 +7163,7 @@ "capture_quality": null, "prompt_sha256": "6f9155fcece89ba17aa7f6a815c031c8d12d24be0fa61cd11b88bb2259500039", "source_context_sha256": "a422dc708edc4ea17dc2ce60d3b90b6b8c4b44e06abbb583c6005c04d0cb7b3a", - "current_source_context_sha256": "d30eb3daf9f3d4b8aac786ab658e9c590072a769f7c3b6f2bf00fb4d05522cc4", + "current_source_context_sha256": "fb191b73ad9a3db0b190d13788fd20a33068c669ed5834e7b967af5dc6fea3a2", "source_context_status": "legacy_accepted", "raw_response_sha256": "c499b155c9c9411ac156248c95c1622e55e7d5d9a9e59eddc1d2fc2132174496", "frontend_context_status": "ready_for_frontend_implementation", @@ -8849,7 +8849,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "ac67e51576f74561c51d5dd267e85552d6843b3b18dbc973ba9199d16255d54c", + "current_source_context_sha256": "5f649c8f8b1f4c7ab03bb06459e9b931665bf18e58a4eb4ce84f1cb6743ff701", "accepted_source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", "captured_source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -8891,7 +8891,7 @@ }, "prompt_sha256": "270596b1ddcbec5b8a1d7801a7592213667c27d570a1d0ec61f40f20d0e3933e", "source_context_sha256": "ac0f1d68f886c0e87dcd91e3ab2cfaff3aabca846a21cf607c37b1452a95a2e1", - "current_source_context_sha256": "ac67e51576f74561c51d5dd267e85552d6843b3b18dbc973ba9199d16255d54c", + "current_source_context_sha256": "5f649c8f8b1f4c7ab03bb06459e9b931665bf18e58a4eb4ce84f1cb6743ff701", "source_context_status": "legacy_accepted", "raw_response_sha256": "4d5c6f8ee1e35d49192b94bebc52f7e1c00a0910d31e7a43ff44cdac07a570e0", "frontend_context_status": "ready_for_frontend_implementation", @@ -9114,7 +9114,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "6aa62dcb25a52d342de421b88f0f5e21a2a0000799972b1110d719cd2b2df998", + "current_source_context_sha256": "6ebe3119910ea6b07ce3486e8c5b62da011e5e0415a01e9024e579a136b1dc19", "accepted_source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", "captured_source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -9129,7 +9129,7 @@ "capture_quality": null, "prompt_sha256": "6f9155fcece89ba17aa7f6a815c031c8d12d24be0fa61cd11b88bb2259500039", "source_context_sha256": "10209336f1300d8e8885fb86e34350f74a901baba4d3fbfc295a30d78ab801a2", - "current_source_context_sha256": "6aa62dcb25a52d342de421b88f0f5e21a2a0000799972b1110d719cd2b2df998", + "current_source_context_sha256": "6ebe3119910ea6b07ce3486e8c5b62da011e5e0415a01e9024e579a136b1dc19", "source_context_status": "legacy_accepted", "raw_response_sha256": "588b66ae373ddf7e35c6355b2eec0820f8a332189d68b012dc637aecc8770004", "frontend_context_status": "ready_for_frontend_implementation", @@ -9284,7 +9284,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "7d2f320bcf48c8127ebbca8f89722695a2c31da249234d95997c265d048f43a9", + "current_source_context_sha256": "9c361bec476bc6eb0962c1d8a2bf1435f6471a6459ed3d13f10f7fcb8acb8747", "accepted_source_context_sha256": "5fb5bad62994a5ec45b69ce09b343eb3932725dd0be51369a850c027f8e4675b", "captured_source_context_sha256": "5fb5bad62994a5ec45b69ce09b343eb3932725dd0be51369a850c027f8e4675b", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -9454,7 +9454,7 @@ }, "prompt_sha256": "ee421af6cb25603e4fcb4ee668a2809df71763ae9fec25aff2b9132baf96716c", "source_context_sha256": "5fb5bad62994a5ec45b69ce09b343eb3932725dd0be51369a850c027f8e4675b", - "current_source_context_sha256": "7d2f320bcf48c8127ebbca8f89722695a2c31da249234d95997c265d048f43a9", + "current_source_context_sha256": "9c361bec476bc6eb0962c1d8a2bf1435f6471a6459ed3d13f10f7fcb8acb8747", "source_context_status": "legacy_accepted", "raw_response_sha256": "eecb6225a40ccac71aba03fe167b3595f164328f5544b3f011f679a00932a231", "frontend_context_status": "ready_for_frontend_implementation", @@ -9588,7 +9588,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "4ad189477f46853a5c7f70420d255ae86e567af5ddd2fbdb1bef62c1589bd450", + "current_source_context_sha256": "c3b36bd021abc184c7498eb2e008d7388bd4aee9dbbf0751e9cc7252c1cb267b", "accepted_source_context_sha256": "84d7adc5190f3796a3fc4e61f40b3987ead81206cb9dc750b4098c36873bbacd", "captured_source_context_sha256": "84d7adc5190f3796a3fc4e61f40b3987ead81206cb9dc750b4098c36873bbacd", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -10022,7 +10022,7 @@ }, "prompt_sha256": "c0a082cd6b1c6ef8907c6793ac54c0f28f1e8f0c9ce7c26d7ba18bb8c21a7375", "source_context_sha256": "84d7adc5190f3796a3fc4e61f40b3987ead81206cb9dc750b4098c36873bbacd", - "current_source_context_sha256": "4ad189477f46853a5c7f70420d255ae86e567af5ddd2fbdb1bef62c1589bd450", + "current_source_context_sha256": "c3b36bd021abc184c7498eb2e008d7388bd4aee9dbbf0751e9cc7252c1cb267b", "source_context_status": "legacy_accepted", "raw_response_sha256": "bb326d684e995426762aceebabc8389ee040e4a75adeb77c99645f83b5cd8ef1", "frontend_context_status": "ready_for_frontend_implementation", 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 be3790c..2bfedc9 100644 --- a/examples/model-ui/field-service-dispatch/reviewed-handoff.fixture.json +++ b/examples/model-ui/field-service-dispatch/reviewed-handoff.fixture.json @@ -1,5 +1,5 @@ { - "version": "0.7.0", + "version": "0.8.0", "contract_id": "judgmentkit.ai-ui-generation.activity-contract", "handoff_status": "ready_for_generation", "source": { diff --git a/examples/model-ui/refund-system-map/artifacts/deterministic-judgmentkit-material-ui.html b/examples/model-ui/refund-system-map/artifacts/deterministic-judgmentkit-material-ui.html index a758055..e37d7e1 100644 --- a/examples/model-ui/refund-system-map/artifacts/deterministic-judgmentkit-material-ui.html +++ b/examples/model-ui/refund-system-map/artifacts/deterministic-judgmentkit-material-ui.html @@ -286,8 +286,8 @@ "handoff_source": "examples/model-ui/refund-system-map/reviewed-handoff.fixture.json", "design_system_adapter_file": "examples/model-ui/refund-system-map/design-system-adapter.json", "capture_file": null, - "source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", - "current_source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", + "source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", + "current_source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", "source_context_status": "current", "model_response_summary": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -352,8 +352,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", - "accepted_source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", + "current_source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", + "accepted_source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." diff --git a/examples/model-ui/refund-system-map/artifacts/deterministic-with-judgmentkit.html b/examples/model-ui/refund-system-map/artifacts/deterministic-with-judgmentkit.html index 3d945ce..21d7cac 100644 --- a/examples/model-ui/refund-system-map/artifacts/deterministic-with-judgmentkit.html +++ b/examples/model-ui/refund-system-map/artifacts/deterministic-with-judgmentkit.html @@ -379,8 +379,8 @@

Support agent

"handoff_source": "examples/model-ui/refund-system-map/reviewed-handoff.fixture.json", "design_system_adapter_file": null, "capture_file": null, - "source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", - "current_source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", + "source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", + "current_source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", "source_context_status": "current", "model_response_summary": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -445,8 +445,8 @@

Support agent

"frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", - "accepted_source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", + "current_source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", + "accepted_source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." diff --git a/examples/model-ui/refund-system-map/artifacts/gemma4-lms-judgmentkit-material-ui.html b/examples/model-ui/refund-system-map/artifacts/gemma4-lms-judgmentkit-material-ui.html index f9f4c78..3fa43ac 100644 --- a/examples/model-ui/refund-system-map/artifacts/gemma4-lms-judgmentkit-material-ui.html +++ b/examples/model-ui/refund-system-map/artifacts/gemma4-lms-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/refund-system-map/design-system-adapter.json", "capture_file": "captures/gemma4-lms-judgmentkit-material-ui.json", "source_context_sha256": "9ac132c121d01a8bb5d46d2c69c8550392a2c12465cb763faa018ad84df09005", - "current_source_context_sha256": "89c3848de86d1cb0d765720a008e7d369503ee263d72ce6687ee0e854f59b3b3", + "current_source_context_sha256": "6fde9db5f9033c53c07f70edf44e48bbabca27cfa68d9b121217cdf2f53a75c3", "source_context_status": "legacy_accepted", "model_response_summary": "Review workspace for refund request R-1842 where evidence is incomplete, requiring the customer to provide a receipt photo before approval.", "frontend_context_status": "ready_for_frontend_implementation", @@ -358,7 +358,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "89c3848de86d1cb0d765720a008e7d369503ee263d72ce6687ee0e854f59b3b3", + "current_source_context_sha256": "6fde9db5f9033c53c07f70edf44e48bbabca27cfa68d9b121217cdf2f53a75c3", "accepted_source_context_sha256": "9ac132c121d01a8bb5d46d2c69c8550392a2c12465cb763faa018ad84df09005", "captured_source_context_sha256": "9ac132c121d01a8bb5d46d2c69c8550392a2c12465cb763faa018ad84df09005", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/refund-system-map/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html b/examples/model-ui/refund-system-map/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html index 5002b27..6a4a568 100644 --- a/examples/model-ui/refund-system-map/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/refund-system-map/artifacts/gpt55-xhigh-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/refund-system-map/design-system-adapter.json", "capture_file": "captures/gpt55-xhigh-codex-judgmentkit-material-ui.json", "source_context_sha256": "5ad2fd84f91850b16be0a4100df01bec39ae3046ccdcdc4f9b7413b3b685a807", - "current_source_context_sha256": "294383e386065d72efb01390cac018bb51f9391f7fb352a62d66b68f7888b32a", + "current_source_context_sha256": "ea11fdd2edfb47a86a365e65c4528e9b0db2be47c04fc982d1ab7f71de03593c", "source_context_status": "legacy_accepted", "model_response_summary": "Structured surface data for a support operations manager to return refund case R-1842 for missing receipt evidence.", "frontend_context_status": "ready_for_frontend_implementation", @@ -352,7 +352,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "294383e386065d72efb01390cac018bb51f9391f7fb352a62d66b68f7888b32a", + "current_source_context_sha256": "ea11fdd2edfb47a86a365e65c4528e9b0db2be47c04fc982d1ab7f71de03593c", "accepted_source_context_sha256": "5ad2fd84f91850b16be0a4100df01bec39ae3046ccdcdc4f9b7413b3b685a807", "captured_source_context_sha256": "5ad2fd84f91850b16be0a4100df01bec39ae3046ccdcdc4f9b7413b3b685a807", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/refund-system-map/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html b/examples/model-ui/refund-system-map/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html index d1c4430..c59e4a7 100644 --- a/examples/model-ui/refund-system-map/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/refund-system-map/artifacts/gpt56-sol-low-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/refund-system-map/design-system-adapter.json", "capture_file": "captures/gpt56-sol-low-codex-judgmentkit-material-ui.json", "source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", - "current_source_context_sha256": "65df5f708386c7ff1c02909ec18bfe2a3e6da72ea93d7f6ec0899fb14a8c4618", + "current_source_context_sha256": "47f8bffb0b1ede02abb1ec7614260d43cd2c5cfbac8900b6cdf34e9fe871146f", "source_context_status": "legacy_accepted", "model_response_summary": "Refund escalation R-1842 should return to the support agent for missing evidence before manager approval.", "frontend_context_status": "ready_for_frontend_implementation", @@ -365,7 +365,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "65df5f708386c7ff1c02909ec18bfe2a3e6da72ea93d7f6ec0899fb14a8c4618", + "current_source_context_sha256": "47f8bffb0b1ede02abb1ec7614260d43cd2c5cfbac8900b6cdf34e9fe871146f", "accepted_source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", "captured_source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/refund-system-map/artifacts/gpt56-sol-low-codex-with-judgmentkit.html b/examples/model-ui/refund-system-map/artifacts/gpt56-sol-low-codex-with-judgmentkit.html index 7ba911a..1a26cdf 100644 --- a/examples/model-ui/refund-system-map/artifacts/gpt56-sol-low-codex-with-judgmentkit.html +++ b/examples/model-ui/refund-system-map/artifacts/gpt56-sol-low-codex-with-judgmentkit.html @@ -366,7 +366,7 @@ "design_system_adapter_file": null, "capture_file": "captures/gpt56-sol-low-codex-with-judgmentkit.json", "source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", - "current_source_context_sha256": "a552719ba51c97db00c84a21c2eac4f5eaf0cc53f281c650e6f2f8c207965eec", + "current_source_context_sha256": "30b33d69c324626be4c0700ddd4815cff0bc26de3916405648aa48ffc762c242", "source_context_status": "legacy_accepted", "model_response_summary": "A focused refund escalation workbench that keeps queue selection, evidence review, decision, and handoff together.", "frontend_context_status": "ready_for_frontend_implementation", @@ -471,7 +471,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "a552719ba51c97db00c84a21c2eac4f5eaf0cc53f281c650e6f2f8c207965eec", + "current_source_context_sha256": "30b33d69c324626be4c0700ddd4815cff0bc26de3916405648aa48ffc762c242", "accepted_source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", "captured_source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/refund-system-map/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html b/examples/model-ui/refund-system-map/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html index 9b6da53..3d86845 100644 --- a/examples/model-ui/refund-system-map/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html +++ b/examples/model-ui/refund-system-map/artifacts/gpt56-sol-ultra-codex-judgmentkit-material-ui.html @@ -287,7 +287,7 @@ "design_system_adapter_file": "examples/model-ui/refund-system-map/design-system-adapter.json", "capture_file": "captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json", "source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", - "current_source_context_sha256": "14f1e278c94ad1827608195b9f46e1156cf89e177184ebb773ff10e2c7e1f0ad", + "current_source_context_sha256": "99266252a708f96c7bdd5395fa7aca1c342df9cbf79310507c3c7fc0b3fca593", "source_context_status": "legacy_accepted", "model_response_summary": "Refund R-1842 should return to the support agent because the receipt photo required for manager approval is missing.", "frontend_context_status": "ready_for_frontend_implementation", @@ -365,7 +365,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "14f1e278c94ad1827608195b9f46e1156cf89e177184ebb773ff10e2c7e1f0ad", + "current_source_context_sha256": "99266252a708f96c7bdd5395fa7aca1c342df9cbf79310507c3c7fc0b3fca593", "accepted_source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", "captured_source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/refund-system-map/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html b/examples/model-ui/refund-system-map/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html index 923580c..f9271b4 100644 --- a/examples/model-ui/refund-system-map/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html +++ b/examples/model-ui/refund-system-map/artifacts/gpt56-sol-ultra-codex-with-judgmentkit.html @@ -1177,7 +1177,7 @@

Handoff

"design_system_adapter_file": null, "capture_file": "captures/gpt56-sol-ultra-codex-with-judgmentkit.json", "source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", - "current_source_context_sha256": "1b115c677b968effdb063e306dc3157de353fc59a4a71034f83554f11405736e", + "current_source_context_sha256": "f68f180dc8f17b2c42ee21148d26a0a42d92a7b2bb30e6e88fc70e940179182c", "source_context_status": "legacy_accepted", "model_response_summary": "A coordinated refund escalation workbench keeps queue ordering, case evidence, the selected return path, and a ready-to-send support handoff visible in one review surface.", "frontend_context_status": "ready_for_frontend_implementation", @@ -1282,7 +1282,7 @@

Handoff

"status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "1b115c677b968effdb063e306dc3157de353fc59a4a71034f83554f11405736e", + "current_source_context_sha256": "f68f180dc8f17b2c42ee21148d26a0a42d92a7b2bb30e6e88fc70e940179182c", "accepted_source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", "captured_source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", diff --git a/examples/model-ui/refund-system-map/captures/gemma4-lms-judgmentkit-material-ui.json b/examples/model-ui/refund-system-map/captures/gemma4-lms-judgmentkit-material-ui.json index 0a632e9..b8b1345 100644 --- a/examples/model-ui/refund-system-map/captures/gemma4-lms-judgmentkit-material-ui.json +++ b/examples/model-ui/refund-system-map/captures/gemma4-lms-judgmentkit-material-ui.json @@ -154,7 +154,7 @@ "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "89c3848de86d1cb0d765720a008e7d369503ee263d72ce6687ee0e854f59b3b3", + "current_source_context_sha256": "6fde9db5f9033c53c07f70edf44e48bbabca27cfa68d9b121217cdf2f53a75c3", "accepted_source_context_sha256": "9ac132c121d01a8bb5d46d2c69c8550392a2c12465cb763faa018ad84df09005", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/refund-system-map/captures/gemma4-lms-with-judgmentkit.json b/examples/model-ui/refund-system-map/captures/gemma4-lms-with-judgmentkit.json index 583d4b4..a11be65 100644 --- a/examples/model-ui/refund-system-map/captures/gemma4-lms-with-judgmentkit.json +++ b/examples/model-ui/refund-system-map/captures/gemma4-lms-with-judgmentkit.json @@ -104,7 +104,7 @@ "stderr_sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "ca29744cc607323788099bc0a8eb09f4ce7567cda35fd2d38f76016d11d46290", + "current_source_context_sha256": "e82707a158fe77056752c820eae91eb8842760fbd40bee006588176c376f97a9", "accepted_source_context_sha256": "61230da7c0d2ff5655e04513a3565f2c1a070abe21b80568036ea1b702466385", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/refund-system-map/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json b/examples/model-ui/refund-system-map/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json index 5a1ab23..1eff54e 100644 --- a/examples/model-ui/refund-system-map/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/refund-system-map/captures/gpt55-xhigh-codex-judgmentkit-material-ui.json @@ -151,7 +151,7 @@ "stderr_sha256": "73b93cec4e799368efb07725d0f31e70bdef130b750c4565663dd7ff7641f4d2" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "294383e386065d72efb01390cac018bb51f9391f7fb352a62d66b68f7888b32a", + "current_source_context_sha256": "ea11fdd2edfb47a86a365e65c4528e9b0db2be47c04fc982d1ab7f71de03593c", "accepted_source_context_sha256": "5ad2fd84f91850b16be0a4100df01bec39ae3046ccdcdc4f9b7413b3b685a807", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/refund-system-map/captures/gpt55-xhigh-codex-with-judgmentkit.json b/examples/model-ui/refund-system-map/captures/gpt55-xhigh-codex-with-judgmentkit.json index 90e0fc8..f49393c 100644 --- a/examples/model-ui/refund-system-map/captures/gpt55-xhigh-codex-with-judgmentkit.json +++ b/examples/model-ui/refund-system-map/captures/gpt55-xhigh-codex-with-judgmentkit.json @@ -98,7 +98,7 @@ "stderr_sha256": "e47cde7abd02e7c4b043836ce486d73cd1064179ef3a45a7dd8353ffb85b4163" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "55b4011e3fc8a0a924969bb8e50eed7bcc8aa5da086b845dcf0e617cfe0d4fac", + "current_source_context_sha256": "f961ede0fac585bce21606e27a92938ea0ba3cb744a5a9a691d4a8c6962edd23", "accepted_source_context_sha256": "2b0cee90315bc5e13da9140a71d11682b601773589b8b0b53a37e275a83dfd90", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured." } diff --git a/examples/model-ui/refund-system-map/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json b/examples/model-ui/refund-system-map/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json index e3a1e8b..48bcec0 100644 --- a/examples/model-ui/refund-system-map/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/refund-system-map/captures/gpt56-sol-low-codex-judgmentkit-material-ui.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "65df5f708386c7ff1c02909ec18bfe2a3e6da72ea93d7f6ec0899fb14a8c4618", + "current_source_context_sha256": "47f8bffb0b1ede02abb1ec7614260d43cd2c5cfbac8900b6cdf34e9fe871146f", "accepted_source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "c659a3708b454999c97408c454852adb42c4b82a38dbceebca1b9877aa43070a", diff --git a/examples/model-ui/refund-system-map/captures/gpt56-sol-low-codex-with-judgmentkit.json b/examples/model-ui/refund-system-map/captures/gpt56-sol-low-codex-with-judgmentkit.json index b5eee71..051974b 100644 --- a/examples/model-ui/refund-system-map/captures/gpt56-sol-low-codex-with-judgmentkit.json +++ b/examples/model-ui/refund-system-map/captures/gpt56-sol-low-codex-with-judgmentkit.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "a552719ba51c97db00c84a21c2eac4f5eaf0cc53f281c650e6f2f8c207965eec", + "current_source_context_sha256": "30b33d69c324626be4c0700ddd4815cff0bc26de3916405648aa48ffc762c242", "accepted_source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "bccd80abf570ad7344b1cfec8b8d5fc0c9dc884581816f200f2d75038b02fb3a", diff --git a/examples/model-ui/refund-system-map/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json b/examples/model-ui/refund-system-map/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json index e8b5f2c..04d3f61 100644 --- a/examples/model-ui/refund-system-map/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json +++ b/examples/model-ui/refund-system-map/captures/gpt56-sol-ultra-codex-judgmentkit-material-ui.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "14f1e278c94ad1827608195b9f46e1156cf89e177184ebb773ff10e2c7e1f0ad", + "current_source_context_sha256": "99266252a708f96c7bdd5395fa7aca1c342df9cbf79310507c3c7fc0b3fca593", "accepted_source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "c659a3708b454999c97408c454852adb42c4b82a38dbceebca1b9877aa43070a", diff --git a/examples/model-ui/refund-system-map/captures/gpt56-sol-ultra-codex-with-judgmentkit.json b/examples/model-ui/refund-system-map/captures/gpt56-sol-ultra-codex-with-judgmentkit.json index 9821a36..121b4a9 100644 --- a/examples/model-ui/refund-system-map/captures/gpt56-sol-ultra-codex-with-judgmentkit.json +++ b/examples/model-ui/refund-system-map/captures/gpt56-sol-ultra-codex-with-judgmentkit.json @@ -76,7 +76,7 @@ }, "source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", "source_context_status": "legacy_accepted", - "current_source_context_sha256": "1b115c677b968effdb063e306dc3157de353fc59a4a71034f83554f11405736e", + "current_source_context_sha256": "f68f180dc8f17b2c42ee21148d26a0a42d92a7b2bb30e6e88fc70e940179182c", "accepted_source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", "prompt_sha256": "bccd80abf570ad7344b1cfec8b8d5fc0c9dc884581816f200f2d75038b02fb3a", diff --git a/examples/model-ui/refund-system-map/manifest.json b/examples/model-ui/refund-system-map/manifest.json index 62e31ef..8ebf4e4 100644 --- a/examples/model-ui/refund-system-map/manifest.json +++ b/examples/model-ui/refund-system-map/manifest.json @@ -194,8 +194,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", - "accepted_source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", + "current_source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", + "accepted_source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -204,8 +204,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", - "current_source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", + "source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", + "current_source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -396,8 +396,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", - "accepted_source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", + "current_source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", + "accepted_source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -406,8 +406,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", - "current_source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", + "source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", + "current_source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -851,7 +851,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "89c3848de86d1cb0d765720a008e7d369503ee263d72ce6687ee0e854f59b3b3", + "current_source_context_sha256": "6fde9db5f9033c53c07f70edf44e48bbabca27cfa68d9b121217cdf2f53a75c3", "accepted_source_context_sha256": "9ac132c121d01a8bb5d46d2c69c8550392a2c12465cb763faa018ad84df09005", "captured_source_context_sha256": "9ac132c121d01a8bb5d46d2c69c8550392a2c12465cb763faa018ad84df09005", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -872,7 +872,7 @@ "capture_quality": null, "prompt_sha256": "091e82e11e7a53f30d2009eacbfe0bb9634ea6cda9df429fd414600705230d2c", "source_context_sha256": "9ac132c121d01a8bb5d46d2c69c8550392a2c12465cb763faa018ad84df09005", - "current_source_context_sha256": "89c3848de86d1cb0d765720a008e7d369503ee263d72ce6687ee0e854f59b3b3", + "current_source_context_sha256": "6fde9db5f9033c53c07f70edf44e48bbabca27cfa68d9b121217cdf2f53a75c3", "source_context_status": "legacy_accepted", "raw_response_sha256": "55054bde4ded9aa9a9dde76a39382f145cf7de8967a9036899bd2af7f74197d5", "frontend_context_status": "ready_for_frontend_implementation", @@ -1269,7 +1269,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "294383e386065d72efb01390cac018bb51f9391f7fb352a62d66b68f7888b32a", + "current_source_context_sha256": "ea11fdd2edfb47a86a365e65c4528e9b0db2be47c04fc982d1ab7f71de03593c", "accepted_source_context_sha256": "5ad2fd84f91850b16be0a4100df01bec39ae3046ccdcdc4f9b7413b3b685a807", "captured_source_context_sha256": "5ad2fd84f91850b16be0a4100df01bec39ae3046ccdcdc4f9b7413b3b685a807", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -1284,7 +1284,7 @@ "capture_quality": null, "prompt_sha256": "c471caecb1b08137854b77791282e6c107e0093329224570a05fc746f5c7eeb6", "source_context_sha256": "5ad2fd84f91850b16be0a4100df01bec39ae3046ccdcdc4f9b7413b3b685a807", - "current_source_context_sha256": "294383e386065d72efb01390cac018bb51f9391f7fb352a62d66b68f7888b32a", + "current_source_context_sha256": "ea11fdd2edfb47a86a365e65c4528e9b0db2be47c04fc982d1ab7f71de03593c", "source_context_status": "legacy_accepted", "raw_response_sha256": "79e90ae35044dc335ba3ab7e7be88b2d2c44081256d470b054f2ad3ea3b05b17", "frontend_context_status": "ready_for_frontend_implementation", @@ -2458,7 +2458,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "a552719ba51c97db00c84a21c2eac4f5eaf0cc53f281c650e6f2f8c207965eec", + "current_source_context_sha256": "30b33d69c324626be4c0700ddd4815cff0bc26de3916405648aa48ffc762c242", "accepted_source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", "captured_source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -2500,7 +2500,7 @@ }, "prompt_sha256": "bccd80abf570ad7344b1cfec8b8d5fc0c9dc884581816f200f2d75038b02fb3a", "source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", - "current_source_context_sha256": "a552719ba51c97db00c84a21c2eac4f5eaf0cc53f281c650e6f2f8c207965eec", + "current_source_context_sha256": "30b33d69c324626be4c0700ddd4815cff0bc26de3916405648aa48ffc762c242", "source_context_status": "legacy_accepted", "raw_response_sha256": "66ab69ee772ee0635b9f18583be099665b383d570c20855687c5ad13bf7e4b4f", "frontend_context_status": "ready_for_frontend_implementation", @@ -2723,7 +2723,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "65df5f708386c7ff1c02909ec18bfe2a3e6da72ea93d7f6ec0899fb14a8c4618", + "current_source_context_sha256": "47f8bffb0b1ede02abb1ec7614260d43cd2c5cfbac8900b6cdf34e9fe871146f", "accepted_source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", "captured_source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -2738,7 +2738,7 @@ "capture_quality": null, "prompt_sha256": "c659a3708b454999c97408c454852adb42c4b82a38dbceebca1b9877aa43070a", "source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", - "current_source_context_sha256": "65df5f708386c7ff1c02909ec18bfe2a3e6da72ea93d7f6ec0899fb14a8c4618", + "current_source_context_sha256": "47f8bffb0b1ede02abb1ec7614260d43cd2c5cfbac8900b6cdf34e9fe871146f", "source_context_status": "legacy_accepted", "raw_response_sha256": "f8f8cfd233d2bc716d7477cb3c5beea7cfe80ad02f76183c2bb76089accc5c79", "frontend_context_status": "ready_for_frontend_implementation", @@ -4417,7 +4417,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "1b115c677b968effdb063e306dc3157de353fc59a4a71034f83554f11405736e", + "current_source_context_sha256": "f68f180dc8f17b2c42ee21148d26a0a42d92a7b2bb30e6e88fc70e940179182c", "accepted_source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", "captured_source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -4459,7 +4459,7 @@ }, "prompt_sha256": "bccd80abf570ad7344b1cfec8b8d5fc0c9dc884581816f200f2d75038b02fb3a", "source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", - "current_source_context_sha256": "1b115c677b968effdb063e306dc3157de353fc59a4a71034f83554f11405736e", + "current_source_context_sha256": "f68f180dc8f17b2c42ee21148d26a0a42d92a7b2bb30e6e88fc70e940179182c", "source_context_status": "legacy_accepted", "raw_response_sha256": "6de7f7a4299e22a71c381a18ab12b57ca4f2446c1adf06f4a22495955eb5511d", "frontend_context_status": "ready_for_frontend_implementation", @@ -4682,7 +4682,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "14f1e278c94ad1827608195b9f46e1156cf89e177184ebb773ff10e2c7e1f0ad", + "current_source_context_sha256": "99266252a708f96c7bdd5395fa7aca1c342df9cbf79310507c3c7fc0b3fca593", "accepted_source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", "captured_source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -4697,7 +4697,7 @@ "capture_quality": null, "prompt_sha256": "c659a3708b454999c97408c454852adb42c4b82a38dbceebca1b9877aa43070a", "source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", - "current_source_context_sha256": "14f1e278c94ad1827608195b9f46e1156cf89e177184ebb773ff10e2c7e1f0ad", + "current_source_context_sha256": "99266252a708f96c7bdd5395fa7aca1c342df9cbf79310507c3c7fc0b3fca593", "source_context_status": "legacy_accepted", "raw_response_sha256": "e9f5d848662225af454d33e873827d01f0f0da2ec7dd3f6eb824800a9a7a238e", "frontend_context_status": "ready_for_frontend_implementation", @@ -4936,8 +4936,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", - "accepted_source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", + "current_source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", + "accepted_source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -4946,8 +4946,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", - "current_source_context_sha256": "609de94c163691197a95f1f02134731ce86908b105dac979f08583350a38d895", + "source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", + "current_source_context_sha256": "d72e09f9d0cd46e585582e534406b9ac49c8bf751c9b721f6a7bbbcfa8387bbf", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -5138,8 +5138,8 @@ "frontend_skill_context_status": "ready", "capture_quality": null, "source_context_status": "current", - "current_source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", - "accepted_source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", + "current_source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", + "accepted_source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", "captured_source_context_sha256": null, "source_context_notes": "Capture transcript source context matches the current generated matrix context.", "notes": "Scripted from fixed fixtures and local renderer code. No model generation is used." @@ -5148,8 +5148,8 @@ "lms_context": null, "capture_quality": null, "prompt_sha256": null, - "source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", - "current_source_context_sha256": "611c4f4490d402a791fc633328de94222701fca848c105e16b824521efd5d91e", + "source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", + "current_source_context_sha256": "d555716b4f3b0480d02e3b13269fcd4316a0b641338e9ba4e8db1065ae27a4a0", "source_context_status": "current", "raw_response_sha256": null, "frontend_context_status": "ready_for_frontend_implementation", @@ -5539,7 +5539,7 @@ }, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "89c3848de86d1cb0d765720a008e7d369503ee263d72ce6687ee0e854f59b3b3", + "current_source_context_sha256": "6fde9db5f9033c53c07f70edf44e48bbabca27cfa68d9b121217cdf2f53a75c3", "accepted_source_context_sha256": "9ac132c121d01a8bb5d46d2c69c8550392a2c12465cb763faa018ad84df09005", "captured_source_context_sha256": "9ac132c121d01a8bb5d46d2c69c8550392a2c12465cb763faa018ad84df09005", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -5560,7 +5560,7 @@ "capture_quality": null, "prompt_sha256": "091e82e11e7a53f30d2009eacbfe0bb9634ea6cda9df429fd414600705230d2c", "source_context_sha256": "9ac132c121d01a8bb5d46d2c69c8550392a2c12465cb763faa018ad84df09005", - "current_source_context_sha256": "89c3848de86d1cb0d765720a008e7d369503ee263d72ce6687ee0e854f59b3b3", + "current_source_context_sha256": "6fde9db5f9033c53c07f70edf44e48bbabca27cfa68d9b121217cdf2f53a75c3", "source_context_status": "legacy_accepted", "raw_response_sha256": "55054bde4ded9aa9a9dde76a39382f145cf7de8967a9036899bd2af7f74197d5", "frontend_context_status": "ready_for_frontend_implementation", @@ -5903,7 +5903,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "294383e386065d72efb01390cac018bb51f9391f7fb352a62d66b68f7888b32a", + "current_source_context_sha256": "ea11fdd2edfb47a86a365e65c4528e9b0db2be47c04fc982d1ab7f71de03593c", "accepted_source_context_sha256": "5ad2fd84f91850b16be0a4100df01bec39ae3046ccdcdc4f9b7413b3b685a807", "captured_source_context_sha256": "5ad2fd84f91850b16be0a4100df01bec39ae3046ccdcdc4f9b7413b3b685a807", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -5918,7 +5918,7 @@ "capture_quality": null, "prompt_sha256": "c471caecb1b08137854b77791282e6c107e0093329224570a05fc746f5c7eeb6", "source_context_sha256": "5ad2fd84f91850b16be0a4100df01bec39ae3046ccdcdc4f9b7413b3b685a807", - "current_source_context_sha256": "294383e386065d72efb01390cac018bb51f9391f7fb352a62d66b68f7888b32a", + "current_source_context_sha256": "ea11fdd2edfb47a86a365e65c4528e9b0db2be47c04fc982d1ab7f71de03593c", "source_context_status": "legacy_accepted", "raw_response_sha256": "79e90ae35044dc335ba3ab7e7be88b2d2c44081256d470b054f2ad3ea3b05b17", "frontend_context_status": "ready_for_frontend_implementation", @@ -7039,7 +7039,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "a552719ba51c97db00c84a21c2eac4f5eaf0cc53f281c650e6f2f8c207965eec", + "current_source_context_sha256": "30b33d69c324626be4c0700ddd4815cff0bc26de3916405648aa48ffc762c242", "accepted_source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", "captured_source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -7081,7 +7081,7 @@ }, "prompt_sha256": "bccd80abf570ad7344b1cfec8b8d5fc0c9dc884581816f200f2d75038b02fb3a", "source_context_sha256": "3ef3d7841b10511bee0979c1afd8800a64b5b79fb4a9ae13f3d36f7fa54b1f32", - "current_source_context_sha256": "a552719ba51c97db00c84a21c2eac4f5eaf0cc53f281c650e6f2f8c207965eec", + "current_source_context_sha256": "30b33d69c324626be4c0700ddd4815cff0bc26de3916405648aa48ffc762c242", "source_context_status": "legacy_accepted", "raw_response_sha256": "66ab69ee772ee0635b9f18583be099665b383d570c20855687c5ad13bf7e4b4f", "frontend_context_status": "ready_for_frontend_implementation", @@ -7304,7 +7304,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "65df5f708386c7ff1c02909ec18bfe2a3e6da72ea93d7f6ec0899fb14a8c4618", + "current_source_context_sha256": "47f8bffb0b1ede02abb1ec7614260d43cd2c5cfbac8900b6cdf34e9fe871146f", "accepted_source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", "captured_source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -7319,7 +7319,7 @@ "capture_quality": null, "prompt_sha256": "c659a3708b454999c97408c454852adb42c4b82a38dbceebca1b9877aa43070a", "source_context_sha256": "d9c0b71c47bbcdddb048db91f5d590c6bc3c0c279d36fca33f81a48a05c82f02", - "current_source_context_sha256": "65df5f708386c7ff1c02909ec18bfe2a3e6da72ea93d7f6ec0899fb14a8c4618", + "current_source_context_sha256": "47f8bffb0b1ede02abb1ec7614260d43cd2c5cfbac8900b6cdf34e9fe871146f", "source_context_status": "legacy_accepted", "raw_response_sha256": "f8f8cfd233d2bc716d7477cb3c5beea7cfe80ad02f76183c2bb76089accc5c79", "frontend_context_status": "ready_for_frontend_implementation", @@ -8945,7 +8945,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "1b115c677b968effdb063e306dc3157de353fc59a4a71034f83554f11405736e", + "current_source_context_sha256": "f68f180dc8f17b2c42ee21148d26a0a42d92a7b2bb30e6e88fc70e940179182c", "accepted_source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", "captured_source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -8987,7 +8987,7 @@ }, "prompt_sha256": "bccd80abf570ad7344b1cfec8b8d5fc0c9dc884581816f200f2d75038b02fb3a", "source_context_sha256": "4ff85ee789f3e6eaa5cc3d9c7e8d9a0153ea3f74fc161e318cc13434987d4711", - "current_source_context_sha256": "1b115c677b968effdb063e306dc3157de353fc59a4a71034f83554f11405736e", + "current_source_context_sha256": "f68f180dc8f17b2c42ee21148d26a0a42d92a7b2bb30e6e88fc70e940179182c", "source_context_status": "legacy_accepted", "raw_response_sha256": "6de7f7a4299e22a71c381a18ab12b57ca4f2446c1adf06f4a22495955eb5511d", "frontend_context_status": "ready_for_frontend_implementation", @@ -9210,7 +9210,7 @@ "lms_context": null, "capture_quality": null, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "14f1e278c94ad1827608195b9f46e1156cf89e177184ebb773ff10e2c7e1f0ad", + "current_source_context_sha256": "99266252a708f96c7bdd5395fa7aca1c342df9cbf79310507c3c7fc0b3fca593", "accepted_source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", "captured_source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -9225,7 +9225,7 @@ "capture_quality": null, "prompt_sha256": "c659a3708b454999c97408c454852adb42c4b82a38dbceebca1b9877aa43070a", "source_context_sha256": "f30b4a0322c9f9329d0c178948700c523fece1e246db91c7b97105b37a15ca92", - "current_source_context_sha256": "14f1e278c94ad1827608195b9f46e1156cf89e177184ebb773ff10e2c7e1f0ad", + "current_source_context_sha256": "99266252a708f96c7bdd5395fa7aca1c342df9cbf79310507c3c7fc0b3fca593", "source_context_status": "legacy_accepted", "raw_response_sha256": "e9f5d848662225af454d33e873827d01f0f0da2ec7dd3f6eb824800a9a7a238e", "frontend_context_status": "ready_for_frontend_implementation", @@ -9380,7 +9380,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "ca29744cc607323788099bc0a8eb09f4ce7567cda35fd2d38f76016d11d46290", + "current_source_context_sha256": "e82707a158fe77056752c820eae91eb8842760fbd40bee006588176c376f97a9", "accepted_source_context_sha256": "61230da7c0d2ff5655e04513a3565f2c1a070abe21b80568036ea1b702466385", "captured_source_context_sha256": "61230da7c0d2ff5655e04513a3565f2c1a070abe21b80568036ea1b702466385", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -9563,7 +9563,7 @@ }, "prompt_sha256": "db2f38c85a8cf938614b009923b19a2171153e782853b0545566e067be04812a", "source_context_sha256": "61230da7c0d2ff5655e04513a3565f2c1a070abe21b80568036ea1b702466385", - "current_source_context_sha256": "ca29744cc607323788099bc0a8eb09f4ce7567cda35fd2d38f76016d11d46290", + "current_source_context_sha256": "e82707a158fe77056752c820eae91eb8842760fbd40bee006588176c376f97a9", "source_context_status": "legacy_accepted", "raw_response_sha256": "3246be9b9e22d0ee3f5c8bef547ed8bdad5837b135ed32138596ff94711fb577", "frontend_context_status": "ready_for_frontend_implementation", @@ -9697,7 +9697,7 @@ "status": "passed" }, "source_context_status": "legacy_accepted", - "current_source_context_sha256": "55b4011e3fc8a0a924969bb8e50eed7bcc8aa5da086b845dcf0e617cfe0d4fac", + "current_source_context_sha256": "f961ede0fac585bce21606e27a92938ea0ba3cb744a5a9a691d4a8c6962edd23", "accepted_source_context_sha256": "2b0cee90315bc5e13da9140a71d11682b601773589b8b0b53a37e275a83dfd90", "captured_source_context_sha256": "2b0cee90315bc5e13da9140a71d11682b601773589b8b0b53a37e275a83dfd90", "source_context_notes": "Capture transcript predates the current generated matrix context and is retained as an explicitly marked legacy capture until recaptured.", @@ -10335,7 +10335,7 @@ }, "prompt_sha256": "901d8b134e28c00954a971e4fd6b5902e454ace1391c198764c639702407ebb0", "source_context_sha256": "2b0cee90315bc5e13da9140a71d11682b601773589b8b0b53a37e275a83dfd90", - "current_source_context_sha256": "55b4011e3fc8a0a924969bb8e50eed7bcc8aa5da086b845dcf0e617cfe0d4fac", + "current_source_context_sha256": "f961ede0fac585bce21606e27a92938ea0ba3cb744a5a9a691d4a8c6962edd23", "source_context_status": "legacy_accepted", "raw_response_sha256": "9cf25babe75d7ae4ad1d7d31afb268eac51b4c68d6ddbb024146183e84bb14df", "frontend_context_status": "ready_for_frontend_implementation", 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 4a941a3..2b79bfe 100644 --- a/examples/model-ui/refund-system-map/reviewed-handoff.fixture.json +++ b/examples/model-ui/refund-system-map/reviewed-handoff.fixture.json @@ -1,5 +1,5 @@ { - "version": "0.7.0", + "version": "0.8.0", "contract_id": "judgmentkit.ai-ui-generation.activity-contract", "handoff_status": "ready_for_generation", "source": { From e35400507937f3025856912f8642cd3978ea35a8 Mon Sep 17 00:00:00 2001 From: Mike Long Date: Sun, 30 Aug 2026 14:37:26 -0700 Subject: [PATCH 4/4] Enforce canonical Artifact Inspector completion --- src/index.mjs | 38 +++++++++++++++------- tests/artifact-inspector-workflow.test.mjs | 27 +++++++++++++++ 2 files changed, 54 insertions(+), 11 deletions(-) diff --git a/src/index.mjs b/src/index.mjs index 9aab92f..4f6e708 100644 --- a/src/index.mjs +++ b/src/index.mjs @@ -5189,6 +5189,11 @@ function buildArtifactInspectorWorkflowDiagnostics( const topologyContract = normalizeArtifactTopologyContract(candidate, contract, { force: true, }); + const canonicalTopology = isPlainObject( + getArtifactInspectorModel(contract)?.topology, + ) + ? getArtifactInspectorModel(contract).topology + : {}; const workUnits = toWorkflowWorkUnitArray(workflow.work_units); const workUnitIds = workflowWorkUnitIds(workUnits); const diagnostics = []; @@ -5552,44 +5557,55 @@ function buildArtifactInspectorWorkflowDiagnostics( } const entryWorkUnitId = optionalString(topologyContract?.entry_work_unit_id); + const canonicalEntryWorkUnitId = optionalString( + canonicalTopology.entry_work_unit_id, + ); if ( topologyContract && - (!entryWorkUnitId || !workUnitIds.includes(entryWorkUnitId)) + (!entryWorkUnitId || + entryWorkUnitId !== canonicalEntryWorkUnitId || + !workUnitIds.includes(entryWorkUnitId)) ) { push({ code: "JK_ARTIFACT_INSPECTOR_ENTRY_REFERENCE_INVALID", field: "workflow.topology.entry_work_unit_id", - meaning: "The topology entry does not reference a declared work unit.", - expected: workUnitIds, + meaning: "The topology entry does not preserve the canonical entry work unit.", + expected: canonicalEntryWorkUnitId, observed: entryWorkUnitId || null, - repair_instruction: "Reference one declared workflow.work_units id as the topology entry.", + repair_instruction: `Set the topology entry to the canonical "${canonicalEntryWorkUnitId}" work unit.`, }); } const completionWorkUnitIds = toStringArray( topologyContract?.completion_work_unit_ids, ); + const canonicalCompletionWorkUnitIds = toStringArray( + canonicalTopology.completion_work_unit_ids, + ); const invalidCompletionIds = completionWorkUnitIds.filter( (id) => !workUnitIds.includes(id), ); + const completionContractMismatch = + completionWorkUnitIds.length !== canonicalCompletionWorkUnitIds.length || + canonicalCompletionWorkUnitIds.some( + (workUnitId, index) => completionWorkUnitIds[index] !== workUnitId, + ); if ( topologyContract && (completionWorkUnitIds.length === 0 || invalidCompletionIds.length > 0 || - !completionWorkUnitIds.includes("verify_result")) + completionContractMismatch) ) { push({ code: "JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID", field: "workflow.topology.completion_work_unit_ids", - meaning: "Artifact-local completion does not reference declared work units.", - expected: { - declared_work_unit_ids: workUnitIds, - required_artifact_local_completion: "verify_result", - }, + meaning: "Artifact-local completion does not preserve the canonical completion set.", + expected: canonicalCompletionWorkUnitIds, observed: completionWorkUnitIds, - repair_instruction: "Reference one or more declared work-unit ids that visibly complete the artifact-local activity.", + repair_instruction: + "Restore the ordered canonical completion work-unit ids for artifact-local verification and return to orientation.", }); } diff --git a/tests/artifact-inspector-workflow.test.mjs b/tests/artifact-inspector-workflow.test.mjs index 848dd17..294edfc 100644 --- a/tests/artifact-inspector-workflow.test.mjs +++ b/tests/artifact-inspector-workflow.test.mjs @@ -2453,6 +2453,14 @@ const MALFORMED_CASES = [ code: "JK_ARTIFACT_INSPECTOR_ENTRY_REFERENCE_INVALID", field: "workflow.topology.entry_work_unit_id", }, + { + label: "noncanonical declared entry reference", + mutate(candidate) { + candidate.workflow.topology.entry_work_unit_id = "select_locus"; + }, + code: "JK_ARTIFACT_INSPECTOR_ENTRY_REFERENCE_INVALID", + field: "workflow.topology.entry_work_unit_id", + }, { label: "invalid completion reference", mutate(candidate) { @@ -2471,6 +2479,25 @@ const MALFORMED_CASES = [ code: "JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID", field: "workflow.topology.completion_work_unit_ids", }, + { + label: "completion omits canonical return to orientation", + mutate(candidate) { + candidate.workflow.topology.completion_work_unit_ids = ["verify_result"]; + }, + code: "JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID", + field: "workflow.topology.completion_work_unit_ids", + }, + { + label: "completion reverses canonical ordering", + mutate(candidate) { + candidate.workflow.topology.completion_work_unit_ids = [ + "orient", + "verify_result", + ]; + }, + code: "JK_ARTIFACT_INSPECTOR_COMPLETION_REFERENCE_INVALID", + field: "workflow.topology.completion_work_unit_ids", + }, { label: "invalid transition reference", mutate(candidate) {