@sigloch/contracts 0.7.0 → 0.8.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/se/conformance-rules.d.ts +2 -2
- package/dist/se/conformance-rules.js +34 -31
- package/dist/se/index.d.ts +2 -2
- package/dist/se/index.js +2 -2
- package/dist/se/meta-model.js +1 -1
- package/dist/se/ontology.d.ts +17 -30
- package/dist/se/ontology.js +25 -33
- package/dist/se/readiness.js +1 -1
- package/dist/se/rules.js +45 -20
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* RC conformance rules (CR-GC-253) — graph↔code resolution, the RESOLUTION
|
|
3
|
-
* twins of the presence rules R-20 (
|
|
3
|
+
* twins of the presence rules R-20 (FUNC realRef) / R-19 (testRef).
|
|
4
4
|
*
|
|
5
5
|
* Rules stay in THIS library (one rule base per onto set — no rule definitions
|
|
6
6
|
* in executor codebases). They are pure functions over (graph, facts): all
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* from the repo), so this module stays I/O-free and browser-bundlable.
|
|
9
9
|
*
|
|
10
10
|
* CodeFacts semantics: `files` is keyed by repo-relative path and MUST contain
|
|
11
|
-
* an entry for every file referenced by a
|
|
11
|
+
* an entry for every file referenced by a realRef/testRef the extractor saw.
|
|
12
12
|
* A MISSING key is treated like `exists:false` — an extractor gap must surface
|
|
13
13
|
* loudly as a violation, never as a silent pass.
|
|
14
14
|
*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* RC conformance rules (CR-GC-253) — graph↔code resolution, the RESOLUTION
|
|
3
|
-
* twins of the presence rules R-20 (
|
|
3
|
+
* twins of the presence rules R-20 (FUNC realRef) / R-19 (testRef).
|
|
4
4
|
*
|
|
5
5
|
* Rules stay in THIS library (one rule base per onto set — no rule definitions
|
|
6
6
|
* in executor codebases). They are pure functions over (graph, facts): all
|
|
@@ -8,14 +8,14 @@
|
|
|
8
8
|
* from the repo), so this module stays I/O-free and browser-bundlable.
|
|
9
9
|
*
|
|
10
10
|
* CodeFacts semantics: `files` is keyed by repo-relative path and MUST contain
|
|
11
|
-
* an entry for every file referenced by a
|
|
11
|
+
* an entry for every file referenced by a realRef/testRef the extractor saw.
|
|
12
12
|
* A MISSING key is treated like `exists:false` — an extractor gap must surface
|
|
13
13
|
* loudly as a violation, never as a silent pass.
|
|
14
14
|
*
|
|
15
15
|
* @sigloch/contracts/se — single source of truth for SE validation rules.
|
|
16
16
|
*/
|
|
17
17
|
import { z } from 'zod/v4';
|
|
18
|
-
import {
|
|
18
|
+
import { RealRefSchema, TestRefSchema } from './ontology.js';
|
|
19
19
|
/** Parser facts about one source file (extracted by the executor). */
|
|
20
20
|
export const FileFactsSchema = z.object({
|
|
21
21
|
/** File exists on disk (repo-relative path). */
|
|
@@ -50,10 +50,11 @@ export const CodeFactsSchema = z.object({
|
|
|
50
50
|
importEdges: z.array(ImportEdgeSchema).optional(),
|
|
51
51
|
});
|
|
52
52
|
const missingFile = (facts, file) => facts.files[file]?.exists !== true;
|
|
53
|
-
// RC-01: every valid
|
|
54
|
-
// Presence is R-20's concern (incl. concept/external/decomposition-parent
|
|
53
|
+
// RC-01: every valid FUNC realRef must resolve — file on disk, symbol declared in
|
|
54
|
+
// it. Presence is R-20's concern (incl. concept/external/decomposition-parent
|
|
55
55
|
// exemptions, CR-GC-244); RC-01 only judges bindings that exist. `lang:'prompt'`
|
|
56
|
-
// is realized by a skill file — file-exists is the whole binding.
|
|
56
|
+
// is realized by a skill file — file-exists is the whole binding. A realRef with
|
|
57
|
+
// no `symbol` (CR-228) is also file-only: resolution stops at file-exists.
|
|
57
58
|
function codeRefMustResolve(graph, facts) {
|
|
58
59
|
const violations = [];
|
|
59
60
|
for (const el of graph.elements) {
|
|
@@ -61,7 +62,7 @@ function codeRefMustResolve(graph, facts) {
|
|
|
61
62
|
continue;
|
|
62
63
|
if (el.attributes?.concept === true || el.attributes?.external === true)
|
|
63
64
|
continue;
|
|
64
|
-
const parsed =
|
|
65
|
+
const parsed = RealRefSchema.safeParse(el.attributes?.realRef);
|
|
65
66
|
if (!parsed.success)
|
|
66
67
|
continue; // no/invalid binding → R-20 territory
|
|
67
68
|
const ref = parsed.data;
|
|
@@ -70,20 +71,20 @@ function codeRefMustResolve(graph, facts) {
|
|
|
70
71
|
rule_id: 'RC-01',
|
|
71
72
|
severity: 'error',
|
|
72
73
|
element_id: el.id,
|
|
73
|
-
message: `${el.id}
|
|
74
|
+
message: `${el.id} realRef.file '${ref.file}' does not exist on disk`,
|
|
74
75
|
fix_hint: 'Re-realize the FUNC (graph_realize) against the current source tree, or fix the moved/renamed file path',
|
|
75
76
|
context: { element_type: el.type, element_name: el.name },
|
|
76
77
|
});
|
|
77
78
|
continue;
|
|
78
79
|
}
|
|
79
|
-
if (ref.lang === 'prompt')
|
|
80
|
-
continue; // skill
|
|
80
|
+
if (ref.lang === 'prompt' || ref.symbol === undefined)
|
|
81
|
+
continue; // skill/file-only binding IS the binding
|
|
81
82
|
if (!facts.files[ref.file].declaredSymbols.includes(ref.symbol)) {
|
|
82
83
|
violations.push({
|
|
83
84
|
rule_id: 'RC-01',
|
|
84
85
|
severity: 'error',
|
|
85
86
|
element_id: el.id,
|
|
86
|
-
message: `${el.id}
|
|
87
|
+
message: `${el.id} realRef.symbol '${ref.symbol}' is not declared in '${ref.file}'`,
|
|
87
88
|
fix_hint: 'The symbol was renamed or removed — re-realize the FUNC against the current code',
|
|
88
89
|
context: { element_type: el.type, element_name: el.name },
|
|
89
90
|
});
|
|
@@ -131,11 +132,11 @@ function testRefMustResolve(graph, facts) {
|
|
|
131
132
|
}
|
|
132
133
|
return violations;
|
|
133
134
|
}
|
|
134
|
-
// RC-03: every valid SCHEMA
|
|
135
|
-
// in it (CR-211). Presence (a SCHEMA with NO
|
|
136
|
-
// R-26 presence rule, not RC-03; concept/external SCHEMAs are exempt
|
|
137
|
-
// here. Severity error, like RC-01: a bound-but-broken schema IS a defect.
|
|
138
|
-
//
|
|
135
|
+
// RC-03: every valid SCHEMA realRef must resolve — file on disk, symbol declared
|
|
136
|
+
// in it (CR-211, unified CR-228). Presence (a SCHEMA with NO realRef) is the
|
|
137
|
+
// concern of the R-26 presence rule, not RC-03; concept/external SCHEMAs are exempt
|
|
138
|
+
// there and here. Severity error, like RC-01: a bound-but-broken schema IS a defect.
|
|
139
|
+
// A symbol-less realRef stops at file-exists. Fires 0× until realRefs exist.
|
|
139
140
|
function schemaRefMustResolve(graph, facts) {
|
|
140
141
|
const violations = [];
|
|
141
142
|
for (const el of graph.elements) {
|
|
@@ -143,7 +144,7 @@ function schemaRefMustResolve(graph, facts) {
|
|
|
143
144
|
continue;
|
|
144
145
|
if (el.attributes?.concept === true || el.attributes?.external === true)
|
|
145
146
|
continue;
|
|
146
|
-
const parsed =
|
|
147
|
+
const parsed = RealRefSchema.safeParse(el.attributes?.realRef);
|
|
147
148
|
if (!parsed.success)
|
|
148
149
|
continue; // no/invalid binding → R-26 territory
|
|
149
150
|
const ref = parsed.data;
|
|
@@ -152,18 +153,20 @@ function schemaRefMustResolve(graph, facts) {
|
|
|
152
153
|
rule_id: 'RC-03',
|
|
153
154
|
severity: 'error',
|
|
154
155
|
element_id: el.id,
|
|
155
|
-
message: `${el.id}
|
|
156
|
+
message: `${el.id} realRef.file '${ref.file}' does not exist on disk`,
|
|
156
157
|
fix_hint: 'Re-bind the SCHEMA (graph_realize) to the current source tree, or fix the moved/renamed file path',
|
|
157
158
|
context: { element_type: el.type, element_name: el.name },
|
|
158
159
|
});
|
|
159
160
|
continue;
|
|
160
161
|
}
|
|
162
|
+
if (ref.symbol === undefined)
|
|
163
|
+
continue; // file-only binding
|
|
161
164
|
if (!facts.files[ref.file].declaredSymbols.includes(ref.symbol)) {
|
|
162
165
|
violations.push({
|
|
163
166
|
rule_id: 'RC-03',
|
|
164
167
|
severity: 'error',
|
|
165
168
|
element_id: el.id,
|
|
166
|
-
message: `${el.id}
|
|
169
|
+
message: `${el.id} realRef.symbol '${ref.symbol}' is not a declared export in '${ref.file}'`,
|
|
167
170
|
fix_hint: 'The schema export was renamed or removed — re-bind the SCHEMA against the current code',
|
|
168
171
|
context: { element_type: el.type, element_name: el.name },
|
|
169
172
|
});
|
|
@@ -174,11 +177,11 @@ function schemaRefMustResolve(graph, facts) {
|
|
|
174
177
|
// RC-04: a bound SCHEMA that the graph says is realized at an interface must
|
|
175
178
|
// actually be parsed there (CR-211). The graph gives the check LOCATIONS: FUNCs
|
|
176
179
|
// io-connected to a FLOW whose data format IS this SCHEMA (FUNC ─io→ FLOW
|
|
177
|
-
// ─relation→ SCHEMA) and that carry a resolvable
|
|
178
|
-
// but NONE of their
|
|
180
|
+
// ─relation→ SCHEMA) and that carry a resolvable realRef. If ≥1 such FUNC exists
|
|
181
|
+
// but NONE of their realRef files import AND parse (`.parse`/`.safeParse`) the
|
|
179
182
|
// schema symbol, the modelled validation is missing. Severity warn (the parse may
|
|
180
183
|
// legitimately sit in a framework layer, not the FUNC's own file). Skips when the
|
|
181
|
-
// SCHEMA has no
|
|
184
|
+
// SCHEMA has no realRef (or a symbol-less one), or no io-connected realized FUNC.
|
|
182
185
|
function schemaRefMustBeUsed(graph, facts) {
|
|
183
186
|
const typeOf = new Map(graph.elements.map(e => [e.id, e.type]));
|
|
184
187
|
const violations = [];
|
|
@@ -187,8 +190,8 @@ function schemaRefMustBeUsed(graph, facts) {
|
|
|
187
190
|
continue;
|
|
188
191
|
if (el.attributes?.concept === true || el.attributes?.external === true)
|
|
189
192
|
continue;
|
|
190
|
-
const parsed =
|
|
191
|
-
if (!parsed.success)
|
|
193
|
+
const parsed = RealRefSchema.safeParse(el.attributes?.realRef);
|
|
194
|
+
if (!parsed.success || parsed.data.symbol === undefined)
|
|
192
195
|
continue;
|
|
193
196
|
const ref = parsed.data;
|
|
194
197
|
// The FLOWs whose data format is this SCHEMA (FLOW ─relation→ SCHEMA).
|
|
@@ -203,11 +206,11 @@ function schemaRefMustBeUsed(graph, facts) {
|
|
|
203
206
|
((flowIds.has(t.target) && typeOf.get(t.source) === 'FUNC') ||
|
|
204
207
|
(flowIds.has(t.source) && typeOf.get(t.target) === 'FUNC')))
|
|
205
208
|
.map(t => (flowIds.has(t.target) ? t.source : t.target)));
|
|
206
|
-
// Realized FUNCs among them: a resolvable
|
|
209
|
+
// Realized FUNCs among them: a resolvable realRef whose file exists.
|
|
207
210
|
const realizedFiles = [];
|
|
208
211
|
for (const fnId of funcIds) {
|
|
209
212
|
const fn = graph.elements.find(e => e.id === fnId);
|
|
210
|
-
const cr =
|
|
213
|
+
const cr = RealRefSchema.safeParse(fn?.attributes?.realRef);
|
|
211
214
|
if (cr.success && !missingFile(facts, cr.data.file))
|
|
212
215
|
realizedFiles.push(cr.data.file);
|
|
213
216
|
}
|
|
@@ -255,12 +258,12 @@ function importDriftConformance(graph, facts) {
|
|
|
255
258
|
const modIds = graph.elements.filter(e => e.type === 'MOD').map(e => e.id);
|
|
256
259
|
if (modIds.length === 0)
|
|
257
260
|
return [];
|
|
258
|
-
// 1. file → MOD. Direct
|
|
261
|
+
// 1. file → MOD. Direct realRef bindings first.
|
|
259
262
|
const fileToMod = new Map();
|
|
260
263
|
for (const el of graph.elements) {
|
|
261
264
|
if (el.type !== 'FUNC')
|
|
262
265
|
continue;
|
|
263
|
-
const cr =
|
|
266
|
+
const cr = RealRefSchema.safeParse(el.attributes?.realRef);
|
|
264
267
|
if (!cr.success)
|
|
265
268
|
continue;
|
|
266
269
|
const modTrace = graph.traces.find(t => t.source === el.id && t.type === 'allocate' && typeOf.get(t.target) === 'MOD');
|
|
@@ -352,10 +355,10 @@ function importDriftConformance(graph, facts) {
|
|
|
352
355
|
}
|
|
353
356
|
/** All RC conformance rules — evaluated by executors that can supply CodeFacts. */
|
|
354
357
|
export const CODE_CONFORMANCE_RULES = [
|
|
355
|
-
{ id: 'RC-01', name: '
|
|
358
|
+
{ id: 'RC-01', name: 'FUNC realRef resolves to a declared symbol', severity: 'error', evaluate: codeRefMustResolve },
|
|
356
359
|
{ id: 'RC-02', name: 'testRef resolves to a runnable test', severity: 'error', evaluate: testRefMustResolve },
|
|
357
|
-
{ id: 'RC-03', name: '
|
|
358
|
-
{ id: 'RC-04', name: '
|
|
360
|
+
{ id: 'RC-03', name: 'SCHEMA realRef resolves to a declared export', severity: 'error', evaluate: schemaRefMustResolve },
|
|
361
|
+
{ id: 'RC-04', name: 'SCHEMA realRef is parsed at its interface', severity: 'warning', evaluate: schemaRefMustBeUsed },
|
|
359
362
|
{ id: 'RC-05', name: 'cross-module import drift', severity: 'warning', evaluate: importDriftConformance },
|
|
360
363
|
];
|
|
361
364
|
/** Run all RC rules against a graph + extracted code facts. */
|
package/dist/se/index.d.ts
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* Single source of truth for SE ontology schemas across all projects.
|
|
4
4
|
*/
|
|
5
5
|
/** Ontology schema version (element types + trace types). */
|
|
6
|
-
export declare const ONTOLOGY_VERSION = "3.
|
|
6
|
+
export declare const ONTOLOGY_VERSION = "3.9.0";
|
|
7
7
|
/** Rules engine version (validation rules incl. RC conformance). */
|
|
8
|
-
export declare const RULES_VERSION = "2.
|
|
8
|
+
export declare const RULES_VERSION = "2.18.0";
|
|
9
9
|
/** Meta-model version (trace pattern constraints + format-e parser). */
|
|
10
10
|
export declare const META_MODEL_VERSION = "1.4.0";
|
|
11
11
|
export * from './ontology.js';
|
package/dist/se/index.js
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
* Single source of truth for SE ontology schemas across all projects.
|
|
4
4
|
*/
|
|
5
5
|
/** Ontology schema version (element types + trace types). */
|
|
6
|
-
export const ONTOLOGY_VERSION = '3.
|
|
6
|
+
export const ONTOLOGY_VERSION = '3.9.0'; // realRef unifies codeRef+schemaRef (+physical-MOD CAD ref), symbol optional; testRef stays separate (CR-228 C); +RepoRelativePathSchema on testRef/realRef .file — no absolute/`..` paths (CR-GC-255)
|
|
7
7
|
/** Rules engine version (validation rules incl. RC conformance). */
|
|
8
|
-
export const RULES_VERSION = '2.
|
|
8
|
+
export const RULES_VERSION = '2.18.0'; // R-20/R-26/RC-01/RC-03/RC-04 read realRef (unified codeRef+schemaRef); +R-27 physical-MOD realRef presence (CR-228 C); -R-24/R-25 REQ→MOD allocation rules deleted (CR-228 A: REQ→MOD allocate no longer a valid pattern, R-18 flags residual edges); NFR-01 budget target split physical→MOD / behavioral→FCHAIN; RULE_TO_DIMENSION completeness (R-18..R-23/R-26/MS-03/CR-R04 mapped, no advisory fall-through) (CR-228 B/D); +BQ-01/02/04/06/07 base-quality rules promoted from aimpro (K2-b, completes rule consolidation); +ND-01/02 near-duplicate + AO-D01/D03/CR-01/RT-01/PH-01/CA-01/IO-01 architecture rules promoted from aimpro (K2-b); +CR-R01..04/MS-03 change-request rules promoted from aimpro (K2-b); +FM-01..03/NFR-01 FMEA + VR-01/CL-01 view rules promoted from aimpro (K2-b); +MT-01..03 architecture metrics promoted from aimpro (K2-b); +SC-01..03/UC-01..06/FC-01..03 quality rules promoted from aimpro (K2-a); +RC-05 cross-module import drift (CR-212); +R-26/RC-03/RC-04 schemaRef (CR-211); +R-22..R-25/R-10/R-20 (CR-201/202/208/209/210)
|
|
9
9
|
/** Meta-model version (trace pattern constraints + format-e parser). */
|
|
10
10
|
export const META_MODEL_VERSION = '1.4.0'; // -REQ→MOD allocate pattern removed (CR-228 A); +FUNC→FUNC compose (blackbox function decomposition)
|
|
11
11
|
export * from './ontology.js';
|
package/dist/se/meta-model.js
CHANGED
|
@@ -8,7 +8,7 @@ export const TRACE_PATTERNS = [
|
|
|
8
8
|
{ source: 'UC', target: 'FCHAIN', type: 'compose', cardinality: '1..*', description: 'UC behavioral scenarios' },
|
|
9
9
|
{ source: 'UC', target: 'REQ', type: 'compose', cardinality: '1..*', description: 'UC functional/non-functional requirements' },
|
|
10
10
|
{ source: 'FCHAIN', target: 'FUNC', type: 'compose', cardinality: '1..*', description: 'Functions participating in chain' },
|
|
11
|
-
{ source: 'FUNC', target: 'FUNC', type: 'compose', cardinality: '0..*', description: 'Function (blackbox architecture block) decomposes into sub-functions one level deeper; leaf FUNCs carry
|
|
11
|
+
{ source: 'FUNC', target: 'FUNC', type: 'compose', cardinality: '0..*', description: 'Function (blackbox architecture block) decomposes into sub-functions one level deeper; leaf FUNCs carry realRef, the parent is realized by its children' },
|
|
12
12
|
{ source: 'REQ', target: 'REQ', type: 'compose', cardinality: '0..*', description: 'Requirement decomposes into sub-requirements (incl. mitigation)' },
|
|
13
13
|
// ── io (data exchange, always through FLOW) ──
|
|
14
14
|
{ source: 'ACTOR', target: 'FLOW', type: 'io', description: 'Actor triggers/receives via flow' },
|
package/dist/se/ontology.d.ts
CHANGED
|
@@ -110,40 +110,27 @@ export declare const TestRefSchema: z.ZodObject<{
|
|
|
110
110
|
}, z.core.$strip>;
|
|
111
111
|
export type TestRef = z.infer<typeof TestRefSchema>;
|
|
112
112
|
/**
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
* - `
|
|
120
|
-
* - `
|
|
121
|
-
*
|
|
122
|
-
*
|
|
113
|
+
* Realization binding for an element (CR-228, ontology bump 3.9.0) — unifies the
|
|
114
|
+
* byte-identical former `codeRef` (FUNC → code symbol) and `schemaRef` (SCHEMA →
|
|
115
|
+
* Zod export), and extends to MOD (physical part → CAD/geometry artefact). The
|
|
116
|
+
* *type* of the pointing element disambiguates what kind of realization it is:
|
|
117
|
+
* FUNC→code, SCHEMA→Zod-def, physical MOD→CAD. TEST keeps its own `testRef`
|
|
118
|
+
* (a TEST is not just located but *executed* — the runner is the extra value).
|
|
119
|
+
* - `file` : realization file path, e.g. `src/harness.ts`, `part.step`.
|
|
120
|
+
* - `symbol` : the realizing symbol (function/class/Zod export). Optional — a
|
|
121
|
+
* geometry artefact (CAD) has no symbol; file-exists is the binding.
|
|
122
|
+
* - `lang` : optional language/format id (default `ts`) — selects the
|
|
123
|
+
* conformance engine, so the binding is language-agnostic.
|
|
124
|
+
* Stored under `OntologyElement.attributes.realRef` (additive, opt-in validation).
|
|
125
|
+
* The free-text SCHEMA `contract` attribute stays a human description, not the
|
|
126
|
+
* conformance basis: RC-01/RC-03 resolve this binding, RC-04 checks it is parsed.
|
|
123
127
|
*/
|
|
124
|
-
export declare const
|
|
128
|
+
export declare const RealRefSchema: z.ZodObject<{
|
|
125
129
|
file: z.ZodString;
|
|
126
|
-
symbol: z.ZodString
|
|
130
|
+
symbol: z.ZodOptional<z.ZodString>;
|
|
127
131
|
lang: z.ZodOptional<z.ZodString>;
|
|
128
132
|
}, z.core.$strip>;
|
|
129
|
-
export type
|
|
130
|
-
/**
|
|
131
|
-
* Binding of a SCHEMA node to the Zod schema that defines it (CR-211), analogous
|
|
132
|
-
* to CodeRefSchema for FUNC:
|
|
133
|
-
* - `file` : the source file declaring the Zod schema, e.g. `src/se/ontology.ts`.
|
|
134
|
-
* - `symbol` : the exported schema symbol, e.g. `CodeRefSchema`.
|
|
135
|
-
* - `lang` : optional language id (default `ts`).
|
|
136
|
-
* Stored under `OntologyElement.attributes.schemaRef`. The free-text `contract`
|
|
137
|
-
* attribute stays as a human description but is no longer the conformance basis:
|
|
138
|
-
* RC-03 resolves this binding to a declared export, RC-04 checks it is parsed at
|
|
139
|
-
* the modelled interface.
|
|
140
|
-
*/
|
|
141
|
-
export declare const SchemaRefSchema: z.ZodObject<{
|
|
142
|
-
file: z.ZodString;
|
|
143
|
-
symbol: z.ZodString;
|
|
144
|
-
lang: z.ZodOptional<z.ZodString>;
|
|
145
|
-
}, z.core.$strip>;
|
|
146
|
-
export type SchemaRef = z.infer<typeof SchemaRefSchema>;
|
|
133
|
+
export type RealRef = z.infer<typeof RealRefSchema>;
|
|
147
134
|
/**
|
|
148
135
|
* An element (node) in the SE ontology graph.
|
|
149
136
|
* `attributes` holds type-specific properties (e.g. FUNC.safety_relevant).
|
package/dist/se/ontology.js
CHANGED
|
@@ -72,36 +72,24 @@ export const TestRefSchema = z.object({
|
|
|
72
72
|
level: z.string().optional(),
|
|
73
73
|
});
|
|
74
74
|
/**
|
|
75
|
-
*
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
* - `
|
|
82
|
-
* - `
|
|
83
|
-
*
|
|
84
|
-
*
|
|
75
|
+
* Realization binding for an element (CR-228, ontology bump 3.9.0) — unifies the
|
|
76
|
+
* byte-identical former `codeRef` (FUNC → code symbol) and `schemaRef` (SCHEMA →
|
|
77
|
+
* Zod export), and extends to MOD (physical part → CAD/geometry artefact). The
|
|
78
|
+
* *type* of the pointing element disambiguates what kind of realization it is:
|
|
79
|
+
* FUNC→code, SCHEMA→Zod-def, physical MOD→CAD. TEST keeps its own `testRef`
|
|
80
|
+
* (a TEST is not just located but *executed* — the runner is the extra value).
|
|
81
|
+
* - `file` : realization file path, e.g. `src/harness.ts`, `part.step`.
|
|
82
|
+
* - `symbol` : the realizing symbol (function/class/Zod export). Optional — a
|
|
83
|
+
* geometry artefact (CAD) has no symbol; file-exists is the binding.
|
|
84
|
+
* - `lang` : optional language/format id (default `ts`) — selects the
|
|
85
|
+
* conformance engine, so the binding is language-agnostic.
|
|
86
|
+
* Stored under `OntologyElement.attributes.realRef` (additive, opt-in validation).
|
|
87
|
+
* The free-text SCHEMA `contract` attribute stays a human description, not the
|
|
88
|
+
* conformance basis: RC-01/RC-03 resolve this binding, RC-04 checks it is parsed.
|
|
85
89
|
*/
|
|
86
|
-
export const
|
|
90
|
+
export const RealRefSchema = z.object({
|
|
87
91
|
file: RepoRelativePathSchema,
|
|
88
|
-
symbol: z.string(),
|
|
89
|
-
lang: z.string().optional(),
|
|
90
|
-
});
|
|
91
|
-
/**
|
|
92
|
-
* Binding of a SCHEMA node to the Zod schema that defines it (CR-211), analogous
|
|
93
|
-
* to CodeRefSchema for FUNC:
|
|
94
|
-
* - `file` : the source file declaring the Zod schema, e.g. `src/se/ontology.ts`.
|
|
95
|
-
* - `symbol` : the exported schema symbol, e.g. `CodeRefSchema`.
|
|
96
|
-
* - `lang` : optional language id (default `ts`).
|
|
97
|
-
* Stored under `OntologyElement.attributes.schemaRef`. The free-text `contract`
|
|
98
|
-
* attribute stays as a human description but is no longer the conformance basis:
|
|
99
|
-
* RC-03 resolves this binding to a declared export, RC-04 checks it is parsed at
|
|
100
|
-
* the modelled interface.
|
|
101
|
-
*/
|
|
102
|
-
export const SchemaRefSchema = z.object({
|
|
103
|
-
file: RepoRelativePathSchema,
|
|
104
|
-
symbol: z.string(),
|
|
92
|
+
symbol: z.string().optional(),
|
|
105
93
|
lang: z.string().optional(),
|
|
106
94
|
});
|
|
107
95
|
/**
|
|
@@ -188,8 +176,8 @@ export const ELEMENT_ATTRIBUTES = {
|
|
|
188
176
|
{ key: 'timingBudgetMs', type: 'number', description: 'NFR timing budget in ms' },
|
|
189
177
|
{ key: 'measuredMs', type: 'number', description: 'Measured execution time in ms' },
|
|
190
178
|
{ key: 'sourceFile', type: 'string', description: 'Implementation source file' },
|
|
191
|
-
{ key: '
|
|
192
|
-
{ key: 'external', type: 'boolean', description: 'Externally-realized FUNC (e.g. a renderer in another package): exempt from the R-20
|
|
179
|
+
{ key: 'realRef', type: 'object', description: 'Realization binding {file, symbol?, lang?} — the code symbol that realizes this FUNC; see RealRefSchema (CR-228, was codeRef)' },
|
|
180
|
+
{ key: 'external', type: 'boolean', description: 'Externally-realized FUNC (e.g. a renderer in another package): exempt from the R-20 realRef-binding requirement (CR-GC-205)' },
|
|
193
181
|
{ key: 'concept', type: 'boolean', description: 'Concept-only FUNC: specified, no implementation yet; exempt from R-20 (CR-GC-205)' },
|
|
194
182
|
],
|
|
195
183
|
UC: [
|
|
@@ -206,11 +194,15 @@ export const ELEMENT_ATTRIBUTES = {
|
|
|
206
194
|
],
|
|
207
195
|
MOD: [
|
|
208
196
|
{ key: 'path', type: 'string', description: 'Source file or glob the module owns, e.g. src/harness.ts — anchors the MOD<->file mapping for graph<->code conformance (CR-GC-205)' },
|
|
197
|
+
{ key: 'kind', type: 'string', description: "Module kind, e.g. 'physical' for a machine part (Bauteil) — physical MODs are realized by a CAD/geometry realRef (R-27), logical MODs by their FUNCs' code (CR-191/228)" },
|
|
198
|
+
{ key: 'realRef', type: 'object', description: 'Realization binding {file, symbol?, lang?} — CAD/geometry artefact realizing a physical MOD; see RealRefSchema (CR-228, symbol optional)' },
|
|
199
|
+
{ key: 'external', type: 'boolean', description: 'Externally-realized MOD: exempt from the R-27 realRef-presence requirement (CR-228)' },
|
|
200
|
+
{ key: 'concept', type: 'boolean', description: 'Concept-only MOD: modelled, no realization yet; exempt from R-27 (CR-228)' },
|
|
209
201
|
],
|
|
210
202
|
SCHEMA: [
|
|
211
203
|
{ key: 'contract', type: 'string', description: 'Free-text contract description, e.g. "@sigloch/contracts LiveUpdateEventSchema" — human hint only, not the conformance basis (CR-211)' },
|
|
212
|
-
{ key: '
|
|
213
|
-
{ key: 'external', type: 'boolean', description: 'Externally-defined SCHEMA (e.g. a foreign-API contract): exempt from the
|
|
214
|
-
{ key: 'concept', type: 'boolean', description: 'Concept-only SCHEMA: modelled, no Zod export yet; exempt from the
|
|
204
|
+
{ key: 'realRef', type: 'object', description: 'Realization binding {file, symbol?, lang?} — the Zod export defining this SCHEMA; see RealRefSchema (CR-228, was schemaRef)' },
|
|
205
|
+
{ key: 'external', type: 'boolean', description: 'Externally-defined SCHEMA (e.g. a foreign-API contract): exempt from the realRef-presence requirement (CR-211)' },
|
|
206
|
+
{ key: 'concept', type: 'boolean', description: 'Concept-only SCHEMA: modelled, no Zod export yet; exempt from the realRef-presence requirement (CR-211)' },
|
|
215
207
|
],
|
|
216
208
|
};
|
package/dist/se/readiness.js
CHANGED
|
@@ -39,7 +39,7 @@ export const RULE_TO_DIMENSION = {
|
|
|
39
39
|
'RD-01': 'req', 'RD-02': 'req', 'RD-03': 'req',
|
|
40
40
|
// trace/realization/allocation completeness rules (CR-228 D: previously unmapped → advisory fall-through)
|
|
41
41
|
'R-18': 'arch', 'R-19': 'ver', 'R-20': 'arch', 'R-21': 'ver',
|
|
42
|
-
'R-22': 'alloc', 'R-23': 'alloc', 'R-26': 'schema',
|
|
42
|
+
'R-22': 'alloc', 'R-23': 'alloc', 'R-26': 'schema', 'R-27': 'arch',
|
|
43
43
|
// uc
|
|
44
44
|
'UC-01': 'uc', 'UC-02': 'uc', 'UC-03': 'uc', 'UC-04': 'uc',
|
|
45
45
|
'UC-05': 'uc', 'UC-06': 'uc',
|
package/dist/se/rules.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @sigloch/contracts/se — single source of truth for SE validation rules.
|
|
5
5
|
*/
|
|
6
6
|
import { z } from 'zod/v4';
|
|
7
|
-
import { ElementType, TraceType, TestRefSchema,
|
|
7
|
+
import { ElementType, TraceType, TestRefSchema, RealRefSchema } from './ontology.js';
|
|
8
8
|
import { isValidTrace } from './meta-model.js';
|
|
9
9
|
export const RuleSeverity = z.enum(['error', 'warning', 'info']);
|
|
10
10
|
/** Candidate target for resolving a violation (e.g. a REQ to satisfy, a TEST to link). */
|
|
@@ -581,10 +581,10 @@ function testMustHaveRunnableBinding(graph) {
|
|
|
581
581
|
}));
|
|
582
582
|
}
|
|
583
583
|
// ---------------------------------------------------------------------------
|
|
584
|
-
// R-20: FUNC
|
|
585
|
-
// is not explicitly concept-only (attributes.concept === true) or
|
|
586
|
-
// realized (attributes.external === true) counts as BOUND when it EITHER
|
|
587
|
-
// a valid
|
|
584
|
+
// R-20: FUNC realRef binding (CR-GC-205 Item 5, extended by CR-210, unified CR-228)
|
|
585
|
+
// — a FUNC that is not explicitly concept-only (attributes.concept === true) or
|
|
586
|
+
// externally realized (attributes.external === true) counts as BOUND when it EITHER
|
|
587
|
+
// carries a valid realRef {file, symbol?} OR is a blackbox parent whose compose→FUNC
|
|
588
588
|
// children are ALL (recursively) bound — the parent is realized by its children
|
|
589
589
|
// (e.g. FUNC-gesture-capture, gve CR-GVE-150). A partially-bound parent fires
|
|
590
590
|
// R-20 naming the still-unbound leaves in the fix_hint, so drift on a child is
|
|
@@ -598,7 +598,7 @@ function funcMustHaveCodeBinding(graph) {
|
|
|
598
598
|
const composeFuncChildren = (id) => graph.traces
|
|
599
599
|
.filter(t => t.source === id && t.type === 'compose' && funcById.has(t.target))
|
|
600
600
|
.map(t => t.target);
|
|
601
|
-
const hasCodeRef = (el) =>
|
|
601
|
+
const hasCodeRef = (el) => RealRefSchema.safeParse(el.attributes?.realRef).success;
|
|
602
602
|
const isExempt = (el) => el.attributes?.concept === true || el.attributes?.external === true;
|
|
603
603
|
// A FUNC is bound iff it is exempt, has a codeRef, or is a parent whose
|
|
604
604
|
// compose→FUNC children are all bound (recursive, cycle-safe).
|
|
@@ -662,8 +662,8 @@ function funcMustHaveCodeBinding(graph) {
|
|
|
662
662
|
rule_id: 'R-20',
|
|
663
663
|
severity: 'warning',
|
|
664
664
|
element_id: fn.id,
|
|
665
|
-
message: `${fn.id} is a FUNC without a valid
|
|
666
|
-
fix_hint: 'Add attributes.
|
|
665
|
+
message: `${fn.id} is a FUNC without a valid realRef binding`,
|
|
666
|
+
fix_hint: 'Add attributes.realRef {file, symbol, lang?}, or set attributes.concept:true (spec-only) / attributes.external:true (realized in another package)',
|
|
667
667
|
context: { element_type: fn.type, element_name: fn.name },
|
|
668
668
|
});
|
|
669
669
|
}
|
|
@@ -800,28 +800,52 @@ function modMustHaveAllocatedFunc(graph) {
|
|
|
800
800
|
// MOD→satisfy→REQ, behavioral NFRs FCHAIN→satisfy→REQ. R-18 now flags any residual
|
|
801
801
|
// REQ→MOD allocate edge as an invalid trace pattern.
|
|
802
802
|
// ---------------------------------------------------------------------------
|
|
803
|
-
// R-26: SCHEMA
|
|
804
|
-
// concept-only or external should carry a valid
|
|
805
|
-
// Zod definition is machine-resolvable (RC-03 then checks it resolves, RC-04
|
|
806
|
-
// it is parsed at the interface). WARNING, not error:
|
|
807
|
-
//
|
|
808
|
-
//
|
|
809
|
-
//
|
|
803
|
+
// R-26: SCHEMA realRef presence (CR-211, unified CR-228) — a SCHEMA that is not
|
|
804
|
+
// explicitly concept-only or external should carry a valid realRef {file, symbol?}
|
|
805
|
+
// so its Zod definition is machine-resolvable (RC-03 then checks it resolves, RC-04
|
|
806
|
+
// that it is parsed at the interface). WARNING, not error: currently-unbound SCHEMAs
|
|
807
|
+
// on the reference model must not turn readiness red before any binding exists — the
|
|
808
|
+
// presence signal mirrors R-20 (FUNC realRef) / R-19 (testRef). Symbol RESOLUTION is
|
|
809
|
+
// out of scope here (pure, no I/O — that is RC-03's job).
|
|
810
810
|
// ---------------------------------------------------------------------------
|
|
811
811
|
function schemaMustHaveSchemaRef(graph) {
|
|
812
812
|
return graph.elements
|
|
813
813
|
.filter(e => e.type === 'SCHEMA')
|
|
814
814
|
.filter(e => e.attributes?.concept !== true && e.attributes?.external !== true)
|
|
815
|
-
.filter(e => !
|
|
815
|
+
.filter(e => !RealRefSchema.safeParse(e.attributes?.realRef).success)
|
|
816
816
|
.map(sc => ({
|
|
817
817
|
rule_id: 'R-26',
|
|
818
818
|
severity: 'warning',
|
|
819
819
|
element_id: sc.id,
|
|
820
|
-
message: `${sc.id} is a SCHEMA without a valid
|
|
821
|
-
fix_hint: 'Add attributes.
|
|
820
|
+
message: `${sc.id} is a SCHEMA without a valid realRef binding`,
|
|
821
|
+
fix_hint: 'Add attributes.realRef {file, symbol, lang?}, or set attributes.concept:true (spec-only) / attributes.external:true (foreign-API contract)',
|
|
822
822
|
context: { element_type: sc.type, element_name: sc.name },
|
|
823
823
|
}));
|
|
824
824
|
}
|
|
825
|
+
// ---------------------------------------------------------------------------
|
|
826
|
+
// R-27: physical MOD realRef presence (CR-228) — the MOD arm of the unified
|
|
827
|
+
// "element must have a realRef" rule (FUNC=R-20, SCHEMA=R-26, physical MOD=R-27).
|
|
828
|
+
// A physical MOD (kind='physical') is a Bauteil realized by a CAD/geometry
|
|
829
|
+
// artefact, not by code (RT-01: FUNCs never allocate directly to it). Logical/SW
|
|
830
|
+
// MODs are realized through their FUNCs' code (R-20) and are NOT in scope here.
|
|
831
|
+
// WARNING (presence signal like R-20/R-26); concept/external MODs are exempt.
|
|
832
|
+
// Symbol is optional on a realRef (a geometry file has none) — presence = a valid
|
|
833
|
+
// realRef with a file. RESOLUTION (file on disk) is a consumer/RC concern.
|
|
834
|
+
// ---------------------------------------------------------------------------
|
|
835
|
+
function physicalModMustHaveRealRef(graph) {
|
|
836
|
+
return graph.elements
|
|
837
|
+
.filter(e => e.type === 'MOD' && e.attributes?.kind === 'physical')
|
|
838
|
+
.filter(e => e.attributes?.concept !== true && e.attributes?.external !== true)
|
|
839
|
+
.filter(e => !RealRefSchema.safeParse(e.attributes?.realRef).success)
|
|
840
|
+
.map(mod => ({
|
|
841
|
+
rule_id: 'R-27',
|
|
842
|
+
severity: 'warning',
|
|
843
|
+
element_id: mod.id,
|
|
844
|
+
message: `${mod.id} is a physical MOD without a valid realRef (CAD/geometry) binding`,
|
|
845
|
+
fix_hint: 'Add attributes.realRef {file, symbol?, lang?} pointing at the CAD/geometry artefact, or set attributes.concept:true / attributes.external:true',
|
|
846
|
+
context: { element_type: mod.type, element_name: mod.name },
|
|
847
|
+
}));
|
|
848
|
+
}
|
|
825
849
|
export const V3_RULES = [
|
|
826
850
|
{ id: 'R-01', name: 'REQ must have verification', severity: 'error', evaluate: reqMustHaveVerification },
|
|
827
851
|
{ id: 'R-02', name: 'FUNC must satisfy REQ', severity: 'warning', evaluate: funcMustSatisfyReq },
|
|
@@ -837,11 +861,12 @@ export const V3_RULES = [
|
|
|
837
861
|
{ id: 'R-12', name: 'No circular dependencies', severity: 'warning', evaluate: noDirectCircular },
|
|
838
862
|
{ id: 'R-18', name: 'Valid trace pattern', severity: 'error', evaluate: validTracePattern },
|
|
839
863
|
{ id: 'R-19', name: 'Runnable TEST binding', severity: 'warning', evaluate: testMustHaveRunnableBinding },
|
|
840
|
-
{ id: 'R-20', name: 'FUNC
|
|
864
|
+
{ id: 'R-20', name: 'FUNC realRef binding', severity: 'warning', evaluate: funcMustHaveCodeBinding },
|
|
841
865
|
{ id: 'R-21', name: 'FUNC↔FUNC connection needs integration test', severity: 'warning', evaluate: fchainMustHaveIntegrationTest },
|
|
842
866
|
{ id: 'R-22', name: 'FUNC must be allocated to MOD', severity: 'warning', evaluate: funcMustBeAllocated },
|
|
843
867
|
{ id: 'R-23', name: 'MOD must have allocated FUNC', severity: 'warning', evaluate: modMustHaveAllocatedFunc },
|
|
844
|
-
{ id: 'R-26', name: 'SCHEMA must have
|
|
868
|
+
{ id: 'R-26', name: 'SCHEMA must have realRef', severity: 'warning', evaluate: schemaMustHaveSchemaRef },
|
|
869
|
+
{ id: 'R-27', name: 'Physical MOD must have realRef', severity: 'warning', evaluate: physicalModMustHaveRealRef },
|
|
845
870
|
{ id: 'RD-01', name: 'Unresolved requirement', severity: 'warning', evaluate: unresolvedRequirement },
|
|
846
871
|
{ id: 'RD-02', name: 'Decomposition consistency', severity: 'warning', evaluate: decompositionConsistency },
|
|
847
872
|
{ id: 'RD-03', name: 'No premature decomposition', severity: 'info', evaluate: noPrematureDecomposition },
|