@sigloch/contracts 0.7.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/LICENSE +21 -0
- package/dist/harness/index.d.ts +185 -0
- package/dist/harness/index.js +185 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +14 -0
- package/dist/se/ao-rules.d.ts +59 -0
- package/dist/se/ao-rules.js +341 -0
- package/dist/se/conformance-rules.d.ts +64 -0
- package/dist/se/conformance-rules.js +364 -0
- package/dist/se/cr-quality-rules.d.ts +8 -0
- package/dist/se/cr-quality-rules.js +141 -0
- package/dist/se/evaluate-all.d.ts +17 -0
- package/dist/se/evaluate-all.js +50 -0
- package/dist/se/fchain-quality-rules.d.ts +10 -0
- package/dist/se/fchain-quality-rules.js +105 -0
- package/dist/se/fmea-rules.d.ts +17 -0
- package/dist/se/fmea-rules.js +137 -0
- package/dist/se/format-e-parser.d.ts +28 -0
- package/dist/se/format-e-parser.js +217 -0
- package/dist/se/index.d.ts +28 -0
- package/dist/se/index.js +28 -0
- package/dist/se/meta-model.d.ts +26 -0
- package/dist/se/meta-model.js +60 -0
- package/dist/se/metric-rules.d.ts +45 -0
- package/dist/se/metric-rules.js +208 -0
- package/dist/se/near-duplicate-rules.d.ts +44 -0
- package/dist/se/near-duplicate-rules.js +106 -0
- package/dist/se/ontology.d.ts +327 -0
- package/dist/se/ontology.js +216 -0
- package/dist/se/quality-rules.d.ts +28 -0
- package/dist/se/quality-rules.js +206 -0
- package/dist/se/readiness.d.ts +62 -0
- package/dist/se/readiness.js +79 -0
- package/dist/se/rules.d.ts +159 -0
- package/dist/se/rules.js +854 -0
- package/dist/se/schema-quality-rules.d.ts +11 -0
- package/dist/se/schema-quality-rules.js +73 -0
- package/dist/se/semantic-id.d.ts +30 -0
- package/dist/se/semantic-id.js +90 -0
- package/dist/se/uc-quality-rules.d.ts +13 -0
- package/dist/se/uc-quality-rules.js +123 -0
- package/dist/se/view-rules.d.ts +11 -0
- package/dist/se/view-rules.js +56 -0
- package/package.json +51 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Weasel words list (BQ-01)
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
const WEASEL_WORDS = [
|
|
5
|
+
'should', 'may', 'might', 'appropriate', 'etc', 'adequate', 'as needed',
|
|
6
|
+
'various', 'some', 'often', 'usually', 'normally', 'generally', 'typically',
|
|
7
|
+
'mostly', 'largely', 'commonly', 'presumably', 'possibly', 'potentially',
|
|
8
|
+
'approximately', 'roughly', 'around', 'about', 'near', 'nearly',
|
|
9
|
+
// CR-121 P1: Extended from graphengine requirements-engineer.md
|
|
10
|
+
'fast', 'slow', 'easy', 'simple', 'flexible', 'scalable', 'robust',
|
|
11
|
+
'sufficient', 'reasonable', 'minimal', 'optimal', 'best effort',
|
|
12
|
+
'when possible', 'as far as practicable',
|
|
13
|
+
];
|
|
14
|
+
const weaselPattern = new RegExp(`\\b(${WEASEL_WORDS.map(w => w.replace(/\s+/g, '\\s+')).join('|')})\\b`, 'i');
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Measurable criterion regex (BQ-02)
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
const measurablePattern = /(\d+[\s]*(ms|s|sec|min|%|percent|byte|MB|GB|times|x|sessions?)|\b(must|shall|exactly|at least|at most|no more than|within|before|after|greater|less|equal|minimum|maximum|genau|mindestens|hoechstens|höchstens|nicht mehr als|innerhalb|groesser|größer|kleiner|gleich)\b)/i;
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Helper: filter REQ elements
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
function reqElements(graph) {
|
|
23
|
+
return graph.elements.filter(e => e.type === 'REQ');
|
|
24
|
+
}
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// BQ-01 Unambiguous — detect weasel words in REQ descriptions
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
export function bq01Unambiguous(graph) {
|
|
29
|
+
return reqElements(graph)
|
|
30
|
+
.filter(req => weaselPattern.test(req.description))
|
|
31
|
+
.map(req => {
|
|
32
|
+
const match = req.description.match(weaselPattern);
|
|
33
|
+
return {
|
|
34
|
+
rule_id: 'BQ-01',
|
|
35
|
+
severity: 'warning',
|
|
36
|
+
element_id: req.id,
|
|
37
|
+
message: `${req.id} contains weasel word "${match?.[1]}"`,
|
|
38
|
+
fix_hint: 'Replace vague language with precise, testable statements',
|
|
39
|
+
context: {
|
|
40
|
+
element_type: req.type,
|
|
41
|
+
element_name: req.name,
|
|
42
|
+
current_description: req.description,
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
// ---------------------------------------------------------------------------
|
|
48
|
+
// BQ-02 Verifiable — REQ must contain at least one measurable criterion
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
export function bq02Verifiable(graph) {
|
|
51
|
+
return reqElements(graph)
|
|
52
|
+
.filter(req => !measurablePattern.test(req.description))
|
|
53
|
+
.map(req => ({
|
|
54
|
+
rule_id: 'BQ-02',
|
|
55
|
+
severity: 'warning',
|
|
56
|
+
element_id: req.id,
|
|
57
|
+
message: `${req.id} has no measurable criterion`,
|
|
58
|
+
fix_hint: 'Add a concrete metric, threshold, or comparison operator',
|
|
59
|
+
context: {
|
|
60
|
+
element_type: req.type,
|
|
61
|
+
element_name: req.name,
|
|
62
|
+
current_description: req.description,
|
|
63
|
+
},
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// BQ-04 Necessary — semantic duplicate REQ detection (CR-054)
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
/** Threshold above which two REQs are considered near-duplicates. */
|
|
70
|
+
const BQ04_SIMILARITY_THRESHOLD = 0.85;
|
|
71
|
+
/**
|
|
72
|
+
* Module-level similarity matrix + REQ ID list, set by `setBQ04SimilarityMatrix()`.
|
|
73
|
+
* When null, bq04Necessary returns [] (backward-compat).
|
|
74
|
+
*/
|
|
75
|
+
let _bq04Matrix = null;
|
|
76
|
+
/**
|
|
77
|
+
* Inject a pre-computed similarity matrix for BQ-04.
|
|
78
|
+
* Call this before evaluateBQRules() when embeddings are available.
|
|
79
|
+
* Pass null to clear.
|
|
80
|
+
*/
|
|
81
|
+
export function setBQ04SimilarityMatrix(data) {
|
|
82
|
+
_bq04Matrix = data;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* BQ-04 checks for duplicate / near-duplicate requirements using
|
|
86
|
+
* pre-computed embedding similarity. Returns [] when no matrix is set.
|
|
87
|
+
*/
|
|
88
|
+
export function bq04Necessary(graph) {
|
|
89
|
+
if (!_bq04Matrix)
|
|
90
|
+
return [];
|
|
91
|
+
const { reqIds, matrix } = _bq04Matrix;
|
|
92
|
+
const violations = [];
|
|
93
|
+
const seen = new Set();
|
|
94
|
+
for (let i = 0; i < reqIds.length; i++) {
|
|
95
|
+
for (let j = i + 1; j < reqIds.length; j++) {
|
|
96
|
+
const sim = matrix[i][j];
|
|
97
|
+
if (sim < BQ04_SIMILARITY_THRESHOLD)
|
|
98
|
+
continue;
|
|
99
|
+
const pairKey = `${reqIds[i]}:${reqIds[j]}`;
|
|
100
|
+
if (seen.has(pairKey))
|
|
101
|
+
continue;
|
|
102
|
+
seen.add(pairKey);
|
|
103
|
+
const pct = Math.round(sim * 100);
|
|
104
|
+
// Determine UC ownership via compose traces for overlap hint
|
|
105
|
+
const ucA = findOwnerUC(graph, reqIds[i]);
|
|
106
|
+
const ucB = findOwnerUC(graph, reqIds[j]);
|
|
107
|
+
const overlapHint = ucA && ucB && ucA !== ucB
|
|
108
|
+
? ` — UC overlap: ${ucA} and ${ucB} have overlapping concerns`
|
|
109
|
+
: '';
|
|
110
|
+
const elJ = graph.elements.find(e => e.id === reqIds[j]);
|
|
111
|
+
const elI = graph.elements.find(e => e.id === reqIds[i]);
|
|
112
|
+
violations.push({
|
|
113
|
+
rule_id: 'BQ-04',
|
|
114
|
+
severity: 'warning',
|
|
115
|
+
element_id: reqIds[j],
|
|
116
|
+
message: `${reqIds[j]} is ${pct}% similar to ${reqIds[i]}${overlapHint}`,
|
|
117
|
+
fix_hint: 'Merge into single REQ or differentiate descriptions',
|
|
118
|
+
context: {
|
|
119
|
+
element_type: elJ?.type,
|
|
120
|
+
element_name: elJ?.name,
|
|
121
|
+
candidate_targets: elI ? [{ id: elI.id, type: elI.type, name: elI.name }] : undefined,
|
|
122
|
+
current_description: elJ?.description,
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return violations;
|
|
128
|
+
}
|
|
129
|
+
/** Find the UC that composes a given REQ (via UC [compose] → REQ trace). */
|
|
130
|
+
function findOwnerUC(graph, reqId) {
|
|
131
|
+
const trace = graph.traces.find(t => t.target === reqId && t.type === 'compose'
|
|
132
|
+
&& graph.elements.some(e => e.id === t.source && e.type === 'UC'));
|
|
133
|
+
return trace?.source ?? null;
|
|
134
|
+
}
|
|
135
|
+
// ---------------------------------------------------------------------------
|
|
136
|
+
// BQ-06 Conforming — REQ description should follow "system shall" pattern
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
const conformingPattern = /\b(shall|must|must not)\s+\w+/i;
|
|
139
|
+
const conformingPatternDE = /\b(soll|muss|darf nicht)\s+\w+/i;
|
|
140
|
+
export function bq06Conforming(graph) {
|
|
141
|
+
return reqElements(graph)
|
|
142
|
+
.filter(req => {
|
|
143
|
+
const desc = req.description.trim();
|
|
144
|
+
return !conformingPattern.test(desc) && !conformingPatternDE.test(desc);
|
|
145
|
+
})
|
|
146
|
+
.map(req => ({
|
|
147
|
+
rule_id: 'BQ-06',
|
|
148
|
+
severity: 'warning',
|
|
149
|
+
element_id: req.id,
|
|
150
|
+
message: `${req.id} does not follow "System shall..." pattern`,
|
|
151
|
+
fix_hint: 'Start description with "The system shall <verb>" or "Das System soll/muss <verb>"',
|
|
152
|
+
context: {
|
|
153
|
+
element_type: req.type,
|
|
154
|
+
element_name: req.name,
|
|
155
|
+
current_description: req.description,
|
|
156
|
+
},
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
// ---------------------------------------------------------------------------
|
|
160
|
+
// BQ-07 Complete — REQ must have meaningful description and no placeholders
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
const placeholderPattern = /\b(TBD|TBR|TODO|placeholder|to be determined)\b|needs\s.*review/i;
|
|
163
|
+
const BQ07_MIN_DESC_LENGTH = 20;
|
|
164
|
+
export function bq07Complete(graph) {
|
|
165
|
+
return reqElements(graph)
|
|
166
|
+
.filter(req => {
|
|
167
|
+
const tooShort = req.description.trim().length < BQ07_MIN_DESC_LENGTH;
|
|
168
|
+
const hasPlaceholder = placeholderPattern.test(req.description);
|
|
169
|
+
return tooShort || hasPlaceholder;
|
|
170
|
+
})
|
|
171
|
+
.map(req => {
|
|
172
|
+
const reasons = [];
|
|
173
|
+
if (req.description.trim().length < BQ07_MIN_DESC_LENGTH) {
|
|
174
|
+
reasons.push(`description too short (${req.description.trim().length}/${BQ07_MIN_DESC_LENGTH} chars)`);
|
|
175
|
+
}
|
|
176
|
+
if (placeholderPattern.test(req.description)) {
|
|
177
|
+
reasons.push('contains placeholder');
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
rule_id: 'BQ-07',
|
|
181
|
+
severity: 'warning',
|
|
182
|
+
element_id: req.id,
|
|
183
|
+
message: `${req.id} is incomplete: ${reasons.join(', ')}`,
|
|
184
|
+
fix_hint: 'Write a meaningful description (min 20 chars) and resolve all TBD/TBR/TODO placeholders',
|
|
185
|
+
context: {
|
|
186
|
+
element_type: req.type,
|
|
187
|
+
element_name: req.name,
|
|
188
|
+
current_description: req.description,
|
|
189
|
+
},
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
// ---------------------------------------------------------------------------
|
|
194
|
+
// Aggregated array & convenience runner
|
|
195
|
+
// ---------------------------------------------------------------------------
|
|
196
|
+
export const BQ_RULES = [
|
|
197
|
+
{ id: 'BQ-01', name: 'Unambiguous', severity: 'warning', evaluate: bq01Unambiguous },
|
|
198
|
+
{ id: 'BQ-02', name: 'Verifiable', severity: 'warning', evaluate: bq02Verifiable },
|
|
199
|
+
{ id: 'BQ-04', name: 'Necessary', severity: 'warning', evaluate: bq04Necessary },
|
|
200
|
+
{ id: 'BQ-06', name: 'Conforming', severity: 'warning', evaluate: bq06Conforming },
|
|
201
|
+
{ id: 'BQ-07', name: 'Complete', severity: 'warning', evaluate: bq07Complete },
|
|
202
|
+
];
|
|
203
|
+
/** Run all BQ rules against a graph, returning combined violations. */
|
|
204
|
+
export function evaluateBQRules(graph) {
|
|
205
|
+
return BQ_RULES.flatMap(rule => rule.evaluate(graph));
|
|
206
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CR-120: Readiness dimension schemas for dynamic phase readiness.
|
|
3
|
+
* Dimensions emerge from graph state — no state machine.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod/v4';
|
|
6
|
+
export declare const ReadinessDimension: z.ZodEnum<{
|
|
7
|
+
req: "req";
|
|
8
|
+
uc: "uc";
|
|
9
|
+
arch: "arch";
|
|
10
|
+
alloc: "alloc";
|
|
11
|
+
ver: "ver";
|
|
12
|
+
schema: "schema";
|
|
13
|
+
cr: "cr";
|
|
14
|
+
ms: "ms";
|
|
15
|
+
}>;
|
|
16
|
+
export type ReadinessDimensionType = z.infer<typeof ReadinessDimension>;
|
|
17
|
+
export declare const ReadinessScore: z.ZodObject<{
|
|
18
|
+
dimension: z.ZodEnum<{
|
|
19
|
+
req: "req";
|
|
20
|
+
uc: "uc";
|
|
21
|
+
arch: "arch";
|
|
22
|
+
alloc: "alloc";
|
|
23
|
+
ver: "ver";
|
|
24
|
+
schema: "schema";
|
|
25
|
+
cr: "cr";
|
|
26
|
+
ms: "ms";
|
|
27
|
+
}>;
|
|
28
|
+
score: z.ZodNumber;
|
|
29
|
+
violations: z.ZodNumber;
|
|
30
|
+
applicable: z.ZodNumber;
|
|
31
|
+
ready: z.ZodBoolean;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
export type ReadinessScoreType = z.infer<typeof ReadinessScore>;
|
|
34
|
+
export declare const ReadinessReport: z.ZodObject<{
|
|
35
|
+
scores: z.ZodArray<z.ZodObject<{
|
|
36
|
+
dimension: z.ZodEnum<{
|
|
37
|
+
req: "req";
|
|
38
|
+
uc: "uc";
|
|
39
|
+
arch: "arch";
|
|
40
|
+
alloc: "alloc";
|
|
41
|
+
ver: "ver";
|
|
42
|
+
schema: "schema";
|
|
43
|
+
cr: "cr";
|
|
44
|
+
ms: "ms";
|
|
45
|
+
}>;
|
|
46
|
+
score: z.ZodNumber;
|
|
47
|
+
violations: z.ZodNumber;
|
|
48
|
+
applicable: z.ZodNumber;
|
|
49
|
+
ready: z.ZodBoolean;
|
|
50
|
+
}, z.core.$strip>>;
|
|
51
|
+
emergentPhase: z.ZodString;
|
|
52
|
+
phaseScore: z.ZodNumber;
|
|
53
|
+
overallScore: z.ZodNumber;
|
|
54
|
+
timestamp: z.ZodISODateTime;
|
|
55
|
+
}, z.core.$strip>;
|
|
56
|
+
export type ReadinessReportType = z.infer<typeof ReadinessReport>;
|
|
57
|
+
/**
|
|
58
|
+
* Rule → dimension mapping. Some rules belong to multiple dimensions;
|
|
59
|
+
* here we assign primary dimension per rule. R-01 appears in 'ver' (primary)
|
|
60
|
+
* since its core concern is test verification coverage.
|
|
61
|
+
*/
|
|
62
|
+
export declare const RULE_TO_DIMENSION: Record<string, ReadinessDimensionType>;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CR-120: Readiness dimension schemas for dynamic phase readiness.
|
|
3
|
+
* Dimensions emerge from graph state — no state machine.
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod/v4';
|
|
6
|
+
export const ReadinessDimension = z.enum([
|
|
7
|
+
'req', // Requirements quality (BQ-01..07, RD-01..03)
|
|
8
|
+
'uc', // UC completeness (UC-01..06, R-14, FC-01..03)
|
|
9
|
+
'arch', // Functional architecture (R-02, R-03, R-10, R-12)
|
|
10
|
+
'alloc', // Module allocation (R-04)
|
|
11
|
+
'ver', // Test coverage (R-01, R-05)
|
|
12
|
+
'schema', // Interface completeness (SC-01..03)
|
|
13
|
+
'cr', // CR traceability (CR-R01..R03)
|
|
14
|
+
'ms', // Milestone planning (MS-01..02)
|
|
15
|
+
]);
|
|
16
|
+
export const ReadinessScore = z.object({
|
|
17
|
+
dimension: ReadinessDimension,
|
|
18
|
+
score: z.number().min(0).max(1), // 1 - (violations / applicable)
|
|
19
|
+
violations: z.number().int(),
|
|
20
|
+
applicable: z.number().int(),
|
|
21
|
+
ready: z.boolean(), // score >= 0.7
|
|
22
|
+
});
|
|
23
|
+
export const ReadinessReport = z.object({
|
|
24
|
+
scores: z.array(ReadinessScore),
|
|
25
|
+
emergentPhase: z.string(),
|
|
26
|
+
phaseScore: z.number().min(0).max(1), // CR-146: % progress of current phase
|
|
27
|
+
overallScore: z.number().min(0).max(1),
|
|
28
|
+
timestamp: z.iso.datetime(),
|
|
29
|
+
});
|
|
30
|
+
/**
|
|
31
|
+
* Rule → dimension mapping. Some rules belong to multiple dimensions;
|
|
32
|
+
* here we assign primary dimension per rule. R-01 appears in 'ver' (primary)
|
|
33
|
+
* since its core concern is test verification coverage.
|
|
34
|
+
*/
|
|
35
|
+
export const RULE_TO_DIMENSION = {
|
|
36
|
+
// req
|
|
37
|
+
'BQ-01': 'req', 'BQ-02': 'req', 'BQ-04': 'req',
|
|
38
|
+
'BQ-06': 'req', 'BQ-07': 'req',
|
|
39
|
+
'RD-01': 'req', 'RD-02': 'req', 'RD-03': 'req',
|
|
40
|
+
// trace/realization/allocation completeness rules (CR-228 D: previously unmapped → advisory fall-through)
|
|
41
|
+
'R-18': 'arch', 'R-19': 'ver', 'R-20': 'arch', 'R-21': 'ver',
|
|
42
|
+
'R-22': 'alloc', 'R-23': 'alloc', 'R-26': 'schema',
|
|
43
|
+
// uc
|
|
44
|
+
'UC-01': 'uc', 'UC-02': 'uc', 'UC-03': 'uc', 'UC-04': 'uc',
|
|
45
|
+
'UC-05': 'uc', 'UC-06': 'uc',
|
|
46
|
+
'R-14': 'uc', 'R-15': 'uc', 'R-16': 'uc', 'R-17': 'uc',
|
|
47
|
+
'FC-01': 'uc', 'FC-02': 'uc', 'FC-03': 'uc',
|
|
48
|
+
// arch
|
|
49
|
+
'R-02': 'arch', 'R-03': 'arch', 'R-10': 'arch', 'R-12': 'arch',
|
|
50
|
+
// alloc
|
|
51
|
+
'R-04': 'alloc',
|
|
52
|
+
// ver
|
|
53
|
+
'R-01': 'ver', 'R-05': 'ver',
|
|
54
|
+
// schema
|
|
55
|
+
'SC-01': 'schema', 'SC-02': 'schema', 'SC-03': 'schema',
|
|
56
|
+
// structural rules without primary dimension → assigned by closest concern
|
|
57
|
+
'R-08': 'arch',
|
|
58
|
+
// near-duplicate detection
|
|
59
|
+
'ND-01': 'arch', 'ND-02': 'schema',
|
|
60
|
+
// architecture metrics
|
|
61
|
+
'MT-01': 'alloc', 'MT-02': 'alloc', 'MT-03': 'alloc',
|
|
62
|
+
// CR traceability
|
|
63
|
+
'CR-R01': 'cr', 'CR-R02': 'cr', 'CR-R03': 'cr', 'CR-R04': 'cr',
|
|
64
|
+
// architecture optimization
|
|
65
|
+
'AO-D01': 'arch', 'AO-D03': 'arch',
|
|
66
|
+
// allocation rules (CR-191)
|
|
67
|
+
'CR-01': 'arch', 'RT-01': 'arch', 'PH-01': 'arch', 'CA-01': 'arch',
|
|
68
|
+
// milestone planning
|
|
69
|
+
'MS-01': 'ms', 'MS-02': 'ms', 'MS-03': 'ms',
|
|
70
|
+
// FMEA / risk
|
|
71
|
+
'FM-01': 'req', 'FM-02': 'req', 'FM-03': 'ver',
|
|
72
|
+
// NFR budget
|
|
73
|
+
'NFR-01': 'arch',
|
|
74
|
+
// cross-module IO (CR-192)
|
|
75
|
+
'IO-01': 'arch',
|
|
76
|
+
// view rules (CR-184)
|
|
77
|
+
'VR-01': 'ver',
|
|
78
|
+
'CL-01': 'uc',
|
|
79
|
+
};
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SE Rules — declarative config table + evaluation (version: see RULES_VERSION in ./index.ts).
|
|
3
|
+
* R-07/R-09/R-13 removed (CR-180), RD-01..03 added.
|
|
4
|
+
* @sigloch/contracts/se — single source of truth for SE validation rules.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod/v4';
|
|
7
|
+
import type { OntologyGraph } from './ontology.js';
|
|
8
|
+
export declare const RuleSeverity: z.ZodEnum<{
|
|
9
|
+
error: "error";
|
|
10
|
+
warning: "warning";
|
|
11
|
+
info: "info";
|
|
12
|
+
}>;
|
|
13
|
+
export type RuleSeverity = z.infer<typeof RuleSeverity>;
|
|
14
|
+
/** Candidate target for resolving a violation (e.g. a REQ to satisfy, a TEST to link). */
|
|
15
|
+
export declare const ViolationCandidate: z.ZodObject<{
|
|
16
|
+
id: z.ZodString;
|
|
17
|
+
type: z.ZodEnum<{
|
|
18
|
+
SYS: "SYS";
|
|
19
|
+
UC: "UC";
|
|
20
|
+
ACTOR: "ACTOR";
|
|
21
|
+
FCHAIN: "FCHAIN";
|
|
22
|
+
FUNC: "FUNC";
|
|
23
|
+
FLOW: "FLOW";
|
|
24
|
+
REQ: "REQ";
|
|
25
|
+
TEST: "TEST";
|
|
26
|
+
MOD: "MOD";
|
|
27
|
+
SCHEMA: "SCHEMA";
|
|
28
|
+
SESSION: "SESSION";
|
|
29
|
+
CR: "CR";
|
|
30
|
+
MS: "MS";
|
|
31
|
+
}>;
|
|
32
|
+
name: z.ZodString;
|
|
33
|
+
}, z.core.$strip>;
|
|
34
|
+
export type ViolationCandidate = z.infer<typeof ViolationCandidate>;
|
|
35
|
+
/** Graph context attached to a violation — enables prompt generation without extra DB queries. */
|
|
36
|
+
export declare const ViolationContext: z.ZodObject<{
|
|
37
|
+
element_type: z.ZodOptional<z.ZodEnum<{
|
|
38
|
+
SYS: "SYS";
|
|
39
|
+
UC: "UC";
|
|
40
|
+
ACTOR: "ACTOR";
|
|
41
|
+
FCHAIN: "FCHAIN";
|
|
42
|
+
FUNC: "FUNC";
|
|
43
|
+
FLOW: "FLOW";
|
|
44
|
+
REQ: "REQ";
|
|
45
|
+
TEST: "TEST";
|
|
46
|
+
MOD: "MOD";
|
|
47
|
+
SCHEMA: "SCHEMA";
|
|
48
|
+
SESSION: "SESSION";
|
|
49
|
+
CR: "CR";
|
|
50
|
+
MS: "MS";
|
|
51
|
+
}>>;
|
|
52
|
+
element_name: z.ZodOptional<z.ZodString>;
|
|
53
|
+
candidate_targets: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
54
|
+
id: z.ZodString;
|
|
55
|
+
type: z.ZodEnum<{
|
|
56
|
+
SYS: "SYS";
|
|
57
|
+
UC: "UC";
|
|
58
|
+
ACTOR: "ACTOR";
|
|
59
|
+
FCHAIN: "FCHAIN";
|
|
60
|
+
FUNC: "FUNC";
|
|
61
|
+
FLOW: "FLOW";
|
|
62
|
+
REQ: "REQ";
|
|
63
|
+
TEST: "TEST";
|
|
64
|
+
MOD: "MOD";
|
|
65
|
+
SCHEMA: "SCHEMA";
|
|
66
|
+
SESSION: "SESSION";
|
|
67
|
+
CR: "CR";
|
|
68
|
+
MS: "MS";
|
|
69
|
+
}>;
|
|
70
|
+
name: z.ZodString;
|
|
71
|
+
}, z.core.$strip>>>;
|
|
72
|
+
existing_traces: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
73
|
+
target: z.ZodString;
|
|
74
|
+
type: z.ZodEnum<{
|
|
75
|
+
compose: "compose";
|
|
76
|
+
io: "io";
|
|
77
|
+
satisfy: "satisfy";
|
|
78
|
+
verify: "verify";
|
|
79
|
+
allocate: "allocate";
|
|
80
|
+
relation: "relation";
|
|
81
|
+
produces: "produces";
|
|
82
|
+
}>;
|
|
83
|
+
}, z.core.$strip>>>;
|
|
84
|
+
parent_module: z.ZodOptional<z.ZodString>;
|
|
85
|
+
current_description: z.ZodOptional<z.ZodString>;
|
|
86
|
+
}, z.core.$strip>;
|
|
87
|
+
export type ViolationContext = z.infer<typeof ViolationContext>;
|
|
88
|
+
export declare const RuleViolation: z.ZodObject<{
|
|
89
|
+
rule_id: z.ZodString;
|
|
90
|
+
severity: z.ZodEnum<{
|
|
91
|
+
error: "error";
|
|
92
|
+
warning: "warning";
|
|
93
|
+
info: "info";
|
|
94
|
+
}>;
|
|
95
|
+
element_id: z.ZodString;
|
|
96
|
+
message: z.ZodString;
|
|
97
|
+
fix_hint: z.ZodOptional<z.ZodString>;
|
|
98
|
+
context: z.ZodOptional<z.ZodObject<{
|
|
99
|
+
element_type: z.ZodOptional<z.ZodEnum<{
|
|
100
|
+
SYS: "SYS";
|
|
101
|
+
UC: "UC";
|
|
102
|
+
ACTOR: "ACTOR";
|
|
103
|
+
FCHAIN: "FCHAIN";
|
|
104
|
+
FUNC: "FUNC";
|
|
105
|
+
FLOW: "FLOW";
|
|
106
|
+
REQ: "REQ";
|
|
107
|
+
TEST: "TEST";
|
|
108
|
+
MOD: "MOD";
|
|
109
|
+
SCHEMA: "SCHEMA";
|
|
110
|
+
SESSION: "SESSION";
|
|
111
|
+
CR: "CR";
|
|
112
|
+
MS: "MS";
|
|
113
|
+
}>>;
|
|
114
|
+
element_name: z.ZodOptional<z.ZodString>;
|
|
115
|
+
candidate_targets: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
116
|
+
id: z.ZodString;
|
|
117
|
+
type: z.ZodEnum<{
|
|
118
|
+
SYS: "SYS";
|
|
119
|
+
UC: "UC";
|
|
120
|
+
ACTOR: "ACTOR";
|
|
121
|
+
FCHAIN: "FCHAIN";
|
|
122
|
+
FUNC: "FUNC";
|
|
123
|
+
FLOW: "FLOW";
|
|
124
|
+
REQ: "REQ";
|
|
125
|
+
TEST: "TEST";
|
|
126
|
+
MOD: "MOD";
|
|
127
|
+
SCHEMA: "SCHEMA";
|
|
128
|
+
SESSION: "SESSION";
|
|
129
|
+
CR: "CR";
|
|
130
|
+
MS: "MS";
|
|
131
|
+
}>;
|
|
132
|
+
name: z.ZodString;
|
|
133
|
+
}, z.core.$strip>>>;
|
|
134
|
+
existing_traces: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
135
|
+
target: z.ZodString;
|
|
136
|
+
type: z.ZodEnum<{
|
|
137
|
+
compose: "compose";
|
|
138
|
+
io: "io";
|
|
139
|
+
satisfy: "satisfy";
|
|
140
|
+
verify: "verify";
|
|
141
|
+
allocate: "allocate";
|
|
142
|
+
relation: "relation";
|
|
143
|
+
produces: "produces";
|
|
144
|
+
}>;
|
|
145
|
+
}, z.core.$strip>>>;
|
|
146
|
+
parent_module: z.ZodOptional<z.ZodString>;
|
|
147
|
+
current_description: z.ZodOptional<z.ZodString>;
|
|
148
|
+
}, z.core.$strip>>;
|
|
149
|
+
}, z.core.$strip>;
|
|
150
|
+
export type RuleViolation = z.infer<typeof RuleViolation>;
|
|
151
|
+
export interface RuleDefinition {
|
|
152
|
+
id: string;
|
|
153
|
+
name: string;
|
|
154
|
+
severity: 'error' | 'warning' | 'info';
|
|
155
|
+
evaluate: (graph: OntologyGraph) => RuleViolation[];
|
|
156
|
+
}
|
|
157
|
+
export declare const V3_RULES: RuleDefinition[];
|
|
158
|
+
/** Run all rules against a graph */
|
|
159
|
+
export declare function evaluateRules(graph: OntologyGraph): RuleViolation[];
|