@principal-ai/subsystems-core 0.40.0 → 0.42.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 +22 -29
- package/dist/types/subsystem-model.d.ts.map +1 -1
- package/dist/types/subsystem-model.js +4 -19
- package/dist/types/subsystem-model.js.map +1 -1
- package/dist/validation.d.ts +2 -2
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +2 -17
- package/dist/validation.js.map +1 -1
- package/package.json +1 -1
- package/schemas/subsystem-model.schema.json +11 -60
- package/src/types/subsystem-model.test.ts +7 -2
- package/src/types/subsystem-model.ts +23 -57
- package/src/validation.test.ts +0 -13
- package/src/validation.ts +3 -19
|
@@ -43,21 +43,16 @@ export type SubsystemFramework = string;
|
|
|
43
43
|
* Empty when no framework pattern applies. Pair with `framework` when set.
|
|
44
44
|
*/
|
|
45
45
|
export type SubsystemStereotype = string;
|
|
46
|
-
/**
|
|
47
|
-
* Topology relation type — structural / module / type claims between
|
|
48
|
-
* components. Belongs on `relations[]`, not on walkthrough hops.
|
|
49
|
-
*/
|
|
50
|
-
export type SubsystemRelationType = 'extends' | 'inherits' | 'implements' | 'mixes_in' | 'method';
|
|
51
46
|
/**
|
|
52
47
|
* Walkthrough hop mechanism — runtime seams with a `file:line` site.
|
|
53
48
|
* Belongs on walkthrough steps; graph edges for these are derived.
|
|
54
49
|
*/
|
|
55
50
|
export type SubsystemWalkthroughMechanism = 'calls' | 'uses' | 'feeds' | 'produces' | 'writes' | 'reads' | 'watches' | 'registers-into';
|
|
56
51
|
/**
|
|
57
|
-
*
|
|
58
|
-
* walkthrough
|
|
52
|
+
* Edge mechanism used by derived display edges / styling. Display edges are
|
|
53
|
+
* derived from walkthrough hops, so this is the walkthrough mechanism.
|
|
59
54
|
*/
|
|
60
|
-
export type SubsystemEdgeMechanism =
|
|
55
|
+
export type SubsystemEdgeMechanism = SubsystemWalkthroughMechanism;
|
|
61
56
|
export type SubsystemDeclarationProvenance = 'verified' | 'authored';
|
|
62
57
|
export type SubsystemDeclTokenKind = 'keyword' | 'name' | 'member' | 'type' | 'punctuation' | 'string' | 'newline';
|
|
63
58
|
export interface SubsystemDeclToken {
|
|
@@ -178,6 +173,19 @@ export interface SubsystemStoreDeclaration {
|
|
|
178
173
|
* reads/writes files), or `external` (another system — db/service; carries
|
|
179
174
|
* no `process`). */
|
|
180
175
|
storage?: 'memory' | 'disk' | 'external';
|
|
176
|
+
/**
|
|
177
|
+
* The type of the retained state itself — a store declares its type the way
|
|
178
|
+
* every other declaration does. A state block names its value type
|
|
179
|
+
* (`Map<string, FeedState>`, `Set<Listener>`); a table names its row/record
|
|
180
|
+
* type. Orthogonal to `storage`: an in-memory store still has a value type.
|
|
181
|
+
*
|
|
182
|
+
* Optional because a store with neither a `valueType` nor named `properties`
|
|
183
|
+
* has no declared type — that is a gap the audit can flag, not an error.
|
|
184
|
+
*/
|
|
185
|
+
valueType?: string;
|
|
186
|
+
/** Resolvable target of `valueType` — makes the type navigable like a
|
|
187
|
+
* property's `typeRef`. */
|
|
188
|
+
valueTypeRef?: SubsystemReferenceInfo;
|
|
181
189
|
properties: SubsystemPropertyInfo[];
|
|
182
190
|
}
|
|
183
191
|
/** A single authored attribute on a custom entity — free-form key/value. */
|
|
@@ -199,7 +207,7 @@ export type SubsystemConstructDeclaration = SubsystemClassDeclaration | Subsyste
|
|
|
199
207
|
/** A component node — the named unit, construct-tagged. */
|
|
200
208
|
export interface SubsystemComponent {
|
|
201
209
|
/**
|
|
202
|
-
* Model-local stable alias. Referenced by
|
|
210
|
+
* Model-local stable alias. Referenced by walkthrough `from` /
|
|
203
211
|
* `to`; unique per model. Edges point at the alias, not the location — a
|
|
204
212
|
* file move or symbol rename leaves edges intact. Code identity lives on
|
|
205
213
|
* `purl` + `file` + `symbol` and is what composed (multi-model) views
|
|
@@ -262,27 +270,15 @@ export interface SubsystemComponent {
|
|
|
262
270
|
/** Location anchor (file/line/hash) — distinct from `declaration` (shape). */
|
|
263
271
|
declarationRef?: SubsystemDeclarationRef;
|
|
264
272
|
}
|
|
265
|
-
/** A topology relation between components (structural / module / type). */
|
|
266
|
-
export interface SubsystemRelation {
|
|
267
|
-
id: string;
|
|
268
|
-
/** Source component alias. */
|
|
269
|
-
from: string;
|
|
270
|
-
/** Target component alias (or external label). */
|
|
271
|
-
to: string;
|
|
272
|
-
relationType: SubsystemRelationType;
|
|
273
|
-
/** Concrete file/symbol evidence (often purls). */
|
|
274
|
-
refs?: string[];
|
|
275
|
-
}
|
|
276
273
|
/**
|
|
277
|
-
* Derived / display graph edge used by renderers. Built from
|
|
278
|
-
*
|
|
274
|
+
* Derived / display graph edge used by renderers. Built from walkthrough
|
|
275
|
+
* hops — not authored as its own document field.
|
|
279
276
|
*/
|
|
280
277
|
export interface SubsystemComponentEdge {
|
|
281
278
|
id: string;
|
|
282
279
|
from: string;
|
|
283
280
|
to: string;
|
|
284
281
|
mechanism: SubsystemEdgeMechanism;
|
|
285
|
-
refs?: string[];
|
|
286
282
|
}
|
|
287
283
|
export interface SubsystemWalkthroughStep {
|
|
288
284
|
/** Source component alias. */
|
|
@@ -340,8 +336,6 @@ export interface SubsystemModelDocument {
|
|
|
340
336
|
title: string;
|
|
341
337
|
description?: string;
|
|
342
338
|
components: SubsystemComponent[];
|
|
343
|
-
/** Topology relations (structural / module / type). May be empty. */
|
|
344
|
-
relations: SubsystemRelation[];
|
|
345
339
|
/** Runtime walkthroughs (ordered hops with sites). */
|
|
346
340
|
walkthroughs?: SubsystemWalkthrough[];
|
|
347
341
|
/**
|
|
@@ -382,14 +376,13 @@ export declare function isSubsystemModelDocument(value: unknown): value is Subsy
|
|
|
382
376
|
* share surface that must stay schema-clean.
|
|
383
377
|
*/
|
|
384
378
|
export declare function toPortableDocument(doc: SubsystemModelDocument): SubsystemModelDocument;
|
|
385
|
-
/** Stable id for a derived graph edge from a
|
|
379
|
+
/** Stable id for a derived graph edge from a walkthrough hop. */
|
|
386
380
|
export declare function derivedGraphEdgeId(from: string, to: string, mechanism: SubsystemEdgeMechanism): string;
|
|
387
381
|
/**
|
|
388
|
-
* Build display edges for the graph canvas from
|
|
389
|
-
*
|
|
382
|
+
* Build display edges for the graph canvas from walkthrough hops
|
|
383
|
+
* (deduped by from/to/mechanism).
|
|
390
384
|
*/
|
|
391
385
|
export declare function deriveGraphEdges(doc: {
|
|
392
|
-
relations?: SubsystemRelation[];
|
|
393
386
|
walkthroughs?: SubsystemWalkthrough[];
|
|
394
387
|
}): SubsystemComponentEdge[];
|
|
395
388
|
//# sourceMappingURL=subsystem-model.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subsystem-model.d.ts","sourceRoot":"","sources":["../../src/types/subsystem-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;0CAE0C;AAC1C,MAAM,MAAM,kBAAkB,GAC1B,OAAO,GACP,UAAU,GACV,QAAQ,GACR,WAAW,GACX,YAAY,GACZ,MAAM,GACN,OAAO,GACP,UAAU,GACV,eAAe,CAAC;AAEpB,oEAAoE;AACpE,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,SAAS,CAAC;AAEzD;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAExC;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC;;;GAGG;AACH,MAAM,MAAM,
|
|
1
|
+
{"version":3,"file":"subsystem-model.d.ts","sourceRoot":"","sources":["../../src/types/subsystem-model.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH;;0CAE0C;AAC1C,MAAM,MAAM,kBAAkB,GAC1B,OAAO,GACP,UAAU,GACV,QAAQ,GACR,WAAW,GACX,YAAY,GACZ,MAAM,GACN,OAAO,GACP,UAAU,GACV,eAAe,CAAC;AAEpB,oEAAoE;AACpE,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,SAAS,CAAC;AAEzD;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC;;;;GAIG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAExC;;;;GAIG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAEzC;;;GAGG;AACH,MAAM,MAAM,6BAA6B,GACrC,OAAO,GACP,MAAM,GACN,OAAO,GACP,UAAU,GACV,QAAQ,GACR,OAAO,GACP,SAAS,GACT,gBAAgB,CAAC;AAErB;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,6BAA6B,CAAC;AAEnE,MAAM,MAAM,8BAA8B,GAAG,UAAU,GAAG,UAAU,CAAC;AAErE,MAAM,MAAM,sBAAsB,GAC9B,SAAS,GACT,MAAM,GACN,QAAQ,GACR,MAAM,GACN,aAAa,GACb,QAAQ,GACR,SAAS,CAAC;AAEd,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,sBAAsB,CAAC;IAC7B,0DAA0D;IAC1D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,mEAAmE;AACnE,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,sBAAsB,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,sBAAsB,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,sBAAsB,CAAC;CACxC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,UAAU,EAAE,qBAAqB,EAAE,CAAC;IACpC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,EAAE,iBAAiB,EAAE,CAAC;IACpC,UAAU,EAAE,sBAAsB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,UAAU,CAAC;IACjB,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,QAAQ,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,gFAAgF;AAChF,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,0DAA0D;AAC1D,MAAM,WAAW,yBAAyB;IACxC,UAAU,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAClC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,qBAAqB,EAAE,CAAC;IACpC,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACjC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,wEAAwE;IACxE,QAAQ,CAAC,EAAE,sBAAsB,EAAE,CAAC;IACpC,gDAAgD;IAChD,SAAS,CAAC,EAAE,yBAAyB,CAAC;IACtC,mDAAmD;IACnD,WAAW,CAAC,EAAE,uBAAuB,EAAE,CAAC;IACxC,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,OAAO,CAAC;IACd;;;yBAGqB;IACrB,OAAO,CAAC,EAAE,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IACzC;;;;;;;;OAQG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;gCAC4B;IAC5B,YAAY,CAAC,EAAE,sBAAsB,CAAC;IACtC,UAAU,EAAE,qBAAqB,EAAE,CAAC;CACrC;AAED,4EAA4E;AAC5E,MAAM,WAAW,8BAA8B;IAC7C,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,eAAe,CAAC;IACtB,UAAU,EAAE,8BAA8B,EAAE,CAAC;CAC9C;AAED,mDAAmD;AACnD,MAAM,MAAM,6BAA6B,GACrC,yBAAyB,GACzB,4BAA4B,GAC5B,0BAA0B,GAC1B,wBAAwB,GACxB,4BAA4B,GAC5B,yBAAyB,GACzB,gCAAgC,CAAC;AAErC,2DAA2D;AAC3D,MAAM,WAAW,kBAAkB;IACjC;;;;;;OAMG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,kBAAkB,CAAC;IAC9B,sCAAsC;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,0GAA0G;IAC1G,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,sBAAsB,CAAC;IAC9B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B;;;OAGG;IACH,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,UAAU,CAAC,EAAE,mBAAmB,CAAC;IACjC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,WAAW,CAAC,EAAE,6BAA6B,CAAC;IAC5C,qBAAqB,CAAC,EAAE,8BAA8B,CAAC;IACvD,MAAM,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC9B,8EAA8E;IAC9E,cAAc,CAAC,EAAE,uBAAuB,CAAC;CAC1C;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,sBAAsB,CAAC;CACnC;AAED,MAAM,WAAW,wBAAwB;IACvC,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,8BAA8B;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,kCAAkC;IAClC,SAAS,EAAE,6BAA6B,CAAC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,8DAA8D;AAC9D,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,wBAAwB,EAAE,CAAC;CACnC;AAED;;;;GAIG;AACH;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,kBAAkB,EAAE,CAAC;IACjC,sDAAsD;IACtD,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACtC;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAC9C;;;OAGG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CAChD;AAED;;;;;GAKG;AACH,MAAM,WAAW,sBAAuB,SAAQ,sBAAsB;IACpE,wCAAwC;IACxC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,sBAAsB,CAOxF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,sBAAsB,GAC1B,sBAAsB,CAWxB;AAED,iEAAiE;AACjE,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,sBAAsB,GAChC,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE;IACpC,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;CACvC,GAAG,sBAAsB,EAAE,CAgB3B"}
|
|
@@ -31,9 +31,7 @@ function isSubsystemModelDocument(value) {
|
|
|
31
31
|
if (!value || typeof value !== 'object')
|
|
32
32
|
return false;
|
|
33
33
|
const v = value;
|
|
34
|
-
return
|
|
35
|
-
Array.isArray(v.components) &&
|
|
36
|
-
Array.isArray(v.relations));
|
|
34
|
+
return typeof v.title === 'string' && Array.isArray(v.components);
|
|
37
35
|
}
|
|
38
36
|
exports.isSubsystemModelDocument = isSubsystemModelDocument;
|
|
39
37
|
/**
|
|
@@ -45,7 +43,6 @@ function toPortableDocument(doc) {
|
|
|
45
43
|
const out = {
|
|
46
44
|
title: doc.title,
|
|
47
45
|
components: doc.components,
|
|
48
|
-
relations: doc.relations,
|
|
49
46
|
};
|
|
50
47
|
if (doc.$schema)
|
|
51
48
|
out.$schema = doc.$schema;
|
|
@@ -60,29 +57,17 @@ function toPortableDocument(doc) {
|
|
|
60
57
|
return out;
|
|
61
58
|
}
|
|
62
59
|
exports.toPortableDocument = toPortableDocument;
|
|
63
|
-
/** Stable id for a derived graph edge from a
|
|
60
|
+
/** Stable id for a derived graph edge from a walkthrough hop. */
|
|
64
61
|
function derivedGraphEdgeId(from, to, mechanism) {
|
|
65
62
|
return `${from}--${mechanism}-->${to}`;
|
|
66
63
|
}
|
|
67
64
|
exports.derivedGraphEdgeId = derivedGraphEdgeId;
|
|
68
65
|
/**
|
|
69
|
-
* Build display edges for the graph canvas from
|
|
70
|
-
*
|
|
66
|
+
* Build display edges for the graph canvas from walkthrough hops
|
|
67
|
+
* (deduped by from/to/mechanism).
|
|
71
68
|
*/
|
|
72
69
|
function deriveGraphEdges(doc) {
|
|
73
70
|
const byId = new Map();
|
|
74
|
-
for (const r of doc.relations ?? []) {
|
|
75
|
-
const id = r.id || derivedGraphEdgeId(r.from, r.to, r.relationType);
|
|
76
|
-
if (!byId.has(id)) {
|
|
77
|
-
byId.set(id, {
|
|
78
|
-
id,
|
|
79
|
-
from: r.from,
|
|
80
|
-
to: r.to,
|
|
81
|
-
mechanism: r.relationType,
|
|
82
|
-
refs: r.refs,
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
71
|
for (const w of doc.walkthroughs ?? []) {
|
|
87
72
|
for (const step of w.steps) {
|
|
88
73
|
const id = derivedGraphEdgeId(step.from, step.to, step.mechanism);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subsystem-model.js","sourceRoot":"","sources":["../../src/types/subsystem-model.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;
|
|
1
|
+
{"version":3,"file":"subsystem-model.js","sourceRoot":"","sources":["../../src/types/subsystem-model.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;;AA8ZH;;;;GAIG;AACH,SAAgB,wBAAwB,CAAC,KAAc;IACrD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,CAAC,GAAG,KAGT,CAAC;IACF,OAAO,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;AACpE,CAAC;AAPD,4DAOC;AAED;;;;GAIG;AACH,SAAgB,kBAAkB,CAChC,GAA2B;IAE3B,MAAM,GAAG,GAA2B;QAClC,KAAK,EAAE,GAAG,CAAC,KAAK;QAChB,UAAU,EAAE,GAAG,CAAC,UAAU;KAC3B,CAAC;IACF,IAAI,GAAG,CAAC,OAAO;QAAE,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC;IAC3C,IAAI,GAAG,CAAC,WAAW;QAAE,GAAG,CAAC,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;IACvD,IAAI,GAAG,CAAC,YAAY;QAAE,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;IAC1D,IAAI,GAAG,CAAC,gBAAgB;QAAE,GAAG,CAAC,gBAAgB,GAAG,GAAG,CAAC,gBAAgB,CAAC;IACtE,IAAI,GAAG,CAAC,iBAAiB;QAAE,GAAG,CAAC,iBAAiB,GAAG,GAAG,CAAC,iBAAiB,CAAC;IACzE,OAAO,GAAG,CAAC;AACb,CAAC;AAbD,gDAaC;AAED,iEAAiE;AACjE,SAAgB,kBAAkB,CAChC,IAAY,EACZ,EAAU,EACV,SAAiC;IAEjC,OAAO,GAAG,IAAI,KAAK,SAAS,MAAM,EAAE,EAAE,CAAC;AACzC,CAAC;AAND,gDAMC;AAED;;;GAGG;AACH,SAAgB,gBAAgB,CAAC,GAEhC;IACC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkC,CAAC;IACvD,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,YAAY,IAAI,EAAE,EAAE;QACtC,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,KAAK,EAAE;YAC1B,MAAM,EAAE,GAAG,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YAClE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE;gBACjB,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE;oBACX,EAAE;oBACF,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,EAAE,EAAE,IAAI,CAAC,EAAE;oBACX,SAAS,EAAE,IAAI,CAAC,SAAS;iBAC1B,CAAC,CAAC;aACJ;SACF;KACF;IACD,OAAO,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC5B,CAAC;AAlBD,4CAkBC"}
|
package/dist/validation.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* These are the rules the JSON Schema (`schemas/subsystem-model.schema.json`)
|
|
5
5
|
* cannot express — anything that spans fields or arrays: alias uniqueness,
|
|
6
|
-
* referential integrity between
|
|
6
|
+
* referential integrity between walkthroughs and components, and the
|
|
7
7
|
* `module` implies `file` invariant. Structural checks (types, `required`,
|
|
8
8
|
* enums, ranges, closed objects) belong to the schema and are enforced per
|
|
9
9
|
* surface; this module owns only what the schema can't.
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import type { SubsystemModelDocument } from './types/subsystem-model';
|
|
14
14
|
export interface SubsystemValidationProblem {
|
|
15
|
-
/** JSON-pointer-ish location, e.g. `/components/2` or `/
|
|
15
|
+
/** JSON-pointer-ish location, e.g. `/components/2` or `/walkthroughs/0/steps/0/from`. */
|
|
16
16
|
path: string;
|
|
17
17
|
message: string;
|
|
18
18
|
}
|
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,EAGvB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,0BAA0B;IACzC,
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,yBAAyB,CAAC;AAEjC,MAAM,WAAW,0BAA0B;IACzC,yFAAyF;IACzF,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD;;;GAGG;AACH,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,sBAAsB,GAC1B,0BAA0B,EAAE,CA2D9B"}
|
package/dist/validation.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* These are the rules the JSON Schema (`schemas/subsystem-model.schema.json`)
|
|
6
6
|
* cannot express — anything that spans fields or arrays: alias uniqueness,
|
|
7
|
-
* referential integrity between
|
|
7
|
+
* referential integrity between walkthroughs and components, and the
|
|
8
8
|
* `module` implies `file` invariant. Structural checks (types, `required`,
|
|
9
9
|
* enums, ranges, closed objects) belong to the schema and are enforced per
|
|
10
10
|
* surface; this module owns only what the schema can't.
|
|
@@ -23,10 +23,9 @@ function isUngrounded(c) {
|
|
|
23
23
|
function validateSubsystemModelCrossField(doc) {
|
|
24
24
|
const problems = [];
|
|
25
25
|
const components = doc.components ?? [];
|
|
26
|
-
const relations = doc.relations ?? [];
|
|
27
26
|
const walkthroughs = doc.walkthroughs ?? [];
|
|
28
27
|
// Component aliases must be unique, and the set is the referential target
|
|
29
|
-
// for
|
|
28
|
+
// for walkthrough steps.
|
|
30
29
|
const ids = new Set();
|
|
31
30
|
components.forEach((c, i) => {
|
|
32
31
|
if (ids.has(c.alias)) {
|
|
@@ -49,20 +48,6 @@ function validateSubsystemModelCrossField(doc) {
|
|
|
49
48
|
});
|
|
50
49
|
}
|
|
51
50
|
});
|
|
52
|
-
relations.forEach((r, i) => {
|
|
53
|
-
if (!ids.has(r.from)) {
|
|
54
|
-
problems.push({
|
|
55
|
-
path: `/relations/${i}/from`,
|
|
56
|
-
message: `relation ${JSON.stringify(r.id)}: from ${JSON.stringify(r.from)} does not match any component alias`,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
if (!ids.has(r.to)) {
|
|
60
|
-
problems.push({
|
|
61
|
-
path: `/relations/${i}/to`,
|
|
62
|
-
message: `relation ${JSON.stringify(r.id)}: to ${JSON.stringify(r.to)} does not match any component alias`,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
51
|
walkthroughs.forEach((w, wi) => {
|
|
67
52
|
(w.steps ?? []).forEach((step, si) => {
|
|
68
53
|
if (!ids.has(step.from)) {
|
package/dist/validation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;AAcH,SAAS,YAAY,CAAC,CAAqB;IACzC,OAAO,CAAC,CAAC,SAAS,KAAK,UAAU,IAAI,CAAC,CAAC,QAAQ,KAAK,IAAI,CAAC;AAC3D,CAAC;AAED;;;GAGG;AACH,SAAgB,gCAAgC,CAC9C,GAA2B;IAE3B,MAAM,QAAQ,GAAiC,EAAE,CAAC;IAClD,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,EAAE,CAAC;IACxC,MAAM,
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://principal-ai.dev/schemas/subsystem-model.schema.json",
|
|
4
4
|
"title": "Subsystem Model",
|
|
5
|
-
"description": "Portable subsystem model — the shareable standard. Construct-tagged components (nodes) plus
|
|
5
|
+
"description": "Portable subsystem model — the shareable standard. Construct-tagged components (nodes) plus runtime walkthroughs describing one subsystem of a codebase. Ontology: construct = what a node is, framework + stereotype = which framework pattern it plays, role = where it sits, process = where it runs, module = which source file/module the export belongs to. Symbol is the code identity; name is the display label (often derived from symbol). Host-only fields (local path binding, provenance, store ids, verification) are NOT part of this document; they belong on a hydrated envelope around it.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": [
|
|
8
8
|
"title",
|
|
9
|
-
"components"
|
|
10
|
-
"relations"
|
|
9
|
+
"components"
|
|
11
10
|
],
|
|
12
11
|
"additionalProperties": false,
|
|
13
12
|
"properties": {
|
|
@@ -31,13 +30,6 @@
|
|
|
31
30
|
"$ref": "#/$defs/component"
|
|
32
31
|
}
|
|
33
32
|
},
|
|
34
|
-
"relations": {
|
|
35
|
-
"type": "array",
|
|
36
|
-
"description": "Topology relations (structural / module / type). `from` / `to` reference component `alias`es. Runtime seams belong on walkthrough steps, not here.",
|
|
37
|
-
"items": {
|
|
38
|
-
"$ref": "#/$defs/relation"
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
33
|
"walkthroughs": {
|
|
42
34
|
"type": "array",
|
|
43
35
|
"description": "Ordered runtime walkthroughs (one per named behavior). Each step names from/to/mechanism and the concrete file:line where that seam fires.",
|
|
@@ -106,17 +98,6 @@
|
|
|
106
98
|
"authored"
|
|
107
99
|
]
|
|
108
100
|
},
|
|
109
|
-
"relationType": {
|
|
110
|
-
"type": "string",
|
|
111
|
-
"description": "Topology relation type — structural / module / type claim between components.",
|
|
112
|
-
"enum": [
|
|
113
|
-
"extends",
|
|
114
|
-
"inherits",
|
|
115
|
-
"implements",
|
|
116
|
-
"mixes_in",
|
|
117
|
-
"method"
|
|
118
|
-
]
|
|
119
|
-
},
|
|
120
101
|
"mechanism": {
|
|
121
102
|
"type": "string",
|
|
122
103
|
"description": "Walkthrough hop mechanism — how `from` relates to `to` at a runtime site. `uses` = general dependency; `feeds` = data-flow into a processor; `produces` = emits an output; `writes`/`reads`/`watches` = retained-state interactions.",
|
|
@@ -145,7 +126,7 @@
|
|
|
145
126
|
"alias": {
|
|
146
127
|
"type": "string",
|
|
147
128
|
"minLength": 1,
|
|
148
|
-
"description": "Model-local stable alias, unique per model. Referenced by
|
|
129
|
+
"description": "Model-local stable alias, unique per model. Referenced by walkthrough `from` / `to`; edges point at the alias, not the location, so a file move or symbol rename leaves edges intact. Code identity (for composed multi-model views) lives on `purl` + `file` + `symbol`, not here."
|
|
149
130
|
},
|
|
150
131
|
"name": {
|
|
151
132
|
"type": "string",
|
|
@@ -224,44 +205,6 @@
|
|
|
224
205
|
}
|
|
225
206
|
}
|
|
226
207
|
},
|
|
227
|
-
"relation": {
|
|
228
|
-
"type": "object",
|
|
229
|
-
"required": [
|
|
230
|
-
"id",
|
|
231
|
-
"from",
|
|
232
|
-
"to",
|
|
233
|
-
"relationType"
|
|
234
|
-
],
|
|
235
|
-
"additionalProperties": false,
|
|
236
|
-
"properties": {
|
|
237
|
-
"id": {
|
|
238
|
-
"type": "string",
|
|
239
|
-
"minLength": 1,
|
|
240
|
-
"description": "Stable unique relation id."
|
|
241
|
-
},
|
|
242
|
-
"from": {
|
|
243
|
-
"type": "string",
|
|
244
|
-
"minLength": 1,
|
|
245
|
-
"description": "Source component `alias`."
|
|
246
|
-
},
|
|
247
|
-
"to": {
|
|
248
|
-
"type": "string",
|
|
249
|
-
"minLength": 1,
|
|
250
|
-
"description": "Target component `alias` (or external target label)."
|
|
251
|
-
},
|
|
252
|
-
"relationType": {
|
|
253
|
-
"$ref": "#/$defs/relationType"
|
|
254
|
-
},
|
|
255
|
-
"refs": {
|
|
256
|
-
"type": "array",
|
|
257
|
-
"description": "Concrete file/symbol evidence backing the relation (often purl refs).",
|
|
258
|
-
"items": {
|
|
259
|
-
"type": "string",
|
|
260
|
-
"minLength": 1
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
},
|
|
265
208
|
"walkthroughStep": {
|
|
266
209
|
"type": "object",
|
|
267
210
|
"required": [
|
|
@@ -778,6 +721,14 @@
|
|
|
778
721
|
"type": "string",
|
|
779
722
|
"enum": ["memory", "disk", "external"],
|
|
780
723
|
"description": "Where the retained state physically lives / who mediates access. Authored — graphify cannot infer it: `memory` = process-lifetime RAM, `disk` = this process reads/writes the filesystem, `external` = mediated by another system (db/service)."
|
|
724
|
+
},
|
|
725
|
+
"valueType": {
|
|
726
|
+
"type": "string",
|
|
727
|
+
"description": "The type of the retained state itself, as a declaration declares its type: `Map<string, FeedState>` for a state block, a row/record type for a table. Orthogonal to `storage`. A store with no `properties` and no `valueType` has no declared type."
|
|
728
|
+
},
|
|
729
|
+
"valueTypeRef": {
|
|
730
|
+
"$ref": "#/$defs/referenceInfo",
|
|
731
|
+
"description": "Resolvable target of `valueType` when the graph has an edge for it — makes the store's type navigable like a property `typeRef`."
|
|
781
732
|
}
|
|
782
733
|
}
|
|
783
734
|
},
|
|
@@ -18,7 +18,6 @@ describe("toPortableDocument", () => {
|
|
|
18
18
|
const portable = toPortableDocument({
|
|
19
19
|
title: "t",
|
|
20
20
|
components: [],
|
|
21
|
-
relations: [],
|
|
22
21
|
createdAtCommits: { "pkg:github/a/b": "abc" },
|
|
23
22
|
verifiedAtCommits: { "pkg:github/a/b": "def" },
|
|
24
23
|
} as unknown as Parameters<typeof toPortableDocument>[0]);
|
|
@@ -30,7 +29,6 @@ describe("toPortableDocument", () => {
|
|
|
30
29
|
const portable = toPortableDocument({
|
|
31
30
|
title: "t",
|
|
32
31
|
components: [],
|
|
33
|
-
relations: [],
|
|
34
32
|
id: "sg-1",
|
|
35
33
|
createdAt: "now",
|
|
36
34
|
verification: {},
|
|
@@ -51,4 +49,11 @@ describe("subsystem-model schema", () => {
|
|
|
51
49
|
test("no longer carries per-declaration revision (superseded by the model-level pin)", () => {
|
|
52
50
|
expect(schema.$defs.declarationRef?.properties?.revision).toBeUndefined();
|
|
53
51
|
});
|
|
52
|
+
|
|
53
|
+
test("a store declares its own value type", () => {
|
|
54
|
+
// `additionalProperties: false` on the store declaration, so the field
|
|
55
|
+
// has to be declared here or every typed store would be rejected.
|
|
56
|
+
expect(schema.$defs.storeDeclaration?.properties?.valueType).toBeDefined();
|
|
57
|
+
expect(schema.$defs.storeDeclaration?.properties?.valueTypeRef).toBeDefined();
|
|
58
|
+
});
|
|
54
59
|
});
|
|
@@ -58,17 +58,6 @@ export type SubsystemFramework = string;
|
|
|
58
58
|
*/
|
|
59
59
|
export type SubsystemStereotype = string;
|
|
60
60
|
|
|
61
|
-
/**
|
|
62
|
-
* Topology relation type — structural / module / type claims between
|
|
63
|
-
* components. Belongs on `relations[]`, not on walkthrough hops.
|
|
64
|
-
*/
|
|
65
|
-
export type SubsystemRelationType =
|
|
66
|
-
| 'extends'
|
|
67
|
-
| 'inherits'
|
|
68
|
-
| 'implements'
|
|
69
|
-
| 'mixes_in'
|
|
70
|
-
| 'method';
|
|
71
|
-
|
|
72
61
|
/**
|
|
73
62
|
* Walkthrough hop mechanism — runtime seams with a `file:line` site.
|
|
74
63
|
* Belongs on walkthrough steps; graph edges for these are derived.
|
|
@@ -84,12 +73,10 @@ export type SubsystemWalkthroughMechanism =
|
|
|
84
73
|
| 'registers-into';
|
|
85
74
|
|
|
86
75
|
/**
|
|
87
|
-
*
|
|
88
|
-
* walkthrough
|
|
76
|
+
* Edge mechanism used by derived display edges / styling. Display edges are
|
|
77
|
+
* derived from walkthrough hops, so this is the walkthrough mechanism.
|
|
89
78
|
*/
|
|
90
|
-
export type SubsystemEdgeMechanism =
|
|
91
|
-
| SubsystemRelationType
|
|
92
|
-
| SubsystemWalkthroughMechanism;
|
|
79
|
+
export type SubsystemEdgeMechanism = SubsystemWalkthroughMechanism;
|
|
93
80
|
|
|
94
81
|
export type SubsystemDeclarationProvenance = 'verified' | 'authored';
|
|
95
82
|
|
|
@@ -235,6 +222,19 @@ export interface SubsystemStoreDeclaration {
|
|
|
235
222
|
* reads/writes files), or `external` (another system — db/service; carries
|
|
236
223
|
* no `process`). */
|
|
237
224
|
storage?: 'memory' | 'disk' | 'external';
|
|
225
|
+
/**
|
|
226
|
+
* The type of the retained state itself — a store declares its type the way
|
|
227
|
+
* every other declaration does. A state block names its value type
|
|
228
|
+
* (`Map<string, FeedState>`, `Set<Listener>`); a table names its row/record
|
|
229
|
+
* type. Orthogonal to `storage`: an in-memory store still has a value type.
|
|
230
|
+
*
|
|
231
|
+
* Optional because a store with neither a `valueType` nor named `properties`
|
|
232
|
+
* has no declared type — that is a gap the audit can flag, not an error.
|
|
233
|
+
*/
|
|
234
|
+
valueType?: string;
|
|
235
|
+
/** Resolvable target of `valueType` — makes the type navigable like a
|
|
236
|
+
* property's `typeRef`. */
|
|
237
|
+
valueTypeRef?: SubsystemReferenceInfo;
|
|
238
238
|
properties: SubsystemPropertyInfo[];
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -267,7 +267,7 @@ export type SubsystemConstructDeclaration =
|
|
|
267
267
|
/** A component node — the named unit, construct-tagged. */
|
|
268
268
|
export interface SubsystemComponent {
|
|
269
269
|
/**
|
|
270
|
-
* Model-local stable alias. Referenced by
|
|
270
|
+
* Model-local stable alias. Referenced by walkthrough `from` /
|
|
271
271
|
* `to`; unique per model. Edges point at the alias, not the location — a
|
|
272
272
|
* file move or symbol rename leaves edges intact. Code identity lives on
|
|
273
273
|
* `purl` + `file` + `symbol` and is what composed (multi-model) views
|
|
@@ -331,28 +331,15 @@ export interface SubsystemComponent {
|
|
|
331
331
|
declarationRef?: SubsystemDeclarationRef;
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
-
/** A topology relation between components (structural / module / type). */
|
|
335
|
-
export interface SubsystemRelation {
|
|
336
|
-
id: string;
|
|
337
|
-
/** Source component alias. */
|
|
338
|
-
from: string;
|
|
339
|
-
/** Target component alias (or external label). */
|
|
340
|
-
to: string;
|
|
341
|
-
relationType: SubsystemRelationType;
|
|
342
|
-
/** Concrete file/symbol evidence (often purls). */
|
|
343
|
-
refs?: string[];
|
|
344
|
-
}
|
|
345
|
-
|
|
346
334
|
/**
|
|
347
|
-
* Derived / display graph edge used by renderers. Built from
|
|
348
|
-
*
|
|
335
|
+
* Derived / display graph edge used by renderers. Built from walkthrough
|
|
336
|
+
* hops — not authored as its own document field.
|
|
349
337
|
*/
|
|
350
338
|
export interface SubsystemComponentEdge {
|
|
351
339
|
id: string;
|
|
352
340
|
from: string;
|
|
353
341
|
to: string;
|
|
354
342
|
mechanism: SubsystemEdgeMechanism;
|
|
355
|
-
refs?: string[];
|
|
356
343
|
}
|
|
357
344
|
|
|
358
345
|
export interface SubsystemWalkthroughStep {
|
|
@@ -415,8 +402,6 @@ export interface SubsystemModelDocument {
|
|
|
415
402
|
title: string;
|
|
416
403
|
description?: string;
|
|
417
404
|
components: SubsystemComponent[];
|
|
418
|
-
/** Topology relations (structural / module / type). May be empty. */
|
|
419
|
-
relations: SubsystemRelation[];
|
|
420
405
|
/** Runtime walkthroughs (ordered hops with sites). */
|
|
421
406
|
walkthroughs?: SubsystemWalkthrough[];
|
|
422
407
|
/**
|
|
@@ -457,13 +442,8 @@ export function isSubsystemModelDocument(value: unknown): value is SubsystemMode
|
|
|
457
442
|
const v = value as {
|
|
458
443
|
title?: unknown;
|
|
459
444
|
components?: unknown;
|
|
460
|
-
relations?: unknown;
|
|
461
445
|
};
|
|
462
|
-
return (
|
|
463
|
-
typeof v.title === 'string' &&
|
|
464
|
-
Array.isArray(v.components) &&
|
|
465
|
-
Array.isArray(v.relations)
|
|
466
|
-
);
|
|
446
|
+
return typeof v.title === 'string' && Array.isArray(v.components);
|
|
467
447
|
}
|
|
468
448
|
|
|
469
449
|
/**
|
|
@@ -477,7 +457,6 @@ export function toPortableDocument(
|
|
|
477
457
|
const out: SubsystemModelDocument = {
|
|
478
458
|
title: doc.title,
|
|
479
459
|
components: doc.components,
|
|
480
|
-
relations: doc.relations,
|
|
481
460
|
};
|
|
482
461
|
if (doc.$schema) out.$schema = doc.$schema;
|
|
483
462
|
if (doc.description) out.description = doc.description;
|
|
@@ -487,7 +466,7 @@ export function toPortableDocument(
|
|
|
487
466
|
return out;
|
|
488
467
|
}
|
|
489
468
|
|
|
490
|
-
/** Stable id for a derived graph edge from a
|
|
469
|
+
/** Stable id for a derived graph edge from a walkthrough hop. */
|
|
491
470
|
export function derivedGraphEdgeId(
|
|
492
471
|
from: string,
|
|
493
472
|
to: string,
|
|
@@ -497,26 +476,13 @@ export function derivedGraphEdgeId(
|
|
|
497
476
|
}
|
|
498
477
|
|
|
499
478
|
/**
|
|
500
|
-
* Build display edges for the graph canvas from
|
|
501
|
-
*
|
|
479
|
+
* Build display edges for the graph canvas from walkthrough hops
|
|
480
|
+
* (deduped by from/to/mechanism).
|
|
502
481
|
*/
|
|
503
482
|
export function deriveGraphEdges(doc: {
|
|
504
|
-
relations?: SubsystemRelation[];
|
|
505
483
|
walkthroughs?: SubsystemWalkthrough[];
|
|
506
484
|
}): SubsystemComponentEdge[] {
|
|
507
485
|
const byId = new Map<string, SubsystemComponentEdge>();
|
|
508
|
-
for (const r of doc.relations ?? []) {
|
|
509
|
-
const id = r.id || derivedGraphEdgeId(r.from, r.to, r.relationType);
|
|
510
|
-
if (!byId.has(id)) {
|
|
511
|
-
byId.set(id, {
|
|
512
|
-
id,
|
|
513
|
-
from: r.from,
|
|
514
|
-
to: r.to,
|
|
515
|
-
mechanism: r.relationType,
|
|
516
|
-
refs: r.refs,
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
486
|
for (const w of doc.walkthroughs ?? []) {
|
|
521
487
|
for (const step of w.steps) {
|
|
522
488
|
const id = derivedGraphEdgeId(step.from, step.to, step.mechanism);
|
package/src/validation.test.ts
CHANGED
|
@@ -20,7 +20,6 @@ function doc(partial: Partial<SubsystemModelDocument>): SubsystemModelDocument {
|
|
|
20
20
|
return {
|
|
21
21
|
title: 't',
|
|
22
22
|
components: [],
|
|
23
|
-
relations: [],
|
|
24
23
|
...partial,
|
|
25
24
|
} as SubsystemModelDocument;
|
|
26
25
|
}
|
|
@@ -29,7 +28,6 @@ describe('validateSubsystemModelCrossField', () => {
|
|
|
29
28
|
test('accepts a consistent document', () => {
|
|
30
29
|
const d = doc({
|
|
31
30
|
components: [comp('a'), comp('b')],
|
|
32
|
-
relations: [{ id: 'r1', from: 'a', to: 'b', relationType: 'method' }],
|
|
33
31
|
walkthroughs: [
|
|
34
32
|
{
|
|
35
33
|
id: 'w1',
|
|
@@ -49,17 +47,6 @@ describe('validateSubsystemModelCrossField', () => {
|
|
|
49
47
|
expect(problems[0]!.message).toContain('duplicate alias');
|
|
50
48
|
});
|
|
51
49
|
|
|
52
|
-
test('flags relation endpoints that reference no component', () => {
|
|
53
|
-
const problems = validateSubsystemModelCrossField(
|
|
54
|
-
doc({
|
|
55
|
-
components: [comp('a')],
|
|
56
|
-
relations: [{ id: 'r1', from: 'a', to: 'ghost', relationType: 'method' }],
|
|
57
|
-
}),
|
|
58
|
-
);
|
|
59
|
-
expect(problems).toHaveLength(1);
|
|
60
|
-
expect(problems[0]!.path).toBe('/relations/0/to');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
50
|
test('flags walkthrough step endpoints that reference no component', () => {
|
|
64
51
|
const problems = validateSubsystemModelCrossField(
|
|
65
52
|
doc({
|
package/src/validation.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* These are the rules the JSON Schema (`schemas/subsystem-model.schema.json`)
|
|
5
5
|
* cannot express — anything that spans fields or arrays: alias uniqueness,
|
|
6
|
-
* referential integrity between
|
|
6
|
+
* referential integrity between walkthroughs and components, and the
|
|
7
7
|
* `module` implies `file` invariant. Structural checks (types, `required`,
|
|
8
8
|
* enums, ranges, closed objects) belong to the schema and are enforced per
|
|
9
9
|
* surface; this module owns only what the schema can't.
|
|
@@ -18,7 +18,7 @@ import type {
|
|
|
18
18
|
} from './types/subsystem-model';
|
|
19
19
|
|
|
20
20
|
export interface SubsystemValidationProblem {
|
|
21
|
-
/** JSON-pointer-ish location, e.g. `/components/2` or `/
|
|
21
|
+
/** JSON-pointer-ish location, e.g. `/components/2` or `/walkthroughs/0/steps/0/from`. */
|
|
22
22
|
path: string;
|
|
23
23
|
message: string;
|
|
24
24
|
}
|
|
@@ -36,11 +36,10 @@ export function validateSubsystemModelCrossField(
|
|
|
36
36
|
): SubsystemValidationProblem[] {
|
|
37
37
|
const problems: SubsystemValidationProblem[] = [];
|
|
38
38
|
const components = doc.components ?? [];
|
|
39
|
-
const relations = doc.relations ?? [];
|
|
40
39
|
const walkthroughs = doc.walkthroughs ?? [];
|
|
41
40
|
|
|
42
41
|
// Component aliases must be unique, and the set is the referential target
|
|
43
|
-
// for
|
|
42
|
+
// for walkthrough steps.
|
|
44
43
|
const ids = new Set<string>();
|
|
45
44
|
components.forEach((c, i) => {
|
|
46
45
|
if (ids.has(c.alias)) {
|
|
@@ -63,21 +62,6 @@ export function validateSubsystemModelCrossField(
|
|
|
63
62
|
}
|
|
64
63
|
});
|
|
65
64
|
|
|
66
|
-
relations.forEach((r, i) => {
|
|
67
|
-
if (!ids.has(r.from)) {
|
|
68
|
-
problems.push({
|
|
69
|
-
path: `/relations/${i}/from`,
|
|
70
|
-
message: `relation ${JSON.stringify(r.id)}: from ${JSON.stringify(r.from)} does not match any component alias`,
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
if (!ids.has(r.to)) {
|
|
74
|
-
problems.push({
|
|
75
|
-
path: `/relations/${i}/to`,
|
|
76
|
-
message: `relation ${JSON.stringify(r.id)}: to ${JSON.stringify(r.to)} does not match any component alias`,
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
|
|
81
65
|
walkthroughs.forEach((w: SubsystemWalkthrough, wi) => {
|
|
82
66
|
(w.steps ?? []).forEach((step, si) => {
|
|
83
67
|
if (!ids.has(step.from)) {
|