1342 lines
48 KiB
TypeScript
1342 lines
48 KiB
TypeScript
|
|
/**
|
||
|
|
* Canonical diagnostic code registry for Imhotep.
|
||
|
|
*
|
||
|
|
* Every diagnostic code in the system is declared here with its
|
||
|
|
* canonical severity, category, and human-readable message template.
|
||
|
|
*
|
||
|
|
* Invariant: no package may invent a diagnostic code that is not
|
||
|
|
* registered in this file. Adding a new code requires adding it
|
||
|
|
* here first.
|
||
|
|
*
|
||
|
|
* NOTE: This file is kept for backward compatibility. The canonical
|
||
|
|
* type definition lives in imhotep-core/src/diagnostics.ts.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import type { DiagnosticCode } from 'imhotep-core';
|
||
|
|
|
||
|
|
export type Severity = 'error' | 'warning' | 'info';
|
||
|
|
|
||
|
|
export type Category =
|
||
|
|
| 'parse-error'
|
||
|
|
| 'validation-error'
|
||
|
|
| 'resolution-error'
|
||
|
|
| 'extraction-error'
|
||
|
|
| 'contract-failure'
|
||
|
|
| 'indeterminate-result'
|
||
|
|
| 'internal-error';
|
||
|
|
|
||
|
|
export interface CodeEntry {
|
||
|
|
code: DiagnosticCode;
|
||
|
|
severity: Severity;
|
||
|
|
category: Category;
|
||
|
|
message: string;
|
||
|
|
fixHints: string[];
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Parse errors
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_PARSE_UNEXPECTED_TOKEN = 'IMH_PARSE_UNEXPECTED_TOKEN' as const;
|
||
|
|
export const IMH_PARSE_INVALID_SYNTAX = 'IMH_PARSE_INVALID_SYNTAX' as const;
|
||
|
|
export const IMH_PARSE_UNTERMINATED_BLOCK = 'IMH_PARSE_UNTERMINATED_BLOCK' as const;
|
||
|
|
export const IMH_PARSE_ERROR = 'IMH_PARSE_ERROR' as const;
|
||
|
|
export const IMH_PARSE_IS_KEYWORD = 'IMH_PARSE_IS_KEYWORD' as const;
|
||
|
|
export const IMH_PARSE_MISSING_QUOTES = 'IMH_PARSE_MISSING_QUOTES' as const;
|
||
|
|
export const IMH_PARSE_WRONG_QUOTE_STYLE = 'IMH_PARSE_WRONG_QUOTE_STYLE' as const;
|
||
|
|
export const IMH_PARSE_MISSING_UNIT = 'IMH_PARSE_MISSING_UNIT' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Validation errors
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_VALID_ILLEGAL_RELATION_OPTION = 'IMH_VALID_ILLEGAL_RELATION_OPTION' as const;
|
||
|
|
export const IMH_VALID_INVALID_UNIT = 'IMH_VALID_INVALID_UNIT' as const;
|
||
|
|
export const IMH_VALID_INVALID_STATE_TIMELINE = 'IMH_VALID_INVALID_STATE_TIMELINE' as const;
|
||
|
|
export const IMH_VALID_INVALID_ENV_GUARD = 'IMH_VALID_INVALID_ENV_GUARD' as const;
|
||
|
|
export const IMH_VALID_INVALID_QUANTIFIER_NESTING = 'IMH_VALID_INVALID_QUANTIFIER_NESTING' as const;
|
||
|
|
export const IMH_VALID_CONTRADICTION = 'IMH_VALID_CONTRADICTION' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Resolution errors
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_SELECTOR_ZERO_MATCHES = 'IMH_SELECTOR_ZERO_MATCHES' as const;
|
||
|
|
export const IMH_SELECTOR_AMBIGUOUS = 'IMH_SELECTOR_AMBIGUOUS' as const;
|
||
|
|
export const IMH_SELECTOR_NO_MATCH = 'IMH_SELECTOR_NO_MATCH' as const;
|
||
|
|
export const IMH_SELECTOR_RESOLUTION_FAILED = 'IMH_SELECTOR_RESOLUTION_FAILED' as const;
|
||
|
|
export const IMH_FRAME_AMBIGUOUS = 'IMH_FRAME_AMBIGUOUS' as const;
|
||
|
|
export const IMH_FRAME_UNSUPPORTED = 'IMH_FRAME_UNSUPPORTED' as const;
|
||
|
|
export const IMH_TOPOLOGY_UNSUPPORTED = 'IMH_TOPOLOGY_UNSUPPORTED' as const;
|
||
|
|
export const IMH_STATE_MATERIALIZATION_FAILED = 'IMH_STATE_MATERIALIZATION_FAILED' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Extraction errors
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_EXTRACT_PARTIAL = 'IMH_EXTRACT_PARTIAL' as const;
|
||
|
|
export const IMH_EXTRACT_UNAVAILABLE_FACT = 'IMH_EXTRACT_UNAVAILABLE_FACT' as const;
|
||
|
|
export const IMH_EXTRACT_PROTOCOL_ERROR = 'IMH_EXTRACT_PROTOCOL_ERROR' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// CDP errors
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_CDP_SESSION_ATTACH_FAILED = 'IMH_CDP_SESSION_ATTACH_FAILED' as const;
|
||
|
|
export const IMH_DOM_EXTRACTION_FAILED = 'IMH_DOM_EXTRACTION_FAILED' as const;
|
||
|
|
export const IMH_SELECTOR_RESOLUTION_FAILED_CDP = 'IMH_SELECTOR_RESOLUTION_FAILED' as const;
|
||
|
|
export const IMH_BOX_MODEL_PARTIAL = 'IMH_BOX_MODEL_PARTIAL' as const;
|
||
|
|
export const IMH_BOX_MODEL_FAILED = 'IMH_BOX_MODEL_FAILED' as const;
|
||
|
|
export const IMH_VISUAL_BOX_PARTIAL = 'IMH_VISUAL_BOX_PARTIAL' as const;
|
||
|
|
export const IMH_VISUAL_BOX_FAILED = 'IMH_VISUAL_BOX_FAILED' as const;
|
||
|
|
export const IMH_FRAGMENT_PARTIAL = 'IMH_FRAGMENT_PARTIAL' as const;
|
||
|
|
export const IMH_FRAGMENT_FAILED = 'IMH_FRAGMENT_FAILED' as const;
|
||
|
|
export const IMH_TRANSFORM_PARTIAL = 'IMH_TRANSFORM_PARTIAL' as const;
|
||
|
|
export const IMH_TRANSFORM_FAILED = 'IMH_TRANSFORM_FAILED' as const;
|
||
|
|
export const IMH_STYLE_PARTIAL = 'IMH_STYLE_PARTIAL' as const;
|
||
|
|
export const IMH_STYLE_FAILED = 'IMH_STYLE_FAILED' as const;
|
||
|
|
export const IMH_TOPOLOGY_PARTIAL = 'IMH_TOPOLOGY_PARTIAL' as const;
|
||
|
|
export const IMH_TOPOLOGY_FAILED = 'IMH_TOPOLOGY_FAILED' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Extractor planner errors
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_EXTRACTOR_EMPTY_SELECTOR = 'IMH_EXTRACTOR_EMPTY_SELECTOR' as const;
|
||
|
|
export const IMH_EXTRACTOR_MISSING_ENV_GUARD = 'IMH_EXTRACTOR_MISSING_ENV_GUARD' as const;
|
||
|
|
export const IMH_EXTRACTOR_UNRESOLVED_ENV_GUARD = 'IMH_EXTRACTOR_UNRESOLVED_ENV_GUARD' as const;
|
||
|
|
export const IMH_EXTRACTOR_MISSING_STATE = 'IMH_EXTRACTOR_MISSING_STATE' as const;
|
||
|
|
export const IMH_EXTRACTOR_UNRESOLVED_STATE = 'IMH_EXTRACTOR_UNRESOLVED_STATE' as const;
|
||
|
|
export const IMH_EXTRACTOR_UNSUPPORTED_STATE = 'IMH_EXTRACTOR_UNSUPPORTED_STATE' as const;
|
||
|
|
export const IMH_EXTRACTOR_NON_STATIC_TIMELINE = 'IMH_EXTRACTOR_NON_STATIC_TIMELINE' as const;
|
||
|
|
export const IMH_EXTRACTOR_UNSUPPORTED_CLAUSE_TYPE = 'IMH_EXTRACTOR_UNSUPPORTED_CLAUSE_TYPE' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Contract failures
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_RELATION_LEFT_OF_FAILED = 'IMH_RELATION_LEFT_OF_FAILED' as const;
|
||
|
|
export const IMH_RELATION_RIGHT_OF_FAILED = 'IMH_RELATION_RIGHT_OF_FAILED' as const;
|
||
|
|
export const IMH_RELATION_ABOVE_FAILED = 'IMH_RELATION_ABOVE_FAILED' as const;
|
||
|
|
export const IMH_RELATION_BELOW_FAILED = 'IMH_RELATION_BELOW_FAILED' as const;
|
||
|
|
export const IMH_RELATION_ALIGNED_FAILED = 'IMH_RELATION_ALIGNED_FAILED' as const;
|
||
|
|
export const IMH_RELATION_CENTERED_FAILED = 'IMH_RELATION_CENTERED_FAILED' as const;
|
||
|
|
export const IMH_RELATION_INSIDE_FAILED = 'IMH_RELATION_INSIDE_FAILED' as const;
|
||
|
|
export const IMH_RELATION_CONTAINS_FAILED = 'IMH_RELATION_CONTAINS_FAILED' as const;
|
||
|
|
export const IMH_RELATION_OVERLAPS_FAILED = 'IMH_RELATION_OVERLAPS_FAILED' as const;
|
||
|
|
export const IMH_RELATION_BESIDE_FAILED = 'IMH_RELATION_BESIDE_FAILED' as const;
|
||
|
|
export const IMH_RELATION_ADJACENT_FAILED = 'IMH_RELATION_ADJACENT_FAILED' as const;
|
||
|
|
export const IMH_RELATION_NEAR_FAILED = 'IMH_RELATION_NEAR_FAILED' as const;
|
||
|
|
export const IMH_RELATION_FAILED = 'IMH_RELATION_FAILED' as const;
|
||
|
|
export const IMH_ALIGNMENT_FAILED = 'IMH_ALIGNMENT_FAILED' as const;
|
||
|
|
export const IMH_SIZE_AT_LEAST_FAILED = 'IMH_SIZE_AT_LEAST_FAILED' as const;
|
||
|
|
export const IMH_SIZE_AT_MOST_FAILED = 'IMH_SIZE_AT_MOST_FAILED' as const;
|
||
|
|
export const IMH_SIZE_BETWEEN_FAILED = 'IMH_SIZE_BETWEEN_FAILED' as const;
|
||
|
|
export const IMH_TOPOLOGY_CLIPPED_FAILED = 'IMH_TOPOLOGY_CLIPPED_FAILED' as const;
|
||
|
|
export const IMH_TOPOLOGY_STACKING_FAILED = 'IMH_TOPOLOGY_STACKING_FAILED' as const;
|
||
|
|
export const IMH_VISIBILITY_FAILED = 'IMH_VISIBILITY_FAILED' as const;
|
||
|
|
export const IMH_PREDICATE_FAILED = 'IMH_PREDICATE_FAILED' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Cardinality failures
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_CARDINALITY_EXACTLYONE_FAILED = 'IMH_CARDINALITY_EXACTLYONE_FAILED' as const;
|
||
|
|
export const IMH_CARDINALITY_ATLEASTN_FAILED = 'IMH_CARDINALITY_ATLEASTN_FAILED' as const;
|
||
|
|
export const IMH_CARDINALITY_ATMOSTN_FAILED = 'IMH_CARDINALITY_ATMOSTN_FAILED' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Indeterminate results
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_INDETERMINATE_MISSING_FACT = 'IMH_INDETERMINATE_MISSING_FACT' as const;
|
||
|
|
export const IMH_INDETERMINATE_UNSTABLE_INPUT = 'IMH_INDETERMINATE_UNSTABLE_INPUT' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Internal errors
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_INTERNAL_UNKNOWN_CLAUSE_KIND = 'IMH_INTERNAL_UNKNOWN_CLAUSE_KIND' as const;
|
||
|
|
export const IMH_INTERNAL_EVALUATION_EXCEPTION = 'IMH_INTERNAL_EVALUATION_EXCEPTION' as const;
|
||
|
|
export const IMH_FEATURE_NOT_YET_IMPLEMENTED = 'IMH_FEATURE_NOT_YET_IMPLEMENTED' as const;
|
||
|
|
export const IMH_UNKNOWN_FAILURE = 'IMH_UNKNOWN_FAILURE' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Solver / logic errors
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_LOGIC_UNKNOWN_FORMULA_KIND = 'IMH_LOGIC_UNKNOWN_FORMULA_KIND' as const;
|
||
|
|
export const IMH_LOGIC_DOMAIN_UNRESOLVED = 'IMH_LOGIC_DOMAIN_UNRESOLVED' as const;
|
||
|
|
export const IMH_LOGIC_VACUOUS_FORALL = 'IMH_LOGIC_VACUOUS_FORALL' as const;
|
||
|
|
export const IMH_LOGIC_EMPTY_DOMAIN_EXISTS = 'IMH_LOGIC_EMPTY_DOMAIN_EXISTS' as const;
|
||
|
|
export const IMH_LOGIC_PREDICATE_MISSING = 'IMH_LOGIC_PREDICATE_MISSING' as const;
|
||
|
|
export const IMH_LOGIC_UNBOUND_VARIABLE = 'IMH_LOGIC_UNBOUND_VARIABLE' as const;
|
||
|
|
export const IMH_LOGIC_UNSUPPORTED_TERM = 'IMH_LOGIC_UNSUPPORTED_TERM' as const;
|
||
|
|
export const IMH_LOGIC_UNKNOWN_NODE = 'IMH_LOGIC_UNKNOWN_NODE' as const;
|
||
|
|
export const IMH_LOGIC_ARITY_MISMATCH = 'IMH_LOGIC_ARITY_MISMATCH' as const;
|
||
|
|
export const IMH_LOGIC_UNKNOWN_PREDICATE = 'IMH_LOGIC_UNKNOWN_PREDICATE' as const;
|
||
|
|
export const IMH_LOGIC_FREE_VARIABLE = 'IMH_LOGIC_FREE_VARIABLE' as const;
|
||
|
|
export const IMH_LOGIC_EMPTY_DOMAIN = 'IMH_LOGIC_EMPTY_DOMAIN' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Solver engine errors
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_EVALUATOR_MISSING = 'IMH_EVALUATOR_MISSING' as const;
|
||
|
|
export const IMH_EVALUATOR_EXCEPTION = 'IMH_EVALUATOR_EXCEPTION' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Quantifier errors
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_QUANTIFIER_NO_SUBCLAUSES = 'IMH_QUANTIFIER_NO_SUBCLAUSES' as const;
|
||
|
|
export const IMH_PAIRWISE_INSUFFICIENT = 'IMH_PAIRWISE_INSUFFICIENT' as const;
|
||
|
|
export const IMH_UNKNOWN_QUANTIFIER = 'IMH_UNKNOWN_QUANTIFIER' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Fact observation diagnostics (used for rich contract-failure messages)
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_FACT_OBSERVED_GAP = 'IMH_FACT_OBSERVED_GAP' as const;
|
||
|
|
export const IMH_FACT_OBSERVED_SIZE = 'IMH_FACT_OBSERVED_SIZE' as const;
|
||
|
|
export const IMH_FACT_OBSERVED_TOPOLOGY = 'IMH_FACT_OBSERVED_TOPOLOGY' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Property-run diagnostics
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_ENUMERATED_RUN_ERROR = 'IMH_ENUMERATED_RUN_ERROR' as const;
|
||
|
|
export const IMH_SAMPLED_RUN_ERROR = 'IMH_SAMPLED_RUN_ERROR' as const;
|
||
|
|
export const IMH_PROPERTY_RUN_FAILED = 'IMH_PROPERTY_RUN_FAILED' as const;
|
||
|
|
export const IMH_PROPERTY_PASSED = 'IMH_PROPERTY_PASSED' as const;
|
||
|
|
export const IMH_PROPERTY_FAILED = 'IMH_PROPERTY_FAILED' as const;
|
||
|
|
export const IMH_PROPERTY_REPLAY = 'IMH_PROPERTY_REPLAY' as const;
|
||
|
|
export const IMH_PROPERTY_SHRUNK = 'IMH_PROPERTY_SHRUNK' as const;
|
||
|
|
export const IMH_ENUMERATED_PASSED = 'IMH_ENUMERATED_PASSED' as const;
|
||
|
|
export const IMH_ENUMERATED_FAILED = 'IMH_ENUMERATED_FAILED' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Reporter internal diagnostics
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
export const IMH_FRAME_CONTEXT = 'IMH_FRAME_CONTEXT' as const;
|
||
|
|
export const IMH_WITNESS_ENV = 'IMH_WITNESS_ENV' as const;
|
||
|
|
export const IMH_WITNESS_SNAPSHOT = 'IMH_WITNESS_SNAPSHOT' as const;
|
||
|
|
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
// Registry
|
||
|
|
// ---------------------------------------------------------------------------
|
||
|
|
|
||
|
|
const REGISTRY: Map<string, CodeEntry> = new Map([
|
||
|
|
// Parse
|
||
|
|
[IMH_PARSE_UNEXPECTED_TOKEN, {
|
||
|
|
code: IMH_PARSE_UNEXPECTED_TOKEN,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'parse-error',
|
||
|
|
message: 'Unexpected token in input.',
|
||
|
|
fixHints: [
|
||
|
|
'Check for misplaced punctuation or keywords.',
|
||
|
|
'Selectors must be single-quoted strings, e.g. \'[data-testid="x"]\'.',
|
||
|
|
'Use relation keywords directly without "is": e.g. \'a\' leftOf \'b\'.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PARSE_INVALID_SYNTAX, {
|
||
|
|
code: IMH_PARSE_INVALID_SYNTAX,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'parse-error',
|
||
|
|
message: 'Invalid syntax.',
|
||
|
|
fixHints: [
|
||
|
|
'Ensure selectors are wrapped in single quotes.',
|
||
|
|
'Use valid relation keywords: leftOf, rightOf, above, below, alignedWith, centeredWithin, inside, contains, overlaps.',
|
||
|
|
'Gap values require units: e.g. gap 8px or gap 8px..16px.',
|
||
|
|
'Remove the keyword "is": write \'.a\' leftOf \'.b\' instead of \'.a\' is leftOf \'.b\'.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PARSE_UNTERMINATED_BLOCK, {
|
||
|
|
code: IMH_PARSE_UNTERMINATED_BLOCK,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'parse-error',
|
||
|
|
message: 'Unterminated block.',
|
||
|
|
fixHints: [
|
||
|
|
'Close the block with proper indentation (2 or 4 spaces).',
|
||
|
|
'Ensure every opening keyword (all, any, none, forAll, exists) has a matching body.',
|
||
|
|
'Example: all \'.item\' leftOf \'.sidebar\'',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PARSE_ERROR, {
|
||
|
|
code: IMH_PARSE_ERROR,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'parse-error',
|
||
|
|
message: 'Parse error.',
|
||
|
|
fixHints: [
|
||
|
|
'Selectors must be single-quoted strings, e.g. \'[data-testid="x"]\'.',
|
||
|
|
'Use relation keywords directly without "is": e.g. \'a\' leftOf \'b\'.',
|
||
|
|
'Gap values require units: e.g. gap 8px.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PARSE_IS_KEYWORD, {
|
||
|
|
code: IMH_PARSE_IS_KEYWORD,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'parse-error',
|
||
|
|
message: 'Unexpected keyword "is".',
|
||
|
|
fixHints: [
|
||
|
|
'Remove "is" and write the relation directly, e.g. \'.a\' leftOf \'.b\'.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PARSE_MISSING_QUOTES, {
|
||
|
|
code: IMH_PARSE_MISSING_QUOTES,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'parse-error',
|
||
|
|
message: 'Selector must be wrapped in single quotes.',
|
||
|
|
fixHints: [
|
||
|
|
'Wrap selectors in single quotes: \'.class\' instead of .class.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PARSE_WRONG_QUOTE_STYLE, {
|
||
|
|
code: IMH_PARSE_WRONG_QUOTE_STYLE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'parse-error',
|
||
|
|
message: 'Double quotes are not allowed.',
|
||
|
|
fixHints: [
|
||
|
|
'Use single quotes: \'value\' instead of "value".',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PARSE_MISSING_UNIT, {
|
||
|
|
code: IMH_PARSE_MISSING_UNIT,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'parse-error',
|
||
|
|
message: 'Missing unit on gap value.',
|
||
|
|
fixHints: [
|
||
|
|
'Add a unit, e.g. gap 8px or gap 8px..16px.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Validation
|
||
|
|
[IMH_VALID_ILLEGAL_RELATION_OPTION, {
|
||
|
|
code: IMH_VALID_ILLEGAL_RELATION_OPTION,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'validation-error',
|
||
|
|
message: 'Illegal relation option.',
|
||
|
|
fixHints: [
|
||
|
|
'Check the options passed to the relation.',
|
||
|
|
'Common options: minGap, maxGap, tolerance, axis, inStackingContext.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_VALID_INVALID_UNIT, {
|
||
|
|
code: IMH_VALID_INVALID_UNIT,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'validation-error',
|
||
|
|
message: 'Invalid unit.',
|
||
|
|
fixHints: [
|
||
|
|
'Valid units: px, em, rem, %, jnd, vw, vh.',
|
||
|
|
'Example: gap 8px, tolerance 2jnd.',
|
||
|
|
'Ensure the unit is appended directly to the number without spaces.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_VALID_INVALID_STATE_TIMELINE, {
|
||
|
|
code: IMH_VALID_INVALID_STATE_TIMELINE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'validation-error',
|
||
|
|
message: 'Invalid state or timeline reference.',
|
||
|
|
fixHints: [
|
||
|
|
'Valid states: default, hover, focus, focusVisible, active.',
|
||
|
|
'Use the exact state name; focus-visible kebab-case is not supported (use focusVisible).',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_VALID_INVALID_ENV_GUARD, {
|
||
|
|
code: IMH_VALID_INVALID_ENV_GUARD,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'validation-error',
|
||
|
|
message: 'Invalid environment guard.',
|
||
|
|
fixHints: [
|
||
|
|
'Valid environment axes: viewport, colorScheme, pointer, reducedMotion, deviceScaleFactor, locale, writingMode.',
|
||
|
|
'Example: guard viewport width >= 768.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_VALID_INVALID_QUANTIFIER_NESTING, {
|
||
|
|
code: IMH_VALID_INVALID_QUANTIFIER_NESTING,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'validation-error',
|
||
|
|
message: 'Invalid quantifier nesting.',
|
||
|
|
fixHints: [
|
||
|
|
'Flatten nested quantifiers or restructure the assertion.',
|
||
|
|
'Use inline quantifiers: all, any, none before the assertion.',
|
||
|
|
'Example: all \'.item\' leftOf \'.sidebar\'',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_VALID_CONTRADICTION, {
|
||
|
|
code: IMH_VALID_CONTRADICTION,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'validation-error',
|
||
|
|
message: 'Contradiction detected.',
|
||
|
|
fixHints: [
|
||
|
|
'minGap cannot be greater than maxGap.',
|
||
|
|
'Adjust the bounds so that minGap <= maxGap.',
|
||
|
|
'Example: gap 8px..16px (minGap=8, maxGap=16).',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Resolution
|
||
|
|
[IMH_SELECTOR_ZERO_MATCHES, {
|
||
|
|
code: IMH_SELECTOR_ZERO_MATCHES,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Selector matched 0 elements.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the selector is valid and matches an element in the DOM.',
|
||
|
|
'Use ui.extract(selector) to verify the selector resolves to at least one element.',
|
||
|
|
'Ensure the page is fully loaded before running assertions.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_SELECTOR_AMBIGUOUS, {
|
||
|
|
code: IMH_SELECTOR_AMBIGUOUS,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Selector is ambiguous.',
|
||
|
|
fixHints: [
|
||
|
|
'Make the selector more specific (e.g. add a parent class or use an attribute).',
|
||
|
|
'Consider using getByTestId("unique-id") for stable element references.',
|
||
|
|
'Example: \'[data-testid="submit-button"]\' instead of \'.button\'.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_SELECTOR_NO_MATCH, {
|
||
|
|
code: IMH_SELECTOR_NO_MATCH,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Selector matched 0 elements.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the selector is valid and matches an element in the DOM.',
|
||
|
|
'Use ui.extract(selector) to verify the selector resolves to at least one element.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_SELECTOR_RESOLUTION_FAILED, {
|
||
|
|
code: IMH_SELECTOR_RESOLUTION_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Selector resolution failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Use valid CSS selector syntax.',
|
||
|
|
'Avoid complex pseudo-selectors that CDP cannot resolve.',
|
||
|
|
'Test the selector in browser DevTools first.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_FRAME_AMBIGUOUS, {
|
||
|
|
code: IMH_FRAME_AMBIGUOUS,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Frame reference is ambiguous.',
|
||
|
|
fixHints: [
|
||
|
|
'Use a more specific frame selector.',
|
||
|
|
'Supported frames: viewport, document, element, nearestPositionedAncestor, containingBlock, scrollContainer, namedGridArea, landmark, stackingContextRoot.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_FRAME_UNSUPPORTED, {
|
||
|
|
code: IMH_FRAME_UNSUPPORTED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Unsupported frame kind.',
|
||
|
|
fixHints: [
|
||
|
|
'Supported frame types: viewport, document, element, nearestPositionedAncestor, containingBlock, scrollContainer, namedGridArea, landmark, stackingContextRoot.',
|
||
|
|
'Use viewport as the default frame if unsure.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_TOPOLOGY_UNSUPPORTED, {
|
||
|
|
code: IMH_TOPOLOGY_UNSUPPORTED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Unsupported topology query.',
|
||
|
|
fixHints: [
|
||
|
|
'Supported topology assertions: clippedBy, attachedToScrollContainer, escapeClippingChainOf, inStackingContext.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_STATE_MATERIALIZATION_FAILED, {
|
||
|
|
code: IMH_STATE_MATERIALIZATION_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'State materialization failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the element exists before applying a state.',
|
||
|
|
'Ensure the state is supported: default, hover, focus, focusVisible, active.',
|
||
|
|
'Some states (disabled, checked, expanded) are not yet materializable.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Extractor planner
|
||
|
|
[IMH_EXTRACTOR_EMPTY_SELECTOR, {
|
||
|
|
code: IMH_EXTRACTOR_EMPTY_SELECTOR,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Empty selector in extraction plan.',
|
||
|
|
fixHints: [
|
||
|
|
'Ensure all assertions have a non-empty subject selector.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_EXTRACTOR_MISSING_ENV_GUARD, {
|
||
|
|
code: IMH_EXTRACTOR_MISSING_ENV_GUARD,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Missing environment guard.',
|
||
|
|
fixHints: [
|
||
|
|
'Add a valid environment guard or remove the conditional assertion.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_EXTRACTOR_UNRESOLVED_ENV_GUARD, {
|
||
|
|
code: IMH_EXTRACTOR_UNRESOLVED_ENV_GUARD,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Unresolved environment guard.',
|
||
|
|
fixHints: [
|
||
|
|
'Check the environment axis name and comparator.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_EXTRACTOR_MISSING_STATE, {
|
||
|
|
code: IMH_EXTRACTOR_MISSING_STATE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Missing state reference.',
|
||
|
|
fixHints: [
|
||
|
|
'Ensure the state is defined in the state timeline.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_EXTRACTOR_UNRESOLVED_STATE, {
|
||
|
|
code: IMH_EXTRACTOR_UNRESOLVED_STATE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Unresolved state reference.',
|
||
|
|
fixHints: [
|
||
|
|
'Use a supported state name.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_EXTRACTOR_UNSUPPORTED_STATE, {
|
||
|
|
code: IMH_EXTRACTOR_UNSUPPORTED_STATE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Unsupported state.',
|
||
|
|
fixHints: [
|
||
|
|
'Supported states: default, hover, focus, focusVisible, active.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_EXTRACTOR_NON_STATIC_TIMELINE, {
|
||
|
|
code: IMH_EXTRACTOR_NON_STATIC_TIMELINE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Non-static timeline reference.',
|
||
|
|
fixHints: [
|
||
|
|
'Timeline references must be static strings.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_EXTRACTOR_UNSUPPORTED_CLAUSE_TYPE, {
|
||
|
|
code: IMH_EXTRACTOR_UNSUPPORTED_CLAUSE_TYPE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'resolution-error',
|
||
|
|
message: 'Unsupported clause type for extraction.',
|
||
|
|
fixHints: [
|
||
|
|
'Use a supported relation or assertion type.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Extraction
|
||
|
|
[IMH_EXTRACT_PARTIAL, {
|
||
|
|
code: IMH_EXTRACT_PARTIAL,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Partial extraction; some facts may be missing.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the page is fully loaded before running assertions.',
|
||
|
|
'Verify selectors are valid CSS selectors or semantic references.',
|
||
|
|
'Use ui.extract(selector) to debug selector resolution.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_EXTRACT_UNAVAILABLE_FACT, {
|
||
|
|
code: IMH_EXTRACT_UNAVAILABLE_FACT,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Required fact is unavailable.',
|
||
|
|
fixHints: [
|
||
|
|
'Run validate() before assertions to check for unsupported relations or missing elements.',
|
||
|
|
'Ensure the page is loaded and selectors resolve correctly.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_EXTRACT_PROTOCOL_ERROR, {
|
||
|
|
code: IMH_EXTRACT_PROTOCOL_ERROR,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Extraction protocol error.',
|
||
|
|
fixHints: [
|
||
|
|
'Verify the page is fully loaded before running assertions.',
|
||
|
|
'Check that selectors are valid CSS selectors or semantic references.',
|
||
|
|
'Use ui.extract(selector) to debug selector resolution.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// CDP
|
||
|
|
[IMH_CDP_SESSION_ATTACH_FAILED, {
|
||
|
|
code: IMH_CDP_SESSION_ATTACH_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Failed to attach CDP session.',
|
||
|
|
fixHints: [
|
||
|
|
'Restart the browser process.',
|
||
|
|
'Check that the Playwright version matches the browser version.',
|
||
|
|
'Ensure the page was launched with a Chromium-based browser.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_DOM_EXTRACTION_FAILED, {
|
||
|
|
code: IMH_DOM_EXTRACTION_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'DOM extraction failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the page is fully loaded.',
|
||
|
|
'Wait for dynamic content to render before running assertions.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_BOX_MODEL_PARTIAL, {
|
||
|
|
code: IMH_BOX_MODEL_PARTIAL,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Box model partially extracted.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the element is visible and not display:none.',
|
||
|
|
'Ensure the element is in the DOM and not detached.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_BOX_MODEL_FAILED, {
|
||
|
|
code: IMH_BOX_MODEL_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Box model extraction failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the element is visible (not display:none or visibility:hidden).',
|
||
|
|
'Ensure the element is attached to the DOM.',
|
||
|
|
'Try scrolling the element into view before asserting.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_VISUAL_BOX_PARTIAL, {
|
||
|
|
code: IMH_VISUAL_BOX_PARTIAL,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Visual box partially extracted.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the element is visible and not display:none.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_VISUAL_BOX_FAILED, {
|
||
|
|
code: IMH_VISUAL_BOX_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Visual box extraction failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the element is visible and attached to the DOM.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_FRAGMENT_PARTIAL, {
|
||
|
|
code: IMH_FRAGMENT_PARTIAL,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Fragment partially extracted.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the element has visible text content.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_FRAGMENT_FAILED, {
|
||
|
|
code: IMH_FRAGMENT_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Fragment extraction failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the element is visible and has text content.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_TRANSFORM_PARTIAL, {
|
||
|
|
code: IMH_TRANSFORM_PARTIAL,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Transform partially extracted.',
|
||
|
|
fixHints: [
|
||
|
|
'Check CSS transform properties on the element.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_TRANSFORM_FAILED, {
|
||
|
|
code: IMH_TRANSFORM_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Transform extraction failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check CSS transform properties on the element.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_STYLE_PARTIAL, {
|
||
|
|
code: IMH_STYLE_PARTIAL,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Style partially extracted.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that computed styles are accessible for the element.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_STYLE_FAILED, {
|
||
|
|
code: IMH_STYLE_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Style extraction failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that computed styles are accessible for the element.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_TOPOLOGY_PARTIAL, {
|
||
|
|
code: IMH_TOPOLOGY_PARTIAL,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Topology partially extracted.',
|
||
|
|
fixHints: [
|
||
|
|
'Check CSS properties that affect topology (position, overflow, contain, z-index).',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_TOPOLOGY_FAILED, {
|
||
|
|
code: IMH_TOPOLOGY_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'extraction-error',
|
||
|
|
message: 'Topology extraction failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check CSS properties that affect topology (position, overflow, contain, z-index).',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Contract failures
|
||
|
|
[IMH_RELATION_LEFT_OF_FAILED, {
|
||
|
|
code: IMH_RELATION_LEFT_OF_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'leftOf relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Inspect the layout in browser devtools and adjust element positions or gap thresholds.',
|
||
|
|
'Use ui.extract() to verify element rects.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_RIGHT_OF_FAILED, {
|
||
|
|
code: IMH_RELATION_RIGHT_OF_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'rightOf relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Inspect the layout in browser devtools and adjust element positions or gap thresholds.',
|
||
|
|
'Use ui.extract() to verify element rects.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_ABOVE_FAILED, {
|
||
|
|
code: IMH_RELATION_ABOVE_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'above relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Inspect the layout in browser devtools and adjust element positions or gap thresholds.',
|
||
|
|
'Use ui.extract() to verify element rects.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_BELOW_FAILED, {
|
||
|
|
code: IMH_RELATION_BELOW_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'below relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Inspect the layout in browser devtools and adjust element positions or gap thresholds.',
|
||
|
|
'Use ui.extract() to verify element rects.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_ALIGNED_FAILED, {
|
||
|
|
code: IMH_RELATION_ALIGNED_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'aligned relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the elements share the same alignment axis (left, right, top, bottom).',
|
||
|
|
'Use ui.extract() to verify element positions.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_CENTERED_FAILED, {
|
||
|
|
code: IMH_RELATION_CENTERED_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'centered relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the subject element is centered within the reference container.',
|
||
|
|
'Verify margins, padding, and container dimensions with ui.extract().',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_INSIDE_FAILED, {
|
||
|
|
code: IMH_RELATION_INSIDE_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'inside relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the subject fits entirely within the reference container.',
|
||
|
|
'Verify padding, border, and overflow settings on the container.',
|
||
|
|
'Use ui.extract() to compare subject and container rects.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_CONTAINS_FAILED, {
|
||
|
|
code: IMH_RELATION_CONTAINS_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'contains relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the container is large enough to fully contain the subject.',
|
||
|
|
'Verify padding, border, and overflow settings.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_OVERLAPS_FAILED, {
|
||
|
|
code: IMH_RELATION_OVERLAPS_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'overlaps relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the elements actually overlap in the layout.',
|
||
|
|
'Verify z-index and positioning if elements should stack.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_BESIDE_FAILED, {
|
||
|
|
code: IMH_RELATION_BESIDE_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'beside relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the elements are positioned beside each other (leftOf or rightOf).',
|
||
|
|
'Use ui.extract() to verify element rects.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_ADJACENT_FAILED, {
|
||
|
|
code: IMH_RELATION_ADJACENT_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'adjacent relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the elements are touching or very close to each other.',
|
||
|
|
'Use ui.extract() to verify element rects.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_NEAR_FAILED, {
|
||
|
|
code: IMH_RELATION_NEAR_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'near relation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the elements are within the expected proximity.',
|
||
|
|
'Use ui.extract() to verify element rects.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_RELATION_FAILED, {
|
||
|
|
code: IMH_RELATION_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Relation assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Verify the expected layout and consider adjusting thresholds.',
|
||
|
|
'Check element positions using ui.extract(selector) to inspect actual geometry.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_ALIGNMENT_FAILED, {
|
||
|
|
code: IMH_ALIGNMENT_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'alignment assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check the axis option (centerX, centerY, left, right, top, bottom).',
|
||
|
|
'Verify element positions with ui.extract().',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_SIZE_AT_LEAST_FAILED, {
|
||
|
|
code: IMH_SIZE_AT_LEAST_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'size at-least assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check the element dimensions with ui.extract() and adjust the expected size or CSS.',
|
||
|
|
'For touch targets, ensure width and height are at least 44px.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_SIZE_AT_MOST_FAILED, {
|
||
|
|
code: IMH_SIZE_AT_MOST_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'size at-most assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check the element dimensions with ui.extract() and adjust the expected size or CSS.',
|
||
|
|
'Verify the element is not growing unexpectedly due to content.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_SIZE_BETWEEN_FAILED, {
|
||
|
|
code: IMH_SIZE_BETWEEN_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'size between assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check the element dimensions with ui.extract().',
|
||
|
|
'Ensure the size falls within the specified min and max bounds.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_TOPOLOGY_CLIPPED_FAILED, {
|
||
|
|
code: IMH_TOPOLOGY_CLIPPED_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'clipping topology assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check overflow and clip properties on ancestor containers.',
|
||
|
|
'Verify the element is not clipped by a parent with overflow:hidden.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_TOPOLOGY_STACKING_FAILED, {
|
||
|
|
code: IMH_TOPOLOGY_STACKING_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'stacking context assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check z-index and positioning (relative, absolute, fixed) of the element and its ancestors.',
|
||
|
|
'Ensure a new stacking context is created when expected (e.g. opacity < 1, transform, isolation).',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_VISIBILITY_FAILED, {
|
||
|
|
code: IMH_VISIBILITY_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'visibility assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the element is not hidden by display:none, visibility:hidden, or opacity:0.',
|
||
|
|
'Ensure the element is in the viewport and not clipped.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PREDICATE_FAILED, {
|
||
|
|
code: IMH_PREDICATE_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Predicate evaluation failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Verify the expected layout and consider adjusting thresholds.',
|
||
|
|
'Check element positions using ui.extract(selector) to inspect actual geometry.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Cardinality
|
||
|
|
[IMH_CARDINALITY_EXACTLYONE_FAILED, {
|
||
|
|
code: IMH_CARDINALITY_EXACTLYONE_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Cardinality exactly-one assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Verify the selector matches exactly one element.',
|
||
|
|
'Use a more specific selector or adjust the cardinality bound.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_CARDINALITY_ATLEASTN_FAILED, {
|
||
|
|
code: IMH_CARDINALITY_ATLEASTN_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Cardinality at-least-N assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Verify the selector matches at least the expected number of elements.',
|
||
|
|
'Use a more specific selector or adjust the cardinality bound.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_CARDINALITY_ATMOSTN_FAILED, {
|
||
|
|
code: IMH_CARDINALITY_ATMOSTN_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Cardinality at-most-N assertion failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Verify the selector matches at most the expected number of elements.',
|
||
|
|
'Use a more specific selector or adjust the cardinality bound.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Indeterminate
|
||
|
|
[IMH_INDETERMINATE_MISSING_FACT, {
|
||
|
|
code: IMH_INDETERMINATE_MISSING_FACT,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'indeterminate-result',
|
||
|
|
message: 'Result is indeterminate because a required fact is missing.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that selectors resolve and the page is loaded.',
|
||
|
|
'Run validate() to verify the assertion is supported.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_INDETERMINATE_UNSTABLE_INPUT, {
|
||
|
|
code: IMH_INDETERMINATE_UNSTABLE_INPUT,
|
||
|
|
severity: 'warning',
|
||
|
|
category: 'indeterminate-result',
|
||
|
|
message: 'Result is indeterminate because input is unstable.',
|
||
|
|
fixHints: [
|
||
|
|
'Wait for animations, lazy-loaded content, or async data to settle before asserting.',
|
||
|
|
'Use a stable selector that does not depend on dynamic content.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Internal
|
||
|
|
[IMH_INTERNAL_UNKNOWN_CLAUSE_KIND, {
|
||
|
|
code: IMH_INTERNAL_UNKNOWN_CLAUSE_KIND,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Unknown clause kind.',
|
||
|
|
fixHints: [
|
||
|
|
'Update Imhotep to the latest version.',
|
||
|
|
'Use a supported relation or predicate.',
|
||
|
|
'Supported relations: leftOf, rightOf, above, below, alignedWith, centeredWithin, inside, contains, overlaps.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_INTERNAL_EVALUATION_EXCEPTION, {
|
||
|
|
code: IMH_INTERNAL_EVALUATION_EXCEPTION,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Evaluation exception.',
|
||
|
|
fixHints: [
|
||
|
|
'Report this as a bug with a minimal reproduction.',
|
||
|
|
'Try simplifying the assertion or splitting it into smaller parts.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_FEATURE_NOT_YET_IMPLEMENTED, {
|
||
|
|
code: IMH_FEATURE_NOT_YET_IMPLEMENTED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Feature not yet implemented.',
|
||
|
|
fixHints: [
|
||
|
|
'This assertion uses a relation that is documented but not yet implemented.',
|
||
|
|
'Use a supported relation such as leftOf, rightOf, above, below, inside, overlaps, alignedWith, or centeredWithin.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_UNKNOWN_FAILURE, {
|
||
|
|
code: IMH_UNKNOWN_FAILURE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Unknown failure.',
|
||
|
|
fixHints: [
|
||
|
|
'Report this as a bug with a minimal reproduction.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Solver / logic
|
||
|
|
[IMH_LOGIC_UNKNOWN_FORMULA_KIND, {
|
||
|
|
code: IMH_LOGIC_UNKNOWN_FORMULA_KIND,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Unknown formula kind encountered by solver.',
|
||
|
|
fixHints: [
|
||
|
|
'Simplify the assertion to use basic relations.',
|
||
|
|
'Avoid compound formulas with and/or/implications until supported.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_DOMAIN_UNRESOLVED, {
|
||
|
|
code: IMH_LOGIC_DOMAIN_UNRESOLVED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Solver could not resolve a formula domain.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that selectors are valid and resolve to at least one element.',
|
||
|
|
'Use ui.extract(selector) to verify selector resolution.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_VACUOUS_FORALL, {
|
||
|
|
code: IMH_LOGIC_VACUOUS_FORALL,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Forall over empty domain is vacuously true.',
|
||
|
|
fixHints: [
|
||
|
|
'Verify the selector is intended to match an empty set.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_EMPTY_DOMAIN_EXISTS, {
|
||
|
|
code: IMH_LOGIC_EMPTY_DOMAIN_EXISTS,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Exists over empty domain is false.',
|
||
|
|
fixHints: [
|
||
|
|
'Verify the selector is intended to match an empty set.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_PREDICATE_MISSING, {
|
||
|
|
code: IMH_LOGIC_PREDICATE_MISSING,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Solver predicate is missing or unsupported.',
|
||
|
|
fixHints: [
|
||
|
|
'Use a supported predicate.',
|
||
|
|
'Supported predicates: leftOf, rightOf, above, below, alignedWith, centeredWithin, inside, contains, overlaps, atLeast, atMost, between.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_UNBOUND_VARIABLE, {
|
||
|
|
code: IMH_LOGIC_UNBOUND_VARIABLE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Unbound variable in formula.',
|
||
|
|
fixHints: [
|
||
|
|
'Check formula syntax and ensure all variables are bound by a quantifier.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_UNSUPPORTED_TERM, {
|
||
|
|
code: IMH_LOGIC_UNSUPPORTED_TERM,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Unsupported term type in formula.',
|
||
|
|
fixHints: [
|
||
|
|
'Simplify the assertion to use basic relations.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_UNKNOWN_NODE, {
|
||
|
|
code: IMH_LOGIC_UNKNOWN_NODE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Unknown node type in formula.',
|
||
|
|
fixHints: [
|
||
|
|
'Simplify the assertion to use basic relations.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_ARITY_MISMATCH, {
|
||
|
|
code: IMH_LOGIC_ARITY_MISMATCH,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Predicate arity mismatch.',
|
||
|
|
fixHints: [
|
||
|
|
'Check the number of arguments passed to the predicate.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_UNKNOWN_PREDICATE, {
|
||
|
|
code: IMH_LOGIC_UNKNOWN_PREDICATE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Unknown predicate.',
|
||
|
|
fixHints: [
|
||
|
|
'Use a supported predicate.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_FREE_VARIABLE, {
|
||
|
|
code: IMH_LOGIC_FREE_VARIABLE,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Free variable in formula.',
|
||
|
|
fixHints: [
|
||
|
|
'Bind all variables with quantifiers (forAll, exists).',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_LOGIC_EMPTY_DOMAIN, {
|
||
|
|
code: IMH_LOGIC_EMPTY_DOMAIN,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Empty domain in formula.',
|
||
|
|
fixHints: [
|
||
|
|
'Verify the selector is intended to match an empty set.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Solver engine
|
||
|
|
[IMH_EVALUATOR_MISSING, {
|
||
|
|
code: IMH_EVALUATOR_MISSING,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Evaluator is missing for clause kind.',
|
||
|
|
fixHints: [
|
||
|
|
'Use a supported clause type.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_EVALUATOR_EXCEPTION, {
|
||
|
|
code: IMH_EVALUATOR_EXCEPTION,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Evaluator threw an exception.',
|
||
|
|
fixHints: [
|
||
|
|
'Report this as a bug with a minimal reproduction.',
|
||
|
|
'Try simplifying the assertion.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Quantifier
|
||
|
|
[IMH_QUANTIFIER_NO_SUBCLAUSES, {
|
||
|
|
code: IMH_QUANTIFIER_NO_SUBCLAUSES,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Quantifier has no subclauses.',
|
||
|
|
fixHints: [
|
||
|
|
'Add at least one subclause to the quantifier block.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PAIRWISE_INSUFFICIENT, {
|
||
|
|
code: IMH_PAIRWISE_INSUFFICIENT,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Insufficient elements for pairwise quantifier.',
|
||
|
|
fixHints: [
|
||
|
|
'Ensure the domain has at least two elements for pairwise comparison.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_UNKNOWN_QUANTIFIER, {
|
||
|
|
code: IMH_UNKNOWN_QUANTIFIER,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Unknown quantifier kind.',
|
||
|
|
fixHints: [
|
||
|
|
'Use a supported quantifier: all, any, none, forAll, exists.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Fact observation
|
||
|
|
[IMH_FACT_OBSERVED_GAP, {
|
||
|
|
code: IMH_FACT_OBSERVED_GAP,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Observed gap between elements.',
|
||
|
|
fixHints: ['This is an informational observation, no action needed.'],
|
||
|
|
}],
|
||
|
|
[IMH_FACT_OBSERVED_SIZE, {
|
||
|
|
code: IMH_FACT_OBSERVED_SIZE,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Observed size of element.',
|
||
|
|
fixHints: ['This is an informational observation, no action needed.'],
|
||
|
|
}],
|
||
|
|
[IMH_FACT_OBSERVED_TOPOLOGY, {
|
||
|
|
code: IMH_FACT_OBSERVED_TOPOLOGY,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Observed topology fact.',
|
||
|
|
fixHints: ['This is an informational observation, no action needed.'],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Property run
|
||
|
|
[IMH_ENUMERATED_RUN_ERROR, {
|
||
|
|
code: IMH_ENUMERATED_RUN_ERROR,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Enumerated property run error.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the property callback does not throw for the reported input.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_SAMPLED_RUN_ERROR, {
|
||
|
|
code: IMH_SAMPLED_RUN_ERROR,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Sampled property run error.',
|
||
|
|
fixHints: [
|
||
|
|
'Check that the property callback does not throw for the reported input.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PROPERTY_RUN_FAILED, {
|
||
|
|
code: IMH_PROPERTY_RUN_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Property run failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Review the failing counterexample and replay with the same seed.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PROPERTY_PASSED, {
|
||
|
|
code: IMH_PROPERTY_PASSED,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Property passed.',
|
||
|
|
fixHints: ['No action needed; the property holds for all tested inputs.'],
|
||
|
|
}],
|
||
|
|
[IMH_PROPERTY_FAILED, {
|
||
|
|
code: IMH_PROPERTY_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Property failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Review the counterexample and failing clause.',
|
||
|
|
'Use the reported seed to reproduce the exact failure.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_PROPERTY_REPLAY, {
|
||
|
|
code: IMH_PROPERTY_REPLAY,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Replay metadata.',
|
||
|
|
fixHints: ['Use the provided seed and case ID to replay this exact run.'],
|
||
|
|
}],
|
||
|
|
[IMH_PROPERTY_SHRUNK, {
|
||
|
|
code: IMH_PROPERTY_SHRUNK,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Counterexample shrunk.',
|
||
|
|
fixHints: [
|
||
|
|
'The failure was minimized to the smallest reproducible case.',
|
||
|
|
'Use the reported seed and run index to replay.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
[IMH_ENUMERATED_PASSED, {
|
||
|
|
code: IMH_ENUMERATED_PASSED,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Enumerated property passed.',
|
||
|
|
fixHints: ['No action needed; all enumerated cases passed.'],
|
||
|
|
}],
|
||
|
|
[IMH_ENUMERATED_FAILED, {
|
||
|
|
code: IMH_ENUMERATED_FAILED,
|
||
|
|
severity: 'error',
|
||
|
|
category: 'contract-failure',
|
||
|
|
message: 'Enumerated property failed.',
|
||
|
|
fixHints: [
|
||
|
|
'Review the failing case in the enumerated matrix.',
|
||
|
|
'Use the reported environment case ID to reproduce.',
|
||
|
|
],
|
||
|
|
}],
|
||
|
|
|
||
|
|
// Reporter internal
|
||
|
|
[IMH_FRAME_CONTEXT, {
|
||
|
|
code: IMH_FRAME_CONTEXT,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Frame context.',
|
||
|
|
fixHints: ['This is an informational observation, no action needed.'],
|
||
|
|
}],
|
||
|
|
|
||
|
|
[IMH_WITNESS_ENV, {
|
||
|
|
code: IMH_WITNESS_ENV,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Witness environment.',
|
||
|
|
fixHints: ['This is an informational observation, no action needed.'],
|
||
|
|
}],
|
||
|
|
|
||
|
|
[IMH_WITNESS_SNAPSHOT, {
|
||
|
|
code: IMH_WITNESS_SNAPSHOT,
|
||
|
|
severity: 'info',
|
||
|
|
category: 'internal-error',
|
||
|
|
message: 'Witness snapshot.',
|
||
|
|
fixHints: ['This is an informational observation, no action needed.'],
|
||
|
|
}],
|
||
|
|
]);
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Look up a canonical code entry by its string code.
|
||
|
|
*/
|
||
|
|
export function lookupCode(code: string): CodeEntry | undefined {
|
||
|
|
return REGISTRY.get(code);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Return all registered codes.
|
||
|
|
*/
|
||
|
|
export function listCodes(): CodeEntry[] {
|
||
|
|
return Array.from(REGISTRY.values());
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Build a human-readable message for a code, substituting placeholders.
|
||
|
|
*
|
||
|
|
* Supported placeholders:
|
||
|
|
* {selector} — CSS selector string
|
||
|
|
* {relation} — relation name (leftOf, above, etc.)
|
||
|
|
* {expected} — expected value
|
||
|
|
* {observed} — observed / measured value
|
||
|
|
* {frame} — frame identifier
|
||
|
|
*/
|
||
|
|
export function formatMessage(
|
||
|
|
code: string,
|
||
|
|
placeholders: Record<string, string | number>,
|
||
|
|
): string {
|
||
|
|
const entry = lookupCode(code);
|
||
|
|
let message = entry?.message ?? code;
|
||
|
|
for (const [key, value] of Object.entries(placeholders)) {
|
||
|
|
message = message.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value));
|
||
|
|
}
|
||
|
|
return message;
|
||
|
|
}
|