@principal-ai/subsystems-core 0.49.2 → 0.50.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/types/subsystem-model.d.ts +45 -21
- package/dist/types/subsystem-model.d.ts.map +1 -1
- package/dist/types/subsystem-model.js +1 -2
- package/dist/types/subsystem-model.js.map +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +43 -11
- package/dist/validation.js.map +1 -1
- package/package.json +1 -1
- package/schemas/subsystem-model.schema.json +69 -13
- package/src/types/subsystem-model.test.ts +5 -0
- package/src/types/subsystem-model.ts +47 -21
- package/src/validation.test.ts +65 -5
- package/src/validation.ts +57 -13
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Ontology: construct = what a node is, framework + stereotype = which
|
|
15
15
|
* framework pattern it plays, role = where it sits, process = where it runs,
|
|
16
|
-
* module = which source file/module the export belongs to
|
|
17
|
-
* proposed = not yet in source (design / migration placeholder).
|
|
16
|
+
* module = which source file/module the export belongs to.
|
|
18
17
|
* Package (repo) frames are derived from component `purl` when a graph spans
|
|
19
18
|
* multiple repos — there is no separate `package` field.
|
|
20
19
|
* `symbol` is the code identity; `name` is the display label.
|
|
@@ -265,19 +264,10 @@ export interface SubsystemComponent {
|
|
|
265
264
|
logo?: string;
|
|
266
265
|
purpose?: string;
|
|
267
266
|
role?: SubsystemComponentRole;
|
|
268
|
-
/**
|
|
269
|
-
* Design / migration placeholder — participates in edges and flows but is
|
|
270
|
-
* not a live source declaration yet. Verification skips source checks until
|
|
271
|
-
* promoted (`proposed` cleared, `file` + `symbol` filled). Orthogonal to
|
|
272
|
-
* `construct` (intended shape) and `role` (topology).
|
|
273
|
-
*/
|
|
274
|
-
proposed?: boolean;
|
|
275
267
|
/**
|
|
276
268
|
* The claim was real but its source is gone — deleted or renamed upstream.
|
|
277
|
-
*
|
|
278
|
-
*
|
|
279
|
-
* `proposed`, so a model carrying deprecations is no longer wedged on
|
|
280
|
-
* unfixable `missing_file` findings.
|
|
269
|
+
* Verification skips source checks so a model carrying deprecations is no
|
|
270
|
+
* longer wedged on unfixable `missing_file` findings.
|
|
281
271
|
*
|
|
282
272
|
* This is a transitional marker, not a resting state. A cleanup pass removes
|
|
283
273
|
* the component and repairs the trails that referenced it; the field exists so
|
|
@@ -349,6 +339,35 @@ export interface SubsystemComponentEdge {
|
|
|
349
339
|
to: string;
|
|
350
340
|
mechanism: SubsystemEdgeMechanism;
|
|
351
341
|
}
|
|
342
|
+
/**
|
|
343
|
+
* The construct that contains a seam site. The site is always in the step's
|
|
344
|
+
* own file/repo (`step.file` / `step.purl`), so it carries only the construct
|
|
345
|
+
* identity and its full declaration range.
|
|
346
|
+
*/
|
|
347
|
+
export interface SubsystemSiteConstruct {
|
|
348
|
+
/** Caller construct symbol (e.g. `MaintenanceModelList`, `Registry.start`). */
|
|
349
|
+
symbol: string;
|
|
350
|
+
/** Full declaration range of the construct, not just the seam line. */
|
|
351
|
+
span: SubsystemSourceSpan;
|
|
352
|
+
/** Declaration shape, when known (function, method, class, …). */
|
|
353
|
+
construct?: SubsystemConstruct;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* The construct a seam reaches. Unlike `site`, the target can live in another
|
|
357
|
+
* repo, so it carries its own purl + file. `span` is the target declaration
|
|
358
|
+
* range when it resolves; it can be absent for externals or unresolved targets.
|
|
359
|
+
*/
|
|
360
|
+
export interface SubsystemTargetConstruct {
|
|
361
|
+
/** File-anchored purl of the target repo/file. */
|
|
362
|
+
purl: string;
|
|
363
|
+
file: string;
|
|
364
|
+
/** Callee construct symbol (e.g. `mergeProvenance`, `Store.add`). */
|
|
365
|
+
symbol: string;
|
|
366
|
+
/** Full declaration range of the target, when resolvable. */
|
|
367
|
+
span?: SubsystemSourceSpan;
|
|
368
|
+
/** Declaration shape, when known. */
|
|
369
|
+
construct?: SubsystemConstruct;
|
|
370
|
+
}
|
|
352
371
|
export interface SubsystemTrailStep {
|
|
353
372
|
/** Source component alias. */
|
|
354
373
|
from: string;
|
|
@@ -366,6 +385,19 @@ export interface SubsystemTrailStep {
|
|
|
366
385
|
* unverified and the Trails view has no line to highlight.
|
|
367
386
|
*/
|
|
368
387
|
span?: SubsystemSourceSpan;
|
|
388
|
+
/**
|
|
389
|
+
* The construct containing the seam site, with its full declaration range.
|
|
390
|
+
* Required when `mechanism` is `calls`: the caller frame must be housed by
|
|
391
|
+
* the `from` component. For `uses` and data/event seams it is the via-site
|
|
392
|
+
* evidence and remains optional.
|
|
393
|
+
*/
|
|
394
|
+
site?: SubsystemSiteConstruct;
|
|
395
|
+
/**
|
|
396
|
+
* The construct the seam reaches. Distinct from `to` (a component alias):
|
|
397
|
+
* the target can be a method on a modeled component, or a construct that is
|
|
398
|
+
* not a node at all. Optional; populated from accepted call-site evidence.
|
|
399
|
+
*/
|
|
400
|
+
target?: SubsystemTargetConstruct;
|
|
369
401
|
/**
|
|
370
402
|
* File-anchored purl of the seam site (e.g.
|
|
371
403
|
* `pkg:github/owner/name#path/to/file.ts`), mirroring component `purl`.
|
|
@@ -379,14 +411,6 @@ export interface SubsystemTrailStep {
|
|
|
379
411
|
* mechanism + filename fallback.
|
|
380
412
|
*/
|
|
381
413
|
symbol: string;
|
|
382
|
-
/**
|
|
383
|
-
* Planned seam — the step describes intended behavior through code that is
|
|
384
|
-
* not written yet. Orthogonal to (and redundant with) the endpoints' own
|
|
385
|
-
* `proposed` flags: a step is proposed when it says so OR either endpoint
|
|
386
|
-
* is proposed. Verification skips source checks either way, and viewers
|
|
387
|
-
* tint it exactly like a proposed node.
|
|
388
|
-
*/
|
|
389
|
-
proposed?: boolean;
|
|
390
414
|
/**
|
|
391
415
|
* Free-text note anchored to this step's site line. Optional — informative
|
|
392
416
|
* only, never verified against source; viewers surface it via the codeview's
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subsystem-model.d.ts","sourceRoot":"","sources":["../../src/types/subsystem-model.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"subsystem-model.d.ts","sourceRoot":"","sources":["../../src/types/subsystem-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,8 +14,7 @@
|
|
|
14
14
|
*
|
|
15
15
|
* Ontology: construct = what a node is, framework + stereotype = which
|
|
16
16
|
* framework pattern it plays, role = where it sits, process = where it runs,
|
|
17
|
-
* module = which source file/module the export belongs to
|
|
18
|
-
* proposed = not yet in source (design / migration placeholder).
|
|
17
|
+
* module = which source file/module the export belongs to.
|
|
19
18
|
* Package (repo) frames are derived from component `purl` when a graph spans
|
|
20
19
|
* multiple repos — there is no separate `package` field.
|
|
21
20
|
* `symbol` is the code identity; `name` is the display label.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subsystem-model.js","sourceRoot":"","sources":["../../src/types/subsystem-model.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"subsystem-model.js","sourceRoot":"","sources":["../../src/types/subsystem-model.ts"],"names":[],"mappings":"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"}
|
package/dist/validation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,sBAAsB,EAIvB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,0BAA0B;IACzC,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,sBAAsB,EAIvB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,0BAA0B;IACzC,mFAAmF;IACnF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAgDD;;;GAGG;AACH,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,sBAAsB,GAC1B,0BAA0B,EAAE,CAyI9B"}
|
package/dist/validation.js
CHANGED
|
@@ -14,12 +14,10 @@
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.validateSubsystemModelCrossField = void 0;
|
|
16
16
|
function isUngrounded(c) {
|
|
17
|
-
// Deprecated components are exempt
|
|
18
|
-
//
|
|
19
|
-
//
|
|
20
|
-
return
|
|
21
|
-
c.proposed === true ||
|
|
22
|
-
c.deprecated === true);
|
|
17
|
+
// Deprecated components are exempt: the file is a historical pointer to
|
|
18
|
+
// source that is gone, so it cannot resolve and its absence is not an
|
|
19
|
+
// inconsistency.
|
|
20
|
+
return c.construct === 'external' || c.deprecated === true;
|
|
23
21
|
}
|
|
24
22
|
/**
|
|
25
23
|
* `file` is a path *inside the repo named by `purl`* — it resolves against that
|
|
@@ -30,8 +28,7 @@ function isUngrounded(c) {
|
|
|
30
28
|
* Such a component is a third-party dependency: model it as `construct:
|
|
31
29
|
* 'external'` with `purl: 'pkg:npm/<package>'` and no file. Applies to externals
|
|
32
30
|
* too — they carry no file by design, so an install path there is dead weight
|
|
33
|
-
* that draws a link nothing can open.
|
|
34
|
-
* grounding rule: its file is a placeholder for something not placed yet.
|
|
31
|
+
* that draws a link nothing can open.
|
|
35
32
|
*
|
|
36
33
|
* The same rule covers trail step files — a seam into an external belongs
|
|
37
34
|
* at the call site in the caller, which *is* in the repo.
|
|
@@ -78,17 +75,16 @@ function validateSubsystemModelCrossField(doc) {
|
|
|
78
75
|
ids.add(c.alias);
|
|
79
76
|
}
|
|
80
77
|
// A grounded component that claims a `module` needs a `file` to ground the
|
|
81
|
-
// frame. Externals
|
|
78
|
+
// frame. Externals carry no file by design.
|
|
82
79
|
const module = typeof c.module === 'string' ? c.module.trim() : '';
|
|
83
80
|
const file = typeof c.file === 'string' ? c.file.trim() : '';
|
|
84
81
|
if (module && !file && !isUngrounded(c)) {
|
|
85
82
|
problems.push({
|
|
86
83
|
path: `/components/${i}/module`,
|
|
87
|
-
message: `component ${JSON.stringify(c.alias)}: module ${JSON.stringify(module)} is set but file is empty — a module frame needs a file to ground it
|
|
84
|
+
message: `component ${JSON.stringify(c.alias)}: module ${JSON.stringify(module)} is set but file is empty — a module frame needs a file to ground it.`,
|
|
88
85
|
});
|
|
89
86
|
}
|
|
90
87
|
if (file &&
|
|
91
|
-
c.proposed !== true &&
|
|
92
88
|
c.deprecated !== true &&
|
|
93
89
|
mentionsNodeModules(file)) {
|
|
94
90
|
problems.push({
|
|
@@ -135,6 +131,42 @@ function validateSubsystemModelCrossField(doc) {
|
|
|
135
131
|
const spanProblem = spanRangeProblem(step.span, `/trails/${ti}/steps/${si}/span`, `trail ${JSON.stringify(w.id)}: step ${si}`);
|
|
136
132
|
if (spanProblem)
|
|
137
133
|
problems.push(spanProblem);
|
|
134
|
+
// The site construct is the enclosing frame; the seam line must live
|
|
135
|
+
// inside it. The schema can enforce each range but not containment.
|
|
136
|
+
const siteSpanProblem = spanRangeProblem(step.site?.span, `/trails/${ti}/steps/${si}/site/span`, `trail ${JSON.stringify(w.id)}: step ${si} site`);
|
|
137
|
+
if (siteSpanProblem)
|
|
138
|
+
problems.push(siteSpanProblem);
|
|
139
|
+
if (step.span &&
|
|
140
|
+
step.site?.span &&
|
|
141
|
+
!(step.site.span.startLine <= step.span.startLine &&
|
|
142
|
+
step.span.endLine <= step.site.span.endLine)) {
|
|
143
|
+
problems.push({
|
|
144
|
+
path: `/trails/${ti}/steps/${si}/site/span`,
|
|
145
|
+
message: `trail ${JSON.stringify(w.id)}: step ${si} site span ${step.site.span.startLine}-${step.site.span.endLine} does not contain the seam span ${step.span.startLine}-${step.span.endLine}.`,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
// The target is a construct in its own file, so its span and purl
|
|
149
|
+
// fragment are checked independently of the step's site file.
|
|
150
|
+
const targetSpanProblem = spanRangeProblem(step.target?.span, `/trails/${ti}/steps/${si}/target/span`, `trail ${JSON.stringify(w.id)}: step ${si} target`);
|
|
151
|
+
if (targetSpanProblem)
|
|
152
|
+
problems.push(targetSpanProblem);
|
|
153
|
+
if (step.target &&
|
|
154
|
+
typeof step.target.purl === 'string' &&
|
|
155
|
+
step.target.purl.includes('#')) {
|
|
156
|
+
const fragment = step.target.purl.split('#').slice(1).join('#');
|
|
157
|
+
if (fragment !== step.target.file) {
|
|
158
|
+
problems.push({
|
|
159
|
+
path: `/trails/${ti}/steps/${si}/target/purl`,
|
|
160
|
+
message: `trail ${JSON.stringify(w.id)}: step ${si} target purl fragment ${JSON.stringify(fragment)} does not match target file ${JSON.stringify(step.target.file)}`,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (step.target && mentionsNodeModules(step.target.file)) {
|
|
165
|
+
problems.push({
|
|
166
|
+
path: `/trails/${ti}/steps/${si}/target/file`,
|
|
167
|
+
message: `trail ${JSON.stringify(w.id)}: step ${si} target file ${JSON.stringify(step.target.file)} points into node_modules — model the dependency as an external instead.`,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
138
170
|
});
|
|
139
171
|
});
|
|
140
172
|
return problems;
|
package/dist/validation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAeH,SAAS,YAAY,CAAC,CAAqB;IACzC,
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -76,13 +76,9 @@
|
|
|
76
76
|
"service"
|
|
77
77
|
]
|
|
78
78
|
},
|
|
79
|
-
"proposed": {
|
|
80
|
-
"type": "boolean",
|
|
81
|
-
"description": "Design / migration placeholder — not a live source declaration yet. Verification skips source checks until promoted. Keep a real construct for the intended shape."
|
|
82
|
-
},
|
|
83
79
|
"deprecated": {
|
|
84
80
|
"type": "boolean",
|
|
85
|
-
"description": "The claim was real but its source is gone upstream — deleted or renamed.
|
|
81
|
+
"description": "The claim was real but its source is gone upstream — deleted or renamed. Verification skips source checks, so the component stops blocking verification. Transitional: a cleanup pass removes it and repairs the trails that referenced it."
|
|
86
82
|
},
|
|
87
83
|
"removedIn": {
|
|
88
84
|
"type": "object",
|
|
@@ -189,9 +185,6 @@
|
|
|
189
185
|
"role": {
|
|
190
186
|
"$ref": "#/$defs/role"
|
|
191
187
|
},
|
|
192
|
-
"proposed": {
|
|
193
|
-
"$ref": "#/$defs/proposed"
|
|
194
|
-
},
|
|
195
188
|
"deprecated": {
|
|
196
189
|
"$ref": "#/$defs/deprecated"
|
|
197
190
|
},
|
|
@@ -272,6 +265,59 @@
|
|
|
272
265
|
"$ref": "#/$defs/sourceSpan",
|
|
273
266
|
"description": "The seam's source span — the call-site range and its content hash. The trail-step counterpart of a component's declarationSpan; captured by verify tooling. `file` + `symbol` locate the frame."
|
|
274
267
|
},
|
|
268
|
+
"site": {
|
|
269
|
+
"type": "object",
|
|
270
|
+
"description": "The construct containing the seam site, with its full declaration range. Required for `calls`: the caller frame must be housed by the `from` component. For `uses` and data/event seams it is the via-site evidence and is optional. Same file/repo as the step.",
|
|
271
|
+
"additionalProperties": false,
|
|
272
|
+
"required": ["symbol", "span"],
|
|
273
|
+
"properties": {
|
|
274
|
+
"symbol": {
|
|
275
|
+
"type": "string",
|
|
276
|
+
"minLength": 1,
|
|
277
|
+
"description": "Caller/via construct symbol (e.g. `MaintenanceModelList`, `Registry.start`)."
|
|
278
|
+
},
|
|
279
|
+
"span": {
|
|
280
|
+
"$ref": "#/$defs/sourceSpan",
|
|
281
|
+
"description": "Full declaration range of the site construct, not just the seam line."
|
|
282
|
+
},
|
|
283
|
+
"construct": {
|
|
284
|
+
"$ref": "#/$defs/construct",
|
|
285
|
+
"description": "Declaration shape of the site construct, when known."
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
"target": {
|
|
290
|
+
"type": "object",
|
|
291
|
+
"description": "The construct the seam reaches. Distinct from `to` (a component alias): the target can be a method on a modeled component, or a construct that is not a node at all.",
|
|
292
|
+
"additionalProperties": false,
|
|
293
|
+
"required": ["purl", "file", "symbol"],
|
|
294
|
+
"properties": {
|
|
295
|
+
"purl": {
|
|
296
|
+
"type": "string",
|
|
297
|
+
"minLength": 1,
|
|
298
|
+
"description": "File-anchored purl of the target repo/file."
|
|
299
|
+
},
|
|
300
|
+
"file": {
|
|
301
|
+
"type": "string",
|
|
302
|
+
"minLength": 1,
|
|
303
|
+
"pattern": "^(?!.*(^|/)node_modules(/|$)).*$",
|
|
304
|
+
"description": "Repo-root-relative target file."
|
|
305
|
+
},
|
|
306
|
+
"symbol": {
|
|
307
|
+
"type": "string",
|
|
308
|
+
"minLength": 1,
|
|
309
|
+
"description": "Callee construct symbol (e.g. `mergeProvenance`, `Store.add`)."
|
|
310
|
+
},
|
|
311
|
+
"span": {
|
|
312
|
+
"$ref": "#/$defs/sourceSpan",
|
|
313
|
+
"description": "Full declaration range of the target construct, when resolvable."
|
|
314
|
+
},
|
|
315
|
+
"construct": {
|
|
316
|
+
"$ref": "#/$defs/construct",
|
|
317
|
+
"description": "Declaration shape of the target, when known."
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
},
|
|
275
321
|
"purl": {
|
|
276
322
|
"type": "string",
|
|
277
323
|
"minLength": 1,
|
|
@@ -282,16 +328,26 @@
|
|
|
282
328
|
"minLength": 1,
|
|
283
329
|
"description": "Frame name for this step — the function/method on the stack at the site. Required; the Trails list shows this instead of a bare mechanism + filename fallback."
|
|
284
330
|
},
|
|
285
|
-
"proposed": {
|
|
286
|
-
"type": "boolean",
|
|
287
|
-
"description": "Planned seam — the step describes intended behavior through code that is not written yet. Verification skips source checks; viewers tint it like a proposed node. A step is proposed when it says so OR either endpoint component is proposed."
|
|
288
|
-
},
|
|
289
331
|
"annotation": {
|
|
290
332
|
"type": "string",
|
|
291
333
|
"minLength": 1,
|
|
292
334
|
"description": "Free-text note anchored to this step's site line. Optional, informative only, never verified against source; viewers surface it in the codeview's annotation column."
|
|
293
335
|
}
|
|
294
|
-
}
|
|
336
|
+
},
|
|
337
|
+
"allOf": [
|
|
338
|
+
{
|
|
339
|
+
"description": "A calls step claims the site is the caller frame, so it must carry the enclosing site construct. Other mechanisms may use site as evidence but are not required to.",
|
|
340
|
+
"if": {
|
|
341
|
+
"required": ["mechanism"],
|
|
342
|
+
"properties": {
|
|
343
|
+
"mechanism": { "const": "calls" }
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
"then": {
|
|
347
|
+
"required": ["site"]
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
]
|
|
295
351
|
},
|
|
296
352
|
"trail": {
|
|
297
353
|
"type": "object",
|
|
@@ -60,6 +60,11 @@ describe("subsystem-model schema", () => {
|
|
|
60
60
|
expect(schema.$defs.trailStep?.properties?.line).toBeUndefined();
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
+
test("trail steps can carry verifiable site and target constructs", () => {
|
|
64
|
+
expect(schema.$defs.trailStep?.properties?.site).toBeDefined();
|
|
65
|
+
expect(schema.$defs.trailStep?.properties?.target).toBeDefined();
|
|
66
|
+
});
|
|
67
|
+
|
|
63
68
|
test("a store declares its own value type", () => {
|
|
64
69
|
// `additionalProperties: false` on the store declaration, so the field
|
|
65
70
|
// has to be declared here or every typed store would be rejected.
|
|
@@ -13,8 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Ontology: construct = what a node is, framework + stereotype = which
|
|
15
15
|
* framework pattern it plays, role = where it sits, process = where it runs,
|
|
16
|
-
* module = which source file/module the export belongs to
|
|
17
|
-
* proposed = not yet in source (design / migration placeholder).
|
|
16
|
+
* module = which source file/module the export belongs to.
|
|
18
17
|
* Package (repo) frames are derived from component `purl` when a graph spans
|
|
19
18
|
* multiple repos — there is no separate `package` field.
|
|
20
19
|
* `symbol` is the code identity; `name` is the display label.
|
|
@@ -325,19 +324,10 @@ export interface SubsystemComponent {
|
|
|
325
324
|
logo?: string;
|
|
326
325
|
purpose?: string;
|
|
327
326
|
role?: SubsystemComponentRole;
|
|
328
|
-
/**
|
|
329
|
-
* Design / migration placeholder — participates in edges and flows but is
|
|
330
|
-
* not a live source declaration yet. Verification skips source checks until
|
|
331
|
-
* promoted (`proposed` cleared, `file` + `symbol` filled). Orthogonal to
|
|
332
|
-
* `construct` (intended shape) and `role` (topology).
|
|
333
|
-
*/
|
|
334
|
-
proposed?: boolean;
|
|
335
327
|
/**
|
|
336
328
|
* The claim was real but its source is gone — deleted or renamed upstream.
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
* `proposed`, so a model carrying deprecations is no longer wedged on
|
|
340
|
-
* unfixable `missing_file` findings.
|
|
329
|
+
* Verification skips source checks so a model carrying deprecations is no
|
|
330
|
+
* longer wedged on unfixable `missing_file` findings.
|
|
341
331
|
*
|
|
342
332
|
* This is a transitional marker, not a resting state. A cleanup pass removes
|
|
343
333
|
* the component and repairs the trails that referenced it; the field exists so
|
|
@@ -411,6 +401,37 @@ export interface SubsystemComponentEdge {
|
|
|
411
401
|
mechanism: SubsystemEdgeMechanism;
|
|
412
402
|
}
|
|
413
403
|
|
|
404
|
+
/**
|
|
405
|
+
* The construct that contains a seam site. The site is always in the step's
|
|
406
|
+
* own file/repo (`step.file` / `step.purl`), so it carries only the construct
|
|
407
|
+
* identity and its full declaration range.
|
|
408
|
+
*/
|
|
409
|
+
export interface SubsystemSiteConstruct {
|
|
410
|
+
/** Caller construct symbol (e.g. `MaintenanceModelList`, `Registry.start`). */
|
|
411
|
+
symbol: string;
|
|
412
|
+
/** Full declaration range of the construct, not just the seam line. */
|
|
413
|
+
span: SubsystemSourceSpan;
|
|
414
|
+
/** Declaration shape, when known (function, method, class, …). */
|
|
415
|
+
construct?: SubsystemConstruct;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* The construct a seam reaches. Unlike `site`, the target can live in another
|
|
420
|
+
* repo, so it carries its own purl + file. `span` is the target declaration
|
|
421
|
+
* range when it resolves; it can be absent for externals or unresolved targets.
|
|
422
|
+
*/
|
|
423
|
+
export interface SubsystemTargetConstruct {
|
|
424
|
+
/** File-anchored purl of the target repo/file. */
|
|
425
|
+
purl: string;
|
|
426
|
+
file: string;
|
|
427
|
+
/** Callee construct symbol (e.g. `mergeProvenance`, `Store.add`). */
|
|
428
|
+
symbol: string;
|
|
429
|
+
/** Full declaration range of the target, when resolvable. */
|
|
430
|
+
span?: SubsystemSourceSpan;
|
|
431
|
+
/** Declaration shape, when known. */
|
|
432
|
+
construct?: SubsystemConstruct;
|
|
433
|
+
}
|
|
434
|
+
|
|
414
435
|
export interface SubsystemTrailStep {
|
|
415
436
|
/** Source component alias. */
|
|
416
437
|
from: string;
|
|
@@ -428,6 +449,19 @@ export interface SubsystemTrailStep {
|
|
|
428
449
|
* unverified and the Trails view has no line to highlight.
|
|
429
450
|
*/
|
|
430
451
|
span?: SubsystemSourceSpan;
|
|
452
|
+
/**
|
|
453
|
+
* The construct containing the seam site, with its full declaration range.
|
|
454
|
+
* Required when `mechanism` is `calls`: the caller frame must be housed by
|
|
455
|
+
* the `from` component. For `uses` and data/event seams it is the via-site
|
|
456
|
+
* evidence and remains optional.
|
|
457
|
+
*/
|
|
458
|
+
site?: SubsystemSiteConstruct;
|
|
459
|
+
/**
|
|
460
|
+
* The construct the seam reaches. Distinct from `to` (a component alias):
|
|
461
|
+
* the target can be a method on a modeled component, or a construct that is
|
|
462
|
+
* not a node at all. Optional; populated from accepted call-site evidence.
|
|
463
|
+
*/
|
|
464
|
+
target?: SubsystemTargetConstruct;
|
|
431
465
|
/**
|
|
432
466
|
* File-anchored purl of the seam site (e.g.
|
|
433
467
|
* `pkg:github/owner/name#path/to/file.ts`), mirroring component `purl`.
|
|
@@ -441,14 +475,6 @@ export interface SubsystemTrailStep {
|
|
|
441
475
|
* mechanism + filename fallback.
|
|
442
476
|
*/
|
|
443
477
|
symbol: string;
|
|
444
|
-
/**
|
|
445
|
-
* Planned seam — the step describes intended behavior through code that is
|
|
446
|
-
* not written yet. Orthogonal to (and redundant with) the endpoints' own
|
|
447
|
-
* `proposed` flags: a step is proposed when it says so OR either endpoint
|
|
448
|
-
* is proposed. Verification skips source checks either way, and viewers
|
|
449
|
-
* tint it exactly like a proposed node.
|
|
450
|
-
*/
|
|
451
|
-
proposed?: boolean;
|
|
452
478
|
/**
|
|
453
479
|
* Free-text note anchored to this step's site line. Optional — informative
|
|
454
480
|
* only, never verified against source; viewers surface it via the codeview's
|
package/src/validation.test.ts
CHANGED
|
@@ -81,7 +81,70 @@ describe('validateSubsystemModelCrossField', () => {
|
|
|
81
81
|
expect(problems[0]!.path).toBe('/trails/0/steps/0/purl');
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
test('
|
|
84
|
+
test('flags a site construct that does not contain the seam span', () => {
|
|
85
|
+
const problems = validateSubsystemModelCrossField(
|
|
86
|
+
doc({
|
|
87
|
+
components: [comp('a'), comp('b')],
|
|
88
|
+
trails: [
|
|
89
|
+
{
|
|
90
|
+
id: 'w1',
|
|
91
|
+
title: 'flow',
|
|
92
|
+
steps: [
|
|
93
|
+
{
|
|
94
|
+
from: 'a',
|
|
95
|
+
to: 'b',
|
|
96
|
+
mechanism: 'calls',
|
|
97
|
+
file: 'src/a.ts',
|
|
98
|
+
purl: 'pkg:github/acme/app#src/a.ts',
|
|
99
|
+
symbol: 'a',
|
|
100
|
+
span: { startLine: 20, endLine: 20, contentHash: 'h' },
|
|
101
|
+
site: {
|
|
102
|
+
symbol: 'a',
|
|
103
|
+
span: { startLine: 1, endLine: 10, contentHash: 'h' },
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
expect(problems.some((p) => p.path === '/trails/0/steps/0/site/span')).toBe(true);
|
|
112
|
+
expect(problems.find((p) => p.path === '/trails/0/steps/0/site/span')!.message).toContain(
|
|
113
|
+
'does not contain the seam span',
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test('flags a target purl fragment that mismatches the target file', () => {
|
|
118
|
+
const problems = validateSubsystemModelCrossField(
|
|
119
|
+
doc({
|
|
120
|
+
components: [comp('a'), comp('b')],
|
|
121
|
+
trails: [
|
|
122
|
+
{
|
|
123
|
+
id: 'w1',
|
|
124
|
+
title: 'flow',
|
|
125
|
+
steps: [
|
|
126
|
+
{
|
|
127
|
+
from: 'a',
|
|
128
|
+
to: 'b',
|
|
129
|
+
mechanism: 'calls',
|
|
130
|
+
file: 'src/a.ts',
|
|
131
|
+
purl: 'pkg:github/acme/app#src/a.ts',
|
|
132
|
+
symbol: 'a',
|
|
133
|
+
target: {
|
|
134
|
+
purl: 'pkg:github/acme/app#src/b-other.ts',
|
|
135
|
+
file: 'src/b.ts',
|
|
136
|
+
symbol: 'b',
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
}),
|
|
143
|
+
);
|
|
144
|
+
expect(problems.some((p) => p.path === '/trails/0/steps/0/target/purl')).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
test('module implies file, exempting external', () => {
|
|
85
148
|
const bad = validateSubsystemModelCrossField(
|
|
86
149
|
doc({ components: [comp('a', { module: 'src/host', file: '' })] }),
|
|
87
150
|
);
|
|
@@ -93,7 +156,6 @@ describe('validateSubsystemModelCrossField', () => {
|
|
|
93
156
|
doc({
|
|
94
157
|
components: [
|
|
95
158
|
comp('ext', { module: 'pkg:npm/x', construct: 'external', file: '' }),
|
|
96
|
-
comp('plan', { module: 'src/host', file: '', proposed: true }),
|
|
97
159
|
comp('ok', { module: 'src/host', file: 'src/host/main.ts' }),
|
|
98
160
|
],
|
|
99
161
|
}),
|
|
@@ -126,7 +188,7 @@ describe('validateSubsystemModelCrossField', () => {
|
|
|
126
188
|
expect(problems[2]!.path).toBe('/components/2/file');
|
|
127
189
|
});
|
|
128
190
|
|
|
129
|
-
test('accepts
|
|
191
|
+
test('accepts an external identity and a node_modulesx directory', () => {
|
|
130
192
|
expect(
|
|
131
193
|
validateSubsystemModelCrossField(
|
|
132
194
|
doc({
|
|
@@ -137,8 +199,6 @@ describe('validateSubsystemModelCrossField', () => {
|
|
|
137
199
|
file: '',
|
|
138
200
|
purl: 'pkg:npm/@pierre/diffs',
|
|
139
201
|
}),
|
|
140
|
-
// A planned in-repo component may sit where it will live.
|
|
141
|
-
comp('plan', { file: 'packages/x/node_modules/y/z.ts', proposed: true }),
|
|
142
202
|
// `node_modulesx` is an ordinary directory, not the install root.
|
|
143
203
|
comp('ok', { file: 'packages/node_modulesx/z.ts' }),
|
|
144
204
|
],
|
package/src/validation.ts
CHANGED
|
@@ -25,14 +25,10 @@ export interface SubsystemValidationProblem {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
function isUngrounded(c: SubsystemComponent): boolean {
|
|
28
|
-
// Deprecated components are exempt
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
return
|
|
32
|
-
c.construct === 'external' ||
|
|
33
|
-
c.proposed === true ||
|
|
34
|
-
c.deprecated === true
|
|
35
|
-
);
|
|
28
|
+
// Deprecated components are exempt: the file is a historical pointer to
|
|
29
|
+
// source that is gone, so it cannot resolve and its absence is not an
|
|
30
|
+
// inconsistency.
|
|
31
|
+
return c.construct === 'external' || c.deprecated === true;
|
|
36
32
|
}
|
|
37
33
|
|
|
38
34
|
/**
|
|
@@ -44,8 +40,7 @@ function isUngrounded(c: SubsystemComponent): boolean {
|
|
|
44
40
|
* Such a component is a third-party dependency: model it as `construct:
|
|
45
41
|
* 'external'` with `purl: 'pkg:npm/<package>'` and no file. Applies to externals
|
|
46
42
|
* too — they carry no file by design, so an install path there is dead weight
|
|
47
|
-
* that draws a link nothing can open.
|
|
48
|
-
* grounding rule: its file is a placeholder for something not placed yet.
|
|
43
|
+
* that draws a link nothing can open.
|
|
49
44
|
*
|
|
50
45
|
* The same rule covers trail step files — a seam into an external belongs
|
|
51
46
|
* at the call site in the caller, which *is* in the repo.
|
|
@@ -99,18 +94,17 @@ export function validateSubsystemModelCrossField(
|
|
|
99
94
|
ids.add(c.alias);
|
|
100
95
|
}
|
|
101
96
|
// A grounded component that claims a `module` needs a `file` to ground the
|
|
102
|
-
// frame. Externals
|
|
97
|
+
// frame. Externals carry no file by design.
|
|
103
98
|
const module = typeof c.module === 'string' ? c.module.trim() : '';
|
|
104
99
|
const file = typeof c.file === 'string' ? c.file.trim() : '';
|
|
105
100
|
if (module && !file && !isUngrounded(c)) {
|
|
106
101
|
problems.push({
|
|
107
102
|
path: `/components/${i}/module`,
|
|
108
|
-
message: `component ${JSON.stringify(c.alias)}: module ${JSON.stringify(module)} is set but file is empty — a module frame needs a file to ground it
|
|
103
|
+
message: `component ${JSON.stringify(c.alias)}: module ${JSON.stringify(module)} is set but file is empty — a module frame needs a file to ground it.`,
|
|
109
104
|
});
|
|
110
105
|
}
|
|
111
106
|
if (
|
|
112
107
|
file &&
|
|
113
|
-
c.proposed !== true &&
|
|
114
108
|
c.deprecated !== true &&
|
|
115
109
|
mentionsNodeModules(file)
|
|
116
110
|
) {
|
|
@@ -165,6 +159,56 @@ export function validateSubsystemModelCrossField(
|
|
|
165
159
|
`trail ${JSON.stringify(w.id)}: step ${si}`,
|
|
166
160
|
);
|
|
167
161
|
if (spanProblem) problems.push(spanProblem);
|
|
162
|
+
|
|
163
|
+
// The site construct is the enclosing frame; the seam line must live
|
|
164
|
+
// inside it. The schema can enforce each range but not containment.
|
|
165
|
+
const siteSpanProblem = spanRangeProblem(
|
|
166
|
+
step.site?.span,
|
|
167
|
+
`/trails/${ti}/steps/${si}/site/span`,
|
|
168
|
+
`trail ${JSON.stringify(w.id)}: step ${si} site`,
|
|
169
|
+
);
|
|
170
|
+
if (siteSpanProblem) problems.push(siteSpanProblem);
|
|
171
|
+
if (
|
|
172
|
+
step.span &&
|
|
173
|
+
step.site?.span &&
|
|
174
|
+
!(
|
|
175
|
+
step.site.span.startLine <= step.span.startLine &&
|
|
176
|
+
step.span.endLine <= step.site.span.endLine
|
|
177
|
+
)
|
|
178
|
+
) {
|
|
179
|
+
problems.push({
|
|
180
|
+
path: `/trails/${ti}/steps/${si}/site/span`,
|
|
181
|
+
message: `trail ${JSON.stringify(w.id)}: step ${si} site span ${step.site.span.startLine}-${step.site.span.endLine} does not contain the seam span ${step.span.startLine}-${step.span.endLine}.`,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// The target is a construct in its own file, so its span and purl
|
|
186
|
+
// fragment are checked independently of the step's site file.
|
|
187
|
+
const targetSpanProblem = spanRangeProblem(
|
|
188
|
+
step.target?.span,
|
|
189
|
+
`/trails/${ti}/steps/${si}/target/span`,
|
|
190
|
+
`trail ${JSON.stringify(w.id)}: step ${si} target`,
|
|
191
|
+
);
|
|
192
|
+
if (targetSpanProblem) problems.push(targetSpanProblem);
|
|
193
|
+
if (
|
|
194
|
+
step.target &&
|
|
195
|
+
typeof step.target.purl === 'string' &&
|
|
196
|
+
step.target.purl.includes('#')
|
|
197
|
+
) {
|
|
198
|
+
const fragment = step.target.purl.split('#').slice(1).join('#');
|
|
199
|
+
if (fragment !== step.target.file) {
|
|
200
|
+
problems.push({
|
|
201
|
+
path: `/trails/${ti}/steps/${si}/target/purl`,
|
|
202
|
+
message: `trail ${JSON.stringify(w.id)}: step ${si} target purl fragment ${JSON.stringify(fragment)} does not match target file ${JSON.stringify(step.target.file)}`,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (step.target && mentionsNodeModules(step.target.file)) {
|
|
207
|
+
problems.push({
|
|
208
|
+
path: `/trails/${ti}/steps/${si}/target/file`,
|
|
209
|
+
message: `trail ${JSON.stringify(w.id)}: step ${si} target file ${JSON.stringify(step.target.file)} points into node_modules — model the dependency as an external instead.`,
|
|
210
|
+
});
|
|
211
|
+
}
|
|
168
212
|
});
|
|
169
213
|
});
|
|
170
214
|
|