yarramate 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -4
- package/assets/likec4/specification.likec4 +500 -0
- package/dist/adapters/likec4-cli.js +202 -15
- package/dist/adapters/likec4-export.js +14 -1
- package/dist/adapters/likec4-project.js +16 -2
- package/dist/check-command.js +20 -2
- package/dist/cli-support.d.ts +7 -2
- package/dist/cli-support.js +3 -2
- package/dist/cli.js +30 -10
- package/dist/compiler.js +111 -0
- package/package.json +3 -2
- package/schema/yarramate-check-result.schema.json +15 -0
- package/schema/yarramate-core-contract.schema.json +2 -0
- package/schema/yarramate-document.schema.json +29 -0
- package/schema/yarramate-likec4-diagnostic-result.schema.json +1 -1
- package/schema/yarramate-likec4-project.schema.json +1 -0
- package/skills/yarramate-architecture/references/native-authoring.md +33 -1
package/dist/compiler.js
CHANGED
|
@@ -376,6 +376,11 @@ function compileWorkspaceResolved(sources) {
|
|
|
376
376
|
])));
|
|
377
377
|
const qualifyReference = (documentId, reference) => reference.includes('#') ? reference : `${documentId}#${reference}`;
|
|
378
378
|
const architectureStateIds = new Set(documents.flatMap(({ value }) => (value.states ?? []).map((state) => `${value.id}#${state.id}`)));
|
|
379
|
+
const subjectIds = new Set(documents.flatMap(({ value }) => [
|
|
380
|
+
...(value.states ?? []).map((state) => `${value.id}#${state.id}`),
|
|
381
|
+
...value.concepts.map((concept) => `${value.id}#${concept.id}`),
|
|
382
|
+
...value.relationships.map((relationship) => `${value.id}#${relationship.id}`),
|
|
383
|
+
]));
|
|
379
384
|
const architectureStateAfter = new Map(documents.flatMap(({ value }) => (value.states ?? []).flatMap((state) => state.after === undefined
|
|
380
385
|
? []
|
|
381
386
|
: [
|
|
@@ -582,6 +587,36 @@ function compileWorkspaceResolved(sources) {
|
|
|
582
587
|
});
|
|
583
588
|
}
|
|
584
589
|
}
|
|
590
|
+
const seenReferenceIds = new Set();
|
|
591
|
+
for (const [referenceIndex, reference] of (concept.references ?? []).entries()) {
|
|
592
|
+
if (seenReferenceIds.has(reference.id)) {
|
|
593
|
+
const pointer = `/concepts/${index}/references/${referenceIndex}/id`;
|
|
594
|
+
const source = location(['concepts', index, 'references', referenceIndex, 'id'], pointer);
|
|
595
|
+
diagnostics.push({
|
|
596
|
+
severity: 'error',
|
|
597
|
+
code: 'YM309',
|
|
598
|
+
message: `Duplicate reference ID "${reference.id}"`,
|
|
599
|
+
path: input.path,
|
|
600
|
+
pointer,
|
|
601
|
+
line: source.line,
|
|
602
|
+
column: source.column,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
seenReferenceIds.add(reference.id);
|
|
606
|
+
if (!subjectIds.has(qualifyReference(value.id, reference.ref))) {
|
|
607
|
+
const pointer = `/concepts/${index}/references/${referenceIndex}/ref`;
|
|
608
|
+
const source = location(['concepts', index, 'references', referenceIndex, 'ref'], pointer);
|
|
609
|
+
diagnostics.push({
|
|
610
|
+
severity: 'error',
|
|
611
|
+
code: 'YM308',
|
|
612
|
+
message: `Unresolved subject reference "${reference.ref}"`,
|
|
613
|
+
path: input.path,
|
|
614
|
+
pointer,
|
|
615
|
+
line: source.line,
|
|
616
|
+
column: source.column,
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
}
|
|
585
620
|
for (const [stateIndex, state] of (concept.presentIn ?? []).entries()) {
|
|
586
621
|
if (!architectureStateIds.has(qualifyReference(value.id, state))) {
|
|
587
622
|
const pointer = `/concepts/${index}/presentIn/${stateIndex}`;
|
|
@@ -599,6 +634,48 @@ function compileWorkspaceResolved(sources) {
|
|
|
599
634
|
}
|
|
600
635
|
}
|
|
601
636
|
for (const [index, relationship] of value.relationships.entries()) {
|
|
637
|
+
const seenReferenceIds = new Set();
|
|
638
|
+
for (const [referenceIndex, reference] of (relationship.references ?? []).entries()) {
|
|
639
|
+
if (seenReferenceIds.has(reference.id)) {
|
|
640
|
+
const pointer = `/relationships/${index}/references/${referenceIndex}/id`;
|
|
641
|
+
const source = location([
|
|
642
|
+
'relationships',
|
|
643
|
+
index,
|
|
644
|
+
'references',
|
|
645
|
+
referenceIndex,
|
|
646
|
+
'id',
|
|
647
|
+
], pointer);
|
|
648
|
+
diagnostics.push({
|
|
649
|
+
severity: 'error',
|
|
650
|
+
code: 'YM309',
|
|
651
|
+
message: `Duplicate reference ID "${reference.id}"`,
|
|
652
|
+
path: input.path,
|
|
653
|
+
pointer,
|
|
654
|
+
line: source.line,
|
|
655
|
+
column: source.column,
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
seenReferenceIds.add(reference.id);
|
|
659
|
+
if (!subjectIds.has(qualifyReference(value.id, reference.ref))) {
|
|
660
|
+
const pointer = `/relationships/${index}/references/${referenceIndex}/ref`;
|
|
661
|
+
const source = location([
|
|
662
|
+
'relationships',
|
|
663
|
+
index,
|
|
664
|
+
'references',
|
|
665
|
+
referenceIndex,
|
|
666
|
+
'ref',
|
|
667
|
+
], pointer);
|
|
668
|
+
diagnostics.push({
|
|
669
|
+
severity: 'error',
|
|
670
|
+
code: 'YM308',
|
|
671
|
+
message: `Unresolved subject reference "${reference.ref}"`,
|
|
672
|
+
path: input.path,
|
|
673
|
+
pointer,
|
|
674
|
+
line: source.line,
|
|
675
|
+
column: source.column,
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
}
|
|
602
679
|
for (const [stateIndex, state] of (relationship.presentIn ?? []).entries()) {
|
|
603
680
|
const stateIdentity = qualifyReference(value.id, state);
|
|
604
681
|
if (!architectureStateIds.has(stateIdentity)) {
|
|
@@ -785,6 +862,18 @@ function compileWorkspaceResolved(sources) {
|
|
|
785
862
|
source: location(['concepts', index, 'constraints', constraintIndex, 'ref'], `/concepts/${index}/constraints/${constraintIndex}/ref`),
|
|
786
863
|
});
|
|
787
864
|
}
|
|
865
|
+
for (const [referenceIndex, reference] of (concept.references ?? []).entries()) {
|
|
866
|
+
claims.push({
|
|
867
|
+
id: `${subject}~reference-${reference.id}`,
|
|
868
|
+
subject,
|
|
869
|
+
predicate: 'yarramate/reference/refers-to',
|
|
870
|
+
object: {
|
|
871
|
+
ref: qualifyReference(value.id, reference.ref),
|
|
872
|
+
},
|
|
873
|
+
origin: 'declared',
|
|
874
|
+
source: location(['concepts', index, 'references', referenceIndex, 'ref'], `/concepts/${index}/references/${referenceIndex}/ref`),
|
|
875
|
+
});
|
|
876
|
+
}
|
|
788
877
|
for (const [stateIndex, state] of (concept.presentIn ?? []).entries()) {
|
|
789
878
|
const stateIdentity = qualifyReference(value.id, state);
|
|
790
879
|
claims.push({
|
|
@@ -819,6 +908,16 @@ function compileWorkspaceResolved(sources) {
|
|
|
819
908
|
source: location(['relationships', index, 'name'], `/relationships/${index}/name`),
|
|
820
909
|
});
|
|
821
910
|
}
|
|
911
|
+
if (relationship.description !== undefined) {
|
|
912
|
+
claims.push({
|
|
913
|
+
id: `${id}~description`,
|
|
914
|
+
subject: id,
|
|
915
|
+
predicate: 'yarramate/relationship/description',
|
|
916
|
+
object: { value: relationship.description },
|
|
917
|
+
origin: 'declared',
|
|
918
|
+
source: location(['relationships', index, 'description'], `/relationships/${index}/description`),
|
|
919
|
+
});
|
|
920
|
+
}
|
|
822
921
|
if (relationship.mode !== undefined) {
|
|
823
922
|
claims.push({
|
|
824
923
|
id: `${id}~mode`,
|
|
@@ -849,6 +948,18 @@ function compileWorkspaceResolved(sources) {
|
|
|
849
948
|
source: location(['relationships', index, 'status'], `/relationships/${index}/status`),
|
|
850
949
|
});
|
|
851
950
|
}
|
|
951
|
+
for (const [referenceIndex, reference] of (relationship.references ?? []).entries()) {
|
|
952
|
+
claims.push({
|
|
953
|
+
id: `${id}~reference-${reference.id}`,
|
|
954
|
+
subject: id,
|
|
955
|
+
predicate: 'yarramate/reference/refers-to',
|
|
956
|
+
object: {
|
|
957
|
+
ref: qualifyReference(value.id, reference.ref),
|
|
958
|
+
},
|
|
959
|
+
origin: 'declared',
|
|
960
|
+
source: location(['relationships', index, 'references', referenceIndex, 'ref'], `/relationships/${index}/references/${referenceIndex}/ref`),
|
|
961
|
+
});
|
|
962
|
+
}
|
|
852
963
|
for (const [stateIndex, state] of (relationship.presentIn ?? []).entries()) {
|
|
853
964
|
const stateIdentity = qualifyReference(value.id, state);
|
|
854
965
|
claims.push({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "yarramate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Tool-neutral semantic architecture engine and guided methodology",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
],
|
|
24
24
|
"files": [
|
|
25
25
|
"dist",
|
|
26
|
+
"assets/likec4",
|
|
26
27
|
"schema",
|
|
27
28
|
"skills/yarramate-architecture",
|
|
28
29
|
"docs/CONSUMING-YARRAMATE.md"
|
|
@@ -78,7 +79,7 @@
|
|
|
78
79
|
"build": "tsc -p tsconfig.build.json",
|
|
79
80
|
"prepack": "pnpm build",
|
|
80
81
|
"docs:dev": "pnpm self:export:likec4 && likec4 serve .yarramate-out/likec4",
|
|
81
|
-
"format": "likec4 format
|
|
82
|
+
"format": "likec4 format assets/likec4",
|
|
82
83
|
"self:check": "pnpm build && node dist/cli.js check .yarramate/workspace.yaml",
|
|
83
84
|
"self:check:json": "pnpm build && node dist/cli.js check .yarramate/workspace.yaml --json",
|
|
84
85
|
"self:compile": "pnpm build && node dist/cli.js compile .yarramate/workspace.yaml",
|
|
@@ -17,6 +17,9 @@
|
|
|
17
17
|
"items": {
|
|
18
18
|
"$ref": "#/$defs/diagnostic"
|
|
19
19
|
}
|
|
20
|
+
},
|
|
21
|
+
"counted": {
|
|
22
|
+
"$ref": "#/$defs/counted"
|
|
20
23
|
}
|
|
21
24
|
},
|
|
22
25
|
"allOf": [
|
|
@@ -30,6 +33,7 @@
|
|
|
30
33
|
"required": ["ok"]
|
|
31
34
|
},
|
|
32
35
|
"then": {
|
|
36
|
+
"required": ["counted"],
|
|
33
37
|
"properties": {
|
|
34
38
|
"diagnostics": {
|
|
35
39
|
"maxItems": 0
|
|
@@ -46,6 +50,17 @@
|
|
|
46
50
|
}
|
|
47
51
|
],
|
|
48
52
|
"$defs": {
|
|
53
|
+
"counted": {
|
|
54
|
+
"type": "object",
|
|
55
|
+
"additionalProperties": false,
|
|
56
|
+
"required": ["documents", "concepts", "relationships", "states"],
|
|
57
|
+
"properties": {
|
|
58
|
+
"documents": { "type": "integer", "minimum": 0 },
|
|
59
|
+
"concepts": { "type": "integer", "minimum": 0 },
|
|
60
|
+
"relationships": { "type": "integer", "minimum": 0 },
|
|
61
|
+
"states": { "type": "integer", "minimum": 0 }
|
|
62
|
+
}
|
|
63
|
+
},
|
|
49
64
|
"diagnostic": {
|
|
50
65
|
"type": "object",
|
|
51
66
|
"additionalProperties": false,
|
|
@@ -92,6 +92,7 @@
|
|
|
92
92
|
"deterministic-diagnostic-order",
|
|
93
93
|
"git-native-governance",
|
|
94
94
|
"globally-qualified-compiled-identities",
|
|
95
|
+
"identified-reference-integrity",
|
|
95
96
|
"no-partial-graph-on-error",
|
|
96
97
|
"portable-projection-selectors",
|
|
97
98
|
"source-located-diagnostics"
|
|
@@ -110,6 +111,7 @@
|
|
|
110
111
|
"architectural-quality",
|
|
111
112
|
"automatic-discovery",
|
|
112
113
|
"external-language-conformance",
|
|
114
|
+
"formal-workflow-semantics",
|
|
113
115
|
"state-scoped-claim-values"
|
|
114
116
|
]
|
|
115
117
|
}
|
|
@@ -100,6 +100,9 @@
|
|
|
100
100
|
"$ref": "#/$defs/constraint"
|
|
101
101
|
}
|
|
102
102
|
},
|
|
103
|
+
"references": {
|
|
104
|
+
"$ref": "#/$defs/identifiedReferences"
|
|
105
|
+
},
|
|
103
106
|
"presentIn": {
|
|
104
107
|
"$ref": "#/$defs/stateReferences"
|
|
105
108
|
}
|
|
@@ -118,6 +121,26 @@
|
|
|
118
121
|
}
|
|
119
122
|
}
|
|
120
123
|
},
|
|
124
|
+
"identifiedReference": {
|
|
125
|
+
"type": "object",
|
|
126
|
+
"additionalProperties": false,
|
|
127
|
+
"required": ["id", "ref"],
|
|
128
|
+
"properties": {
|
|
129
|
+
"id": {
|
|
130
|
+
"$ref": "#/$defs/id"
|
|
131
|
+
},
|
|
132
|
+
"ref": {
|
|
133
|
+
"$ref": "#/$defs/reference"
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
"identifiedReferences": {
|
|
138
|
+
"type": "array",
|
|
139
|
+
"minItems": 1,
|
|
140
|
+
"items": {
|
|
141
|
+
"$ref": "#/$defs/identifiedReference"
|
|
142
|
+
}
|
|
143
|
+
},
|
|
121
144
|
"relationship": {
|
|
122
145
|
"type": "object",
|
|
123
146
|
"additionalProperties": false,
|
|
@@ -139,6 +162,9 @@
|
|
|
139
162
|
"name": {
|
|
140
163
|
"$ref": "#/$defs/nonEmptyText"
|
|
141
164
|
},
|
|
165
|
+
"description": {
|
|
166
|
+
"$ref": "#/$defs/nonEmptyText"
|
|
167
|
+
},
|
|
142
168
|
"mode": {
|
|
143
169
|
"enum": ["read", "write", "read-write", "unspecified"]
|
|
144
170
|
},
|
|
@@ -148,6 +174,9 @@
|
|
|
148
174
|
"status": {
|
|
149
175
|
"$ref": "#/$defs/lifecycleStatus"
|
|
150
176
|
},
|
|
177
|
+
"references": {
|
|
178
|
+
"$ref": "#/$defs/identifiedReferences"
|
|
179
|
+
},
|
|
151
180
|
"presentIn": {
|
|
152
181
|
"$ref": "#/$defs/stateReferences"
|
|
153
182
|
}
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"const": "error"
|
|
35
35
|
},
|
|
36
36
|
"code": {
|
|
37
|
-
"enum": ["YMLC101", "YMLC102", "YMLC103", "YMLC104", "YMLC105", "YMLC106"]
|
|
37
|
+
"enum": ["YMLC101", "YMLC102", "YMLC103", "YMLC104", "YMLC105", "YMLC106", "YMLC107", "YMLC108", "YMLC109", "YMLC110"]
|
|
38
38
|
},
|
|
39
39
|
"message": {
|
|
40
40
|
"type": "string",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
"path": {
|
|
43
43
|
"type": "string",
|
|
44
|
+
"description": "Repository-relative path resolved from the CLI working directory. Parent traversal, absolute paths, and backslashes are rejected.",
|
|
44
45
|
"pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$))(?!.*\\\\).+$"
|
|
45
46
|
},
|
|
46
47
|
"subjectIdentity": {
|
|
@@ -43,7 +43,11 @@ relationships:
|
|
|
43
43
|
kind: access
|
|
44
44
|
from: delivery-api
|
|
45
45
|
to: delivery-data
|
|
46
|
+
description: The API uses the governed record without maintaining a copy.
|
|
46
47
|
mode: read-write
|
|
48
|
+
references:
|
|
49
|
+
- id: residency-policy
|
|
50
|
+
ref: delivery-data
|
|
47
51
|
```
|
|
48
52
|
|
|
49
53
|
IDs are document-local and compile to `document-id#subject-id`. Cross-document
|
|
@@ -76,6 +80,29 @@ use association when no stronger semantic meaning is justified.
|
|
|
76
80
|
Ownership is one accountable reference, not approval workflow. Constraints are
|
|
77
81
|
identified references, not a policy engine or free-form metadata bag.
|
|
78
82
|
|
|
83
|
+
## Rationale and citations
|
|
84
|
+
|
|
85
|
+
Use `description` on either a concept or relationship for decided narrative
|
|
86
|
+
about that exact subject. Use an identified `references` entry when the
|
|
87
|
+
narrative depends on another concept or relationship and the citation must
|
|
88
|
+
remain checkable:
|
|
89
|
+
|
|
90
|
+
```yaml
|
|
91
|
+
description: Failure releases the lease and retains partial evidence.
|
|
92
|
+
references:
|
|
93
|
+
- id: failure-destination
|
|
94
|
+
ref: retry-pool
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Core checks the explicit target and local reference ID. It does not scan prose
|
|
98
|
+
for IDs or interpret descriptions as formal preconditions, postconditions, or
|
|
99
|
+
workflow rules.
|
|
100
|
+
|
|
101
|
+
For interaction flows, model steps that need identity as behavior concepts and
|
|
102
|
+
model normal or failure transitions as native relationships. A LikeC4 dynamic
|
|
103
|
+
view may order those projected relationships and display their descriptions;
|
|
104
|
+
the view does not become the workflow source of truth.
|
|
105
|
+
|
|
79
106
|
## Architecture states
|
|
80
107
|
|
|
81
108
|
```yaml
|
|
@@ -153,7 +180,9 @@ yarramate add .yarramate/architecture/main.yaml \
|
|
|
153
180
|
--id delivery-api --kind applicationComponent --name "Delivery API"
|
|
154
181
|
yarramate connect .yarramate/architecture/main.yaml \
|
|
155
182
|
--id api-realizes-service --kind realization \
|
|
156
|
-
--from delivery-api --to delivery-service
|
|
183
|
+
--from delivery-api --to delivery-service \
|
|
184
|
+
--description "The API implements the agreed delivery boundary" \
|
|
185
|
+
--reference decision-source=delivery-service
|
|
157
186
|
yarramate check .yarramate/workspace.yaml --json
|
|
158
187
|
yarramate compile .yarramate/workspace.yaml
|
|
159
188
|
yarramate context <projection.yaml> .yarramate/workspace.yaml
|
|
@@ -161,6 +190,9 @@ yarramate view <projection.yaml> .yarramate/workspace.yaml
|
|
|
161
190
|
yarramate compare <from-state> <to-state> .yarramate/workspace.yaml
|
|
162
191
|
yarramate evidence <evidence.yaml> .yarramate/workspace.yaml
|
|
163
192
|
yarramate reconcile .yarramate/workspace.yaml
|
|
193
|
+
yarramate-likec4 map --sync \
|
|
194
|
+
.yarramate/integrations/likec4/subject-mapping.yaml \
|
|
195
|
+
.yarramate/workspace.yaml
|
|
164
196
|
```
|
|
165
197
|
|
|
166
198
|
Treat exit `0` as successful execution, `1` as correctness diagnostics, and
|