@qontinui/shared-types 0.2.5 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -1
- package/dist/index.d.ts +43 -1
- package/dist/ui-bridge-ir.cjs +30 -33
- package/dist/ui-bridge-ir.cjs.map +1 -1
- package/dist/ui-bridge-ir.d.cts +98 -84
- package/dist/ui-bridge-ir.d.ts +98 -84
- package/dist/ui-bridge-ir.js +30 -33
- package/dist/ui-bridge-ir.js.map +1 -1
- package/package.json +1 -1
- package/src/generated/AssertionMiss.d.ts +22 -0
- package/src/generated/AssertionOutcome.d.ts +30 -0
- package/src/generated/AssertionResult.d.ts +38 -0
- package/src/generated/AssertionScope.d.ts +37 -0
- package/src/generated/AssertionSeverityCounts.d.ts +28 -0
- package/src/generated/BridgeFingerprint.d.ts +40 -0
- package/src/generated/CandidateMiss.d.ts +39 -0
- package/src/generated/ConjunctEvaluation.d.ts +24 -0
- package/src/generated/ConjunctRule.d.ts +55 -0
- package/src/generated/FieldDiff.d.ts +33 -0
- package/src/generated/IrAssertion.d.ts +26 -0
- package/src/generated/IrAssertionTarget.d.ts +28 -0
- package/src/generated/IrCrossRef.d.ts +16 -0
- package/src/generated/IrElementCriteria.d.ts +29 -0
- package/src/generated/IrGroup.d.ts +33 -0
- package/src/generated/IrMetadata.d.ts +15 -0
- package/src/generated/IrPageSpec.d.ts +51 -0
- package/src/generated/IrProvenance.d.ts +28 -0
- package/src/generated/IrState.d.ts +36 -0
- package/src/generated/IrStateCondition.d.ts +19 -0
- package/src/generated/IrTransition.d.ts +34 -0
- package/src/generated/IrTransitionAction.d.ts +17 -0
- package/src/generated/IrWaitSpec.d.ts +22 -0
- package/src/generated/LegacyAssertion.d.ts +22 -0
- package/src/generated/LegacyAssertionTarget.d.ts +23 -0
- package/src/generated/LegacyGroup.d.ts +19 -0
- package/src/generated/LegacyProcessStep.d.ts +16 -0
- package/src/generated/LegacySpec.d.ts +30 -0
- package/src/generated/LegacyStateMachine.d.ts +17 -0
- package/src/generated/LegacyStateMachineState.d.ts +21 -0
- package/src/generated/LegacyTransition.d.ts +20 -0
- package/src/generated/MatchOutcome.d.ts +11 -0
- package/src/generated/MatchedElement.d.ts +28 -0
- package/src/generated/MissReason.d.ts +20 -0
- package/src/generated/PolicyConjunct.d.ts +22 -0
- package/src/generated/PolicyEvaluation.d.ts +22 -0
- package/src/generated/PolicyStatus.d.ts +11 -0
- package/src/generated/ProposalStatus.d.ts +13 -0
- package/src/generated/RecommendedState.d.ts +23 -0
- package/src/generated/SpecCheckConfidence.d.ts +15 -0
- package/src/generated/SpecCheckPolicy.d.ts +23 -0
- package/src/generated/SpecCheckResult.d.ts +66 -0
- package/src/generated/SpecCheckStepConfig.d.ts +38 -0
- package/src/generated/SpecCheckSummary.d.ts +28 -0
- package/src/generated/SpecValidation.d.ts +27 -0
- package/src/generated/StateMatchResult.d.ts +36 -0
- package/src/generated/UIBridgeElement.d.ts +28 -0
- package/src/generated/index.ts +46 -0
- package/src/index.ts +5 -0
- package/src/ui-bridge-ir/__tests__/projection.test.ts +114 -22
- package/src/ui-bridge-ir/adapter.ts +7 -1
- package/src/ui-bridge-ir/ir.schema.json +8 -4
- package/src/ui-bridge-ir/primitives.ts +8 -0
- package/src/ui-bridge-ir/projection.ts +34 -57
- package/src/ui-bridge-ir/state.ts +9 -2
package/src/generated/index.ts
CHANGED
|
@@ -27,6 +27,11 @@ export type { ApiAssertionType } from './ApiAssertionType';
|
|
|
27
27
|
export type { ApiContentType } from './ApiContentType';
|
|
28
28
|
export type { ApiVariableExtraction } from './ApiVariableExtraction';
|
|
29
29
|
export type { AppEvent } from './AppEvent';
|
|
30
|
+
export type { AssertionMiss } from './AssertionMiss';
|
|
31
|
+
export type { AssertionOutcome } from './AssertionOutcome';
|
|
32
|
+
export type { AssertionResult } from './AssertionResult';
|
|
33
|
+
export type { AssertionScope } from './AssertionScope';
|
|
34
|
+
export type { AssertionSeverityCounts } from './AssertionSeverityCounts';
|
|
30
35
|
export type { AvailableTransitionsResult } from './AvailableTransitionsResult';
|
|
31
36
|
export type { BaseStepFields } from './BaseStepFields';
|
|
32
37
|
export type { BatchComputeEmbeddingRequest } from './BatchComputeEmbeddingRequest';
|
|
@@ -34,8 +39,10 @@ export type { BatchComputeEmbeddingResponse } from './BatchComputeEmbeddingRespo
|
|
|
34
39
|
export type { BatchEmbeddingResult } from './BatchEmbeddingResult';
|
|
35
40
|
export type { BetweenIterations } from './BetweenIterations';
|
|
36
41
|
export type { BoundingBox } from './BoundingBox';
|
|
42
|
+
export type { BridgeFingerprint } from './BridgeFingerprint';
|
|
37
43
|
export type { BuildPhaseConfig } from './BuildPhaseConfig';
|
|
38
44
|
export type { BuiltinOverrideProposal } from './BuiltinOverrideProposal';
|
|
45
|
+
export type { CandidateMiss } from './CandidateMiss';
|
|
39
46
|
export type { CanonicalStep } from './CanonicalStep';
|
|
40
47
|
export type { CanvasPanel } from './CanvasPanel';
|
|
41
48
|
export type { CatchUpPolicy } from './CatchUpPolicy';
|
|
@@ -56,6 +63,8 @@ export type { ConditionScheduleConfig } from './ConditionScheduleConfig';
|
|
|
56
63
|
export type { ConditionStatus } from './ConditionStatus';
|
|
57
64
|
export type { Confidence } from './Confidence';
|
|
58
65
|
export type { ConfidenceLevel } from './ConfidenceLevel';
|
|
66
|
+
export type { ConjunctEvaluation } from './ConjunctEvaluation';
|
|
67
|
+
export type { ConjunctRule } from './ConjunctRule';
|
|
59
68
|
export type { Constraint } from './Constraint';
|
|
60
69
|
export type { ConstraintCheck } from './ConstraintCheck';
|
|
61
70
|
export type { ConstraintProposal } from './ConstraintProposal';
|
|
@@ -137,6 +146,7 @@ export type { ExitCheckResult } from './ExitCheckResult';
|
|
|
137
146
|
export type { ExitStrategy } from './ExitStrategy';
|
|
138
147
|
export type { ExportResult } from './ExportResult';
|
|
139
148
|
export type { ExtendIterationsRequest } from './ExtendIterationsRequest';
|
|
149
|
+
export type { FieldDiff } from './FieldDiff';
|
|
140
150
|
export type { FileChange } from './FileChange';
|
|
141
151
|
export type { Finding } from './Finding';
|
|
142
152
|
export type { FindingActionType } from './FindingActionType';
|
|
@@ -167,6 +177,19 @@ export type { ImplementFixesConfig } from './ImplementFixesConfig';
|
|
|
167
177
|
export type { IndividualCheckResult } from './IndividualCheckResult';
|
|
168
178
|
export type { InitialStateRef } from './InitialStateRef';
|
|
169
179
|
export type { InitialStatesSource } from './InitialStatesSource';
|
|
180
|
+
export type { IrAssertion } from './IrAssertion';
|
|
181
|
+
export type { IrAssertionTarget } from './IrAssertionTarget';
|
|
182
|
+
export type { IrCrossRef } from './IrCrossRef';
|
|
183
|
+
export type { IrElementCriteria } from './IrElementCriteria';
|
|
184
|
+
export type { IrGroup } from './IrGroup';
|
|
185
|
+
export type { IrMetadata } from './IrMetadata';
|
|
186
|
+
export type { IrPageSpec } from './IrPageSpec';
|
|
187
|
+
export type { IrProvenance } from './IrProvenance';
|
|
188
|
+
export type { IrState } from './IrState';
|
|
189
|
+
export type { IrStateCondition } from './IrStateCondition';
|
|
190
|
+
export type { IrTransition } from './IrTransition';
|
|
191
|
+
export type { IrTransitionAction } from './IrTransitionAction';
|
|
192
|
+
export type { IrWaitSpec } from './IrWaitSpec';
|
|
170
193
|
export type { IssueSeverity } from './IssueSeverity';
|
|
171
194
|
export type { IssueSource } from './IssueSource';
|
|
172
195
|
export type { IssueStatus } from './IssueStatus';
|
|
@@ -179,12 +202,22 @@ export type { JobStatus } from './JobStatus';
|
|
|
179
202
|
export type { JobSummary } from './JobSummary';
|
|
180
203
|
export type { LLMCostSummary } from './LLMCostSummary';
|
|
181
204
|
export type { LLMMetrics } from './LLMMetrics';
|
|
205
|
+
export type { LegacyAssertion } from './LegacyAssertion';
|
|
206
|
+
export type { LegacyAssertionTarget } from './LegacyAssertionTarget';
|
|
207
|
+
export type { LegacyGroup } from './LegacyGroup';
|
|
208
|
+
export type { LegacyProcessStep } from './LegacyProcessStep';
|
|
209
|
+
export type { LegacySpec } from './LegacySpec';
|
|
210
|
+
export type { LegacyStateMachine } from './LegacyStateMachine';
|
|
211
|
+
export type { LegacyStateMachineState } from './LegacyStateMachineState';
|
|
212
|
+
export type { LegacyTransition } from './LegacyTransition';
|
|
182
213
|
export type { LogSourceSelection } from './LogSourceSelection';
|
|
183
214
|
export type { LoopInstanceStatus } from './LoopInstanceStatus';
|
|
184
215
|
export type { LoopPhase } from './LoopPhase';
|
|
185
216
|
export type { MatchAdjustment } from './MatchAdjustment';
|
|
186
217
|
export type { MatchLocation } from './MatchLocation';
|
|
187
218
|
export type { MatchMethod } from './MatchMethod';
|
|
219
|
+
export type { MatchOutcome } from './MatchOutcome';
|
|
220
|
+
export type { MatchedElement } from './MatchedElement';
|
|
188
221
|
export type { McpCallRecord } from './McpCallRecord';
|
|
189
222
|
export type { McpCallsResult } from './McpCallsResult';
|
|
190
223
|
export type { McpConnectionRef } from './McpConnectionRef';
|
|
@@ -194,6 +227,7 @@ export type { McpToolCallResult } from './McpToolCallResult';
|
|
|
194
227
|
export type { McpToolInfo } from './McpToolInfo';
|
|
195
228
|
export type { McpToolInputSchema } from './McpToolInputSchema';
|
|
196
229
|
export type { McpTransport } from './McpTransport';
|
|
230
|
+
export type { MissReason } from './MissReason';
|
|
197
231
|
export type { ModelCostBreakdown } from './ModelCostBreakdown';
|
|
198
232
|
export type { ModelOverrideConfig } from './ModelOverrideConfig';
|
|
199
233
|
export type { Monitor } from './Monitor';
|
|
@@ -228,18 +262,23 @@ export type { PipelineConfig } from './PipelineConfig';
|
|
|
228
262
|
export type { PlaybackFrameRequest } from './PlaybackFrameRequest';
|
|
229
263
|
export type { PlaywrightExecutionMode } from './PlaywrightExecutionMode';
|
|
230
264
|
export type { Point } from './Point';
|
|
265
|
+
export type { PolicyConjunct } from './PolicyConjunct';
|
|
266
|
+
export type { PolicyEvaluation } from './PolicyEvaluation';
|
|
267
|
+
export type { PolicyStatus } from './PolicyStatus';
|
|
231
268
|
export type { PollingConfig } from './PollingConfig';
|
|
232
269
|
export type { ProcessConfig } from './ProcessConfig';
|
|
233
270
|
export type { ProcessState } from './ProcessState';
|
|
234
271
|
export type { ProcessStatus } from './ProcessStatus';
|
|
235
272
|
export type { PromptStep } from './PromptStep';
|
|
236
273
|
export type { PromptStepPhase } from './PromptStepPhase';
|
|
274
|
+
export type { ProposalStatus } from './ProposalStatus';
|
|
237
275
|
export type { RAGDashboardStats } from './RAGDashboardStats';
|
|
238
276
|
export type { RagCompletionEvent } from './RagCompletionEvent';
|
|
239
277
|
export type { RagProcessingStatus } from './RagProcessingStatus';
|
|
240
278
|
export type { RagProgressEvent } from './RagProgressEvent';
|
|
241
279
|
export type { ReadConfigResponse } from './ReadConfigResponse';
|
|
242
280
|
export type { RecommendationReviewDecisionPayload } from './RecommendationReviewDecisionPayload';
|
|
281
|
+
export type { RecommendedState } from './RecommendedState';
|
|
243
282
|
export type { ReflectionFixOutput } from './ReflectionFixOutput';
|
|
244
283
|
export type { Region } from './Region';
|
|
245
284
|
export type { RepositoryInactiveCondition } from './RepositoryInactiveCondition';
|
|
@@ -287,6 +326,12 @@ export type { SearchResultItem } from './SearchResultItem';
|
|
|
287
326
|
export type { SearchStrategy } from './SearchStrategy';
|
|
288
327
|
export type { SemanticSearchRequest } from './SemanticSearchRequest';
|
|
289
328
|
export type { SemanticSearchResponse } from './SemanticSearchResponse';
|
|
329
|
+
export type { SpecCheckConfidence } from './SpecCheckConfidence';
|
|
330
|
+
export type { SpecCheckPolicy } from './SpecCheckPolicy';
|
|
331
|
+
export type { SpecCheckResult } from './SpecCheckResult';
|
|
332
|
+
export type { SpecCheckStepConfig } from './SpecCheckStepConfig';
|
|
333
|
+
export type { SpecCheckSummary } from './SpecCheckSummary';
|
|
334
|
+
export type { SpecValidation } from './SpecValidation';
|
|
290
335
|
export type { StageCondition } from './StageCondition';
|
|
291
336
|
export type { StageInput } from './StageInput';
|
|
292
337
|
export type { StageOutput } from './StageOutput';
|
|
@@ -313,6 +358,7 @@ export type { StateMachineStateUpdate } from './StateMachineStateUpdate';
|
|
|
313
358
|
export type { StateMachineTransition } from './StateMachineTransition';
|
|
314
359
|
export type { StateMachineTransitionCreate } from './StateMachineTransitionCreate';
|
|
315
360
|
export type { StateMachineTransitionUpdate } from './StateMachineTransitionUpdate';
|
|
361
|
+
export type { StateMatchResult } from './StateMatchResult';
|
|
316
362
|
export type { StateNodeData } from './StateNodeData';
|
|
317
363
|
export type { StatesResponse } from './StatesResponse';
|
|
318
364
|
export type { StdioConfig } from './StdioConfig';
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
// Render logging types
|
|
8
8
|
export * from "./render-log";
|
|
9
9
|
|
|
10
|
+
// Spec-check distinctness validation (Plan 04). Surfaced from the
|
|
11
|
+
// auto-generated Rust mirror — see qontinui-schemas/rust/src/spec_check.rs.
|
|
12
|
+
export type { SpecValidation } from "./generated/SpecValidation";
|
|
13
|
+
export type { ProposalStatus } from "./generated/ProposalStatus";
|
|
14
|
+
|
|
10
15
|
// State discovery types
|
|
11
16
|
export * from "./discovery";
|
|
12
17
|
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
import { describe, expect, it } from "vitest";
|
|
14
14
|
|
|
15
15
|
import type { IRDocument } from "../document";
|
|
16
|
+
import type { IRElementCriteria } from "../element-criteria";
|
|
17
|
+
import type { IRAssertion } from "../group";
|
|
16
18
|
import {
|
|
17
19
|
projectIRToBundledPage,
|
|
18
20
|
projectLegacyToIR,
|
|
@@ -24,6 +26,74 @@ import {
|
|
|
24
26
|
// Fixtures
|
|
25
27
|
// ---------------------------------------------------------------------------
|
|
26
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Convert IR-shaped element criteria into the legacy criteria record stored on
|
|
31
|
+
* `IRAssertion.target.criteria`. Mirrors `projection.ts:convertCriteria`'s
|
|
32
|
+
* rename map (text -> textContent, ariaLabel -> accessibleName when no
|
|
33
|
+
* accessibleName is set, attributes -> dataAttributes). The forward projection
|
|
34
|
+
* passes `target.criteria` through verbatim into the legacy group output, so
|
|
35
|
+
* fixtures store criteria in their legacy on-disk shape.
|
|
36
|
+
*/
|
|
37
|
+
function toLegacyCriteria(c: IRElementCriteria): Record<string, unknown> {
|
|
38
|
+
const out: Record<string, unknown> = {};
|
|
39
|
+
if (c.role !== undefined) out.role = c.role;
|
|
40
|
+
if (c.tagName !== undefined) out.tagName = c.tagName;
|
|
41
|
+
if (c.text !== undefined) out.textContent = c.text;
|
|
42
|
+
if (c.textContains !== undefined) out.textContains = c.textContains;
|
|
43
|
+
if (c.accessibleName !== undefined) {
|
|
44
|
+
out.accessibleName = c.accessibleName;
|
|
45
|
+
} else if (c.ariaLabel !== undefined) {
|
|
46
|
+
out.accessibleName = c.ariaLabel;
|
|
47
|
+
}
|
|
48
|
+
if (c.id !== undefined) out.id = c.id;
|
|
49
|
+
if (c.attributes !== undefined) out.dataAttributes = c.attributes;
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Build the canonical IR-side assertion list for a state from a flat array of
|
|
55
|
+
* IR element criteria. Mirrors the shape the projection emits for state-derived
|
|
56
|
+
* groups so the fixtures stay terse — one criteria per assertion, with all the
|
|
57
|
+
* legacy required fields (id/category/severity/...) defaulted the same way the
|
|
58
|
+
* forward projection used to defaulted them when synthesizing assertions from
|
|
59
|
+
* `requiredElements`. Criteria are stored in legacy on-disk form (`textContent`,
|
|
60
|
+
* `accessibleName`, `dataAttributes`) because `IRAssertion.target.criteria` is
|
|
61
|
+
* already the legacy criteria record — the forward projection passes it through
|
|
62
|
+
* verbatim into `group.assertions[].target.criteria`.
|
|
63
|
+
*/
|
|
64
|
+
function assertionsFromCriteria(
|
|
65
|
+
stateId: string,
|
|
66
|
+
stateName: string,
|
|
67
|
+
criteria: IRElementCriteria[],
|
|
68
|
+
): IRAssertion[] {
|
|
69
|
+
return criteria.map((c, index) => ({
|
|
70
|
+
id: `${stateId}-elem-${index}`,
|
|
71
|
+
description: `Required element ${index} for state ${stateName}`,
|
|
72
|
+
category: "element-presence",
|
|
73
|
+
severity: "critical",
|
|
74
|
+
assertionType: "exists",
|
|
75
|
+
target: {
|
|
76
|
+
type: "search",
|
|
77
|
+
criteria: toLegacyCriteria(c),
|
|
78
|
+
label: `Required element for ${stateName}`,
|
|
79
|
+
},
|
|
80
|
+
source: "ai-generated",
|
|
81
|
+
reviewed: false,
|
|
82
|
+
enabled: true,
|
|
83
|
+
}));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Pluck the legacy-criteria record off an assertion produced by the inverse
|
|
88
|
+
* projection. The IR side stores criteria in IR form post-inversion (the
|
|
89
|
+
* projection's `invertCriteria` renames `textContent -> text`,
|
|
90
|
+
* `dataAttributes -> attributes`), so the returned object is shaped like
|
|
91
|
+
* `IRElementCriteria`.
|
|
92
|
+
*/
|
|
93
|
+
function criteriaOf(assertion: IRAssertion): IRElementCriteria {
|
|
94
|
+
return assertion.target.criteria as unknown as IRElementCriteria;
|
|
95
|
+
}
|
|
96
|
+
|
|
27
97
|
/**
|
|
28
98
|
* Slice of `qontinui-runner/src/specs/active.spec.uibridge.json` mapped back
|
|
29
99
|
* to IR. Three to four states, transitions between them, a few criteria
|
|
@@ -44,21 +114,27 @@ const ACTIVE_PAGE_FIXTURE: IRDocument = {
|
|
|
44
114
|
id: "idle",
|
|
45
115
|
name: "Idle",
|
|
46
116
|
description: "No workflow is running.",
|
|
47
|
-
|
|
117
|
+
assertions: assertionsFromCriteria("idle", "Idle", [
|
|
118
|
+
{ text: "No Active Workflow" },
|
|
119
|
+
]),
|
|
48
120
|
isInitial: true,
|
|
49
121
|
},
|
|
50
122
|
{
|
|
51
123
|
id: "running",
|
|
52
124
|
name: "Running",
|
|
53
125
|
description: "A workflow is actively executing.",
|
|
54
|
-
|
|
126
|
+
assertions: assertionsFromCriteria("running", "Running", [
|
|
127
|
+
{ role: "button", text: "Stop" },
|
|
128
|
+
]),
|
|
55
129
|
isInitial: false,
|
|
56
130
|
},
|
|
57
131
|
{
|
|
58
132
|
id: "paused",
|
|
59
133
|
name: "Paused",
|
|
60
134
|
description: "The workflow is temporarily paused.",
|
|
61
|
-
|
|
135
|
+
assertions: assertionsFromCriteria("paused", "Paused", [
|
|
136
|
+
{ role: "button", ariaLabel: "Play" },
|
|
137
|
+
]),
|
|
62
138
|
isInitial: false,
|
|
63
139
|
},
|
|
64
140
|
{
|
|
@@ -66,10 +142,10 @@ const ACTIVE_PAGE_FIXTURE: IRDocument = {
|
|
|
66
142
|
name: "Breakpoint Paused",
|
|
67
143
|
description:
|
|
68
144
|
"A workflow step with breakpoint: true has completed; execution is suspended.",
|
|
69
|
-
|
|
145
|
+
assertions: assertionsFromCriteria("breakpoint-paused", "Breakpoint Paused", [
|
|
70
146
|
{ text: "Breakpoint" },
|
|
71
147
|
{ attributes: { "content-label": "breakpoint step" } },
|
|
72
|
-
],
|
|
148
|
+
]),
|
|
73
149
|
isInitial: false,
|
|
74
150
|
},
|
|
75
151
|
],
|
|
@@ -268,12 +344,12 @@ describe("projectIRToBundledPage — round-trip against active.spec", () => {
|
|
|
268
344
|
{
|
|
269
345
|
id: "first",
|
|
270
346
|
name: "First",
|
|
271
|
-
|
|
347
|
+
assertions: assertionsFromCriteria("first", "First", [{ role: "heading" }]),
|
|
272
348
|
},
|
|
273
349
|
{
|
|
274
350
|
id: "second",
|
|
275
351
|
name: "Second",
|
|
276
|
-
|
|
352
|
+
assertions: assertionsFromCriteria("second", "Second", [{ role: "button" }]),
|
|
277
353
|
},
|
|
278
354
|
],
|
|
279
355
|
transitions: [],
|
|
@@ -388,7 +464,7 @@ describe("projectIRToBundledPage — empty cases", () => {
|
|
|
388
464
|
{
|
|
389
465
|
id: "no-req",
|
|
390
466
|
name: "No Required Elements",
|
|
391
|
-
|
|
467
|
+
assertions: [],
|
|
392
468
|
},
|
|
393
469
|
],
|
|
394
470
|
transitions: [],
|
|
@@ -499,7 +575,7 @@ describe("projectIRToBundledPage — empty cases", () => {
|
|
|
499
575
|
{
|
|
500
576
|
id: "empty-text",
|
|
501
577
|
name: "Empty Text",
|
|
502
|
-
|
|
578
|
+
assertions: assertionsFromCriteria("empty-text", "Empty Text", [{ text: "" }]),
|
|
503
579
|
},
|
|
504
580
|
],
|
|
505
581
|
transitions: [],
|
|
@@ -515,8 +591,16 @@ describe("projectIRToBundledPage — empty cases", () => {
|
|
|
515
591
|
id: "p",
|
|
516
592
|
name: "P",
|
|
517
593
|
states: [
|
|
518
|
-
{
|
|
519
|
-
|
|
594
|
+
{
|
|
595
|
+
id: "a",
|
|
596
|
+
name: "A",
|
|
597
|
+
assertions: assertionsFromCriteria("a", "A", [{ role: "heading" }]),
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
id: "b",
|
|
601
|
+
name: "B",
|
|
602
|
+
assertions: assertionsFromCriteria("b", "B", [{ role: "heading" }]),
|
|
603
|
+
},
|
|
520
604
|
],
|
|
521
605
|
transitions: [
|
|
522
606
|
{
|
|
@@ -541,8 +625,16 @@ describe("projectIRToBundledPage — empty cases", () => {
|
|
|
541
625
|
id: "p",
|
|
542
626
|
name: "P",
|
|
543
627
|
states: [
|
|
544
|
-
{
|
|
545
|
-
|
|
628
|
+
{
|
|
629
|
+
id: "base",
|
|
630
|
+
name: "Base",
|
|
631
|
+
assertions: assertionsFromCriteria("base", "Base", [{ role: "heading" }]),
|
|
632
|
+
},
|
|
633
|
+
{
|
|
634
|
+
id: "modal",
|
|
635
|
+
name: "Modal",
|
|
636
|
+
assertions: assertionsFromCriteria("modal", "Modal", [{ role: "dialog" }]),
|
|
637
|
+
},
|
|
546
638
|
],
|
|
547
639
|
transitions: [
|
|
548
640
|
{
|
|
@@ -576,7 +668,7 @@ describe("projectIRToBundledPage — provenance + state metadata", () => {
|
|
|
576
668
|
{
|
|
577
669
|
id: "s",
|
|
578
670
|
name: "S",
|
|
579
|
-
|
|
671
|
+
assertions: assertionsFromCriteria("s", "S", [{ role: "heading" }]),
|
|
580
672
|
provenance: { source: "hand-authored", file: "p.tsx" },
|
|
581
673
|
},
|
|
582
674
|
],
|
|
@@ -595,7 +687,7 @@ describe("projectIRToBundledPage — provenance + state metadata", () => {
|
|
|
595
687
|
{
|
|
596
688
|
id: "s",
|
|
597
689
|
name: "S",
|
|
598
|
-
|
|
690
|
+
assertions: assertionsFromCriteria("s", "S", [{ role: "heading" }]),
|
|
599
691
|
},
|
|
600
692
|
],
|
|
601
693
|
transitions: [],
|
|
@@ -613,7 +705,7 @@ describe("projectIRToBundledPage — provenance + state metadata", () => {
|
|
|
613
705
|
{
|
|
614
706
|
id: "s",
|
|
615
707
|
name: "S",
|
|
616
|
-
|
|
708
|
+
assertions: assertionsFromCriteria("s", "S", [{ role: "heading" }]),
|
|
617
709
|
metadata: { description: "From metadata" },
|
|
618
710
|
},
|
|
619
711
|
],
|
|
@@ -632,7 +724,7 @@ describe("projectIRToBundledPage — provenance + state metadata", () => {
|
|
|
632
724
|
{
|
|
633
725
|
id: "s",
|
|
634
726
|
name: "S",
|
|
635
|
-
|
|
727
|
+
assertions: assertionsFromCriteria("s", "S", [{ role: "heading" }]),
|
|
636
728
|
},
|
|
637
729
|
],
|
|
638
730
|
transitions: [],
|
|
@@ -834,21 +926,21 @@ describe("projectLegacyToIR — basic shape", () => {
|
|
|
834
926
|
expect(alpha.description).toBe("First group for the round-trip test.");
|
|
835
927
|
});
|
|
836
928
|
|
|
837
|
-
it("sources
|
|
929
|
+
it("sources state.assertions[].target.criteria from group.assertions[].target.criteria (inverted)", () => {
|
|
838
930
|
const ir = projectLegacyToIR(LEGACY_FIXTURE);
|
|
839
931
|
const alpha = ir.states.find((s) => s.id === "alpha")!;
|
|
840
|
-
expect(alpha.
|
|
841
|
-
expect(alpha.
|
|
932
|
+
expect(alpha.assertions).toHaveLength(2);
|
|
933
|
+
expect(criteriaOf(alpha.assertions[0]!)).toEqual({
|
|
842
934
|
role: "heading",
|
|
843
935
|
text: "Alpha",
|
|
844
936
|
});
|
|
845
|
-
expect(alpha.
|
|
937
|
+
expect(criteriaOf(alpha.assertions[1]!)).toEqual({ text: "Welcome" });
|
|
846
938
|
});
|
|
847
939
|
|
|
848
940
|
it("inverts dataAttributes -> attributes and accessibleName passthrough", () => {
|
|
849
941
|
const ir = projectLegacyToIR(LEGACY_FIXTURE);
|
|
850
942
|
const beta = ir.states.find((s) => s.id === "beta")!;
|
|
851
|
-
expect(beta.
|
|
943
|
+
expect(criteriaOf(beta.assertions[0]!)).toEqual({
|
|
852
944
|
role: "dialog",
|
|
853
945
|
accessibleName: "Confirm",
|
|
854
946
|
});
|
|
@@ -114,10 +114,16 @@ const SUPPORTED_IR_VERSIONS = new Set<string>(["1.0"]);
|
|
|
114
114
|
* incomingTransitions, crossRefs, visualRefs).
|
|
115
115
|
*/
|
|
116
116
|
export function adaptIRState(state: IRState): AdaptedState {
|
|
117
|
+
// Project rich IR assertions down to the runtime's flat element-criteria
|
|
118
|
+
// list. The runtime engine (ui-bridge-auto's WorkflowConfig.StateConfig)
|
|
119
|
+
// doesn't carry per-element severity/category — those metadata fields stay
|
|
120
|
+
// IR-side, consumed by Spec-Check policies.
|
|
117
121
|
const out: AdaptedState = {
|
|
118
122
|
id: state.id,
|
|
119
123
|
name: state.name,
|
|
120
|
-
requiredElements: state.
|
|
124
|
+
requiredElements: state.assertions.map(
|
|
125
|
+
(a) => a.target.criteria as unknown as IRElementCriteria,
|
|
126
|
+
),
|
|
121
127
|
};
|
|
122
128
|
if (state.description !== undefined) out.description = state.description;
|
|
123
129
|
if (state.excludedElements !== undefined) out.excludedElements = state.excludedElements;
|
|
@@ -95,7 +95,11 @@
|
|
|
95
95
|
"file": { "type": "string" },
|
|
96
96
|
"line": { "type": "integer", "minimum": 1 },
|
|
97
97
|
"column": { "type": "integer", "minimum": 1 },
|
|
98
|
-
"pluginVersion": { "type": "string" }
|
|
98
|
+
"pluginVersion": { "type": "string" },
|
|
99
|
+
"status": {
|
|
100
|
+
"type": "string",
|
|
101
|
+
"enum": ["proposed", "pending", "promoted"]
|
|
102
|
+
}
|
|
99
103
|
}
|
|
100
104
|
},
|
|
101
105
|
"IRCrossRef": {
|
|
@@ -146,15 +150,15 @@
|
|
|
146
150
|
},
|
|
147
151
|
"IRState": {
|
|
148
152
|
"type": "object",
|
|
149
|
-
"required": ["id", "name", "
|
|
153
|
+
"required": ["id", "name", "assertions"],
|
|
150
154
|
"additionalProperties": false,
|
|
151
155
|
"properties": {
|
|
152
156
|
"id": { "type": "string" },
|
|
153
157
|
"name": { "type": "string" },
|
|
154
158
|
"description": { "type": "string" },
|
|
155
|
-
"
|
|
159
|
+
"assertions": {
|
|
156
160
|
"type": "array",
|
|
157
|
-
"items": { "$ref": "#/$defs/
|
|
161
|
+
"items": { "$ref": "#/$defs/IRAssertion" }
|
|
158
162
|
},
|
|
159
163
|
"excludedElements": {
|
|
160
164
|
"type": "array",
|
|
@@ -27,6 +27,14 @@ export interface IRProvenance {
|
|
|
27
27
|
column?: number;
|
|
28
28
|
/** Build-plugin version that produced this node, if applicable. */
|
|
29
29
|
pluginVersion?: string;
|
|
30
|
+
/**
|
|
31
|
+
* Lifecycle status for the Stream E coverage-growth flywheel. Absent =
|
|
32
|
+
* implicitly `"promoted"` (legacy + on-disk specs that predate the field).
|
|
33
|
+
* Set to `"proposed"` by `spec_authoring`, `"pending"` when staged in
|
|
34
|
+
* `_pending/`, `"promoted"` after the 2-green sweep moves the file to
|
|
35
|
+
* `pages/<id>/`.
|
|
36
|
+
*/
|
|
37
|
+
status?: "proposed" | "pending" | "promoted";
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
// ---------------------------------------------------------------------------
|
|
@@ -371,58 +371,13 @@ function convertCriteria(criteria: IRElementCriteria): LegacyCriteria {
|
|
|
371
371
|
}
|
|
372
372
|
|
|
373
373
|
/**
|
|
374
|
-
* Build
|
|
375
|
-
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
* empty `assertions[]` — legitimate legacy specs (e.g. architecture-only
|
|
379
|
-
* groups in `graphql-infrastructure`, `activity-timeline`, `opik-integration`,
|
|
380
|
-
* `watchers`) ship with empty `assertions[]`, and the inverse projection
|
|
381
|
-
* round-trip must preserve that emptiness or `check-spec-pairing` flags an
|
|
382
|
-
* assertion-count drift.
|
|
383
|
-
*/
|
|
384
|
-
function buildAssertion(
|
|
385
|
-
state: IRState,
|
|
386
|
-
index: number,
|
|
387
|
-
criteria: IRElementCriteria,
|
|
388
|
-
): LegacyAssertion {
|
|
389
|
-
const description =
|
|
390
|
-
state.metadata?.description ?? `Required element ${index} for state ${state.name}`;
|
|
391
|
-
const targetCriteria: LegacyCriteria = convertCriteria(criteria);
|
|
392
|
-
const assertion: LegacyAssertion = {
|
|
393
|
-
id: `${state.id}-elem-${index}`,
|
|
394
|
-
description,
|
|
395
|
-
category: "element-presence",
|
|
396
|
-
severity: "critical",
|
|
397
|
-
assertionType: "exists",
|
|
398
|
-
target: {
|
|
399
|
-
type: "search",
|
|
400
|
-
criteria: targetCriteria,
|
|
401
|
-
label: `Required element for ${state.name}`,
|
|
402
|
-
},
|
|
403
|
-
source: "ai-generated",
|
|
404
|
-
reviewed: false,
|
|
405
|
-
enabled: true,
|
|
406
|
-
};
|
|
407
|
-
if (state.precondition !== undefined) {
|
|
408
|
-
assertion.precondition = state.precondition;
|
|
409
|
-
}
|
|
410
|
-
return assertion;
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
/**
|
|
414
|
-
* Build the legacy `groups[]` entry for one IR state. Emits exactly one
|
|
415
|
-
* assertion per `requiredElement`; states with zero requiredElements project
|
|
416
|
-
* to a group with an empty `assertions[]` array. Legacy consumers (runner
|
|
417
|
-
* spec drift / verify, error monitor curator, AI session) tolerate empty
|
|
418
|
-
* groups — multiple shipping legacy specs already use them for
|
|
419
|
-
* architecture-only / documentation-only groups.
|
|
374
|
+
* Build the legacy `groups[]` entry for one IR state. With IrState.assertions
|
|
375
|
+
* carrying first-class assertion metadata (id/description/severity/category/
|
|
376
|
+
* target), this is now a direct shape-conversion per assertion — no more
|
|
377
|
+
* synthesizing IDs or defaulting severity.
|
|
420
378
|
*/
|
|
421
379
|
function buildGroup(state: IRState): LegacyGroup {
|
|
422
|
-
const
|
|
423
|
-
const assertions: LegacyAssertion[] = elems.map((c, i) =>
|
|
424
|
-
buildAssertion(state, i, c),
|
|
425
|
-
);
|
|
380
|
+
const assertions: LegacyAssertion[] = state.assertions.map(synthesizedAssertionToLegacy);
|
|
426
381
|
return {
|
|
427
382
|
id: state.id,
|
|
428
383
|
name: state.name,
|
|
@@ -535,7 +490,10 @@ function buildStateMachineState(
|
|
|
535
490
|
id: state.id,
|
|
536
491
|
name: state.name,
|
|
537
492
|
description: state.description ?? "",
|
|
538
|
-
|
|
493
|
+
// Project legacy `elements[]` from each assertion's target.criteria.
|
|
494
|
+
elements: state.assertions.map((a) =>
|
|
495
|
+
convertCriteria(a.target.criteria as IRElementCriteria),
|
|
496
|
+
),
|
|
539
497
|
isInitial,
|
|
540
498
|
transitions: outgoing,
|
|
541
499
|
};
|
|
@@ -680,11 +638,30 @@ function buildIRState(
|
|
|
680
638
|
group: LegacyGroup,
|
|
681
639
|
smState: LegacyStateMachineState | undefined,
|
|
682
640
|
): IRState {
|
|
683
|
-
//
|
|
684
|
-
//
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
641
|
+
// Map each LegacyAssertion to an IRAssertion, preserving id/description/
|
|
642
|
+
// severity/category. target.criteria is normalized via invertCriteria so
|
|
643
|
+
// the criteria shape matches what the IR side stores.
|
|
644
|
+
const assertions: IRAssertion[] = group.assertions.map((a) => {
|
|
645
|
+
const ir: IRAssertion = {
|
|
646
|
+
id: a.id,
|
|
647
|
+
description: a.description,
|
|
648
|
+
category: a.category,
|
|
649
|
+
severity: a.severity,
|
|
650
|
+
assertionType: a.assertionType,
|
|
651
|
+
target: {
|
|
652
|
+
type: "search",
|
|
653
|
+
criteria: invertCriteria(a.target?.criteria) as unknown as Record<string, unknown>,
|
|
654
|
+
label: a.target?.label ?? a.description,
|
|
655
|
+
},
|
|
656
|
+
source: a.source,
|
|
657
|
+
reviewed: a.reviewed,
|
|
658
|
+
enabled: a.enabled,
|
|
659
|
+
};
|
|
660
|
+
if (a.precondition !== undefined) {
|
|
661
|
+
ir.precondition = a.precondition;
|
|
662
|
+
}
|
|
663
|
+
return ir;
|
|
664
|
+
});
|
|
688
665
|
|
|
689
666
|
const description =
|
|
690
667
|
group.description !== undefined && group.description.length > 0
|
|
@@ -695,7 +672,7 @@ function buildIRState(
|
|
|
695
672
|
const state: IRState = {
|
|
696
673
|
id: group.id,
|
|
697
674
|
name: smState?.name ?? group.name,
|
|
698
|
-
|
|
675
|
+
assertions,
|
|
699
676
|
};
|
|
700
677
|
if (description !== undefined && description.length > 0) {
|
|
701
678
|
state.description = description;
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type { IRElementCriteria } from "./element-criteria";
|
|
10
|
+
import type { IRAssertion } from "./group";
|
|
10
11
|
import type { IRCrossRef, IRMetadata, IRProvenance, IRVisualRef } from "./primitives";
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -42,8 +43,14 @@ export interface IRState {
|
|
|
42
43
|
description?: string;
|
|
43
44
|
|
|
44
45
|
// Predicates (canonical) -----------------------------------------------
|
|
45
|
-
/**
|
|
46
|
-
|
|
46
|
+
/**
|
|
47
|
+
* State-scoped assertions. Each carries its own assertion_id, description,
|
|
48
|
+
* severity, category, and an IrElementCriteria target via target.criteria.
|
|
49
|
+
* Spec-Check (Plan 02) evaluates these against UI Bridge snapshots; policy
|
|
50
|
+
* filtering via `severity`/`category` is meaningful because each assertion
|
|
51
|
+
* carries its own metadata (no synthesized stubs).
|
|
52
|
+
*/
|
|
53
|
+
assertions: IRAssertion[];
|
|
47
54
|
/** Element criteria where NONE may be satisfied (any match disqualifies). */
|
|
48
55
|
excludedElements?: IRElementCriteria[];
|
|
49
56
|
/** Additional property checks on matched elements. */
|