yarramate 0.23.0 → 1.0.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.
Files changed (159) hide show
  1. package/README.md +13 -4
  2. package/catalogues/core-enrichment.yaml +79 -55
  3. package/dist/adapter-mapping.js +6 -1
  4. package/dist/adapters/likec4-cli.js +36 -7
  5. package/dist/adapters/visual/client.d.ts +2 -2
  6. package/dist/adapters/visual/client.js +79 -10
  7. package/dist/adapters/visual/protocol-contract.d.ts +124 -10
  8. package/dist/adapters/visual/protocol-contract.js +12 -1
  9. package/dist/adapters/visual/protocol.d.ts +63 -0
  10. package/dist/adapters/visual/protocol.js +96 -5
  11. package/dist/adapters/visual/session-server.d.ts +1 -6
  12. package/dist/adapters/visual/session-server.js +243 -143
  13. package/dist/adapters/visual/session-store.d.ts +9 -0
  14. package/dist/adapters/visual/session-store.js +14 -5
  15. package/dist/adapters/visual/view-identity.d.ts +135 -0
  16. package/dist/adapters/visual/view-identity.js +200 -0
  17. package/dist/adapters/visual/wire.d.ts +19 -4
  18. package/dist/adapters/visual/workspace-model.d.ts +116 -0
  19. package/dist/adapters/visual/workspace-model.js +212 -0
  20. package/dist/adapters/visual-cli.d.ts +1 -1
  21. package/dist/adapters/visual-cli.js +30 -21
  22. package/dist/apply-cli.d.ts +2 -0
  23. package/dist/apply-cli.js +83 -0
  24. package/dist/apply-command.d.ts +84 -3
  25. package/dist/apply-command.js +218 -109
  26. package/dist/archimate-relationships.generated.d.ts +22 -0
  27. package/dist/archimate-relationships.generated.js +156 -0
  28. package/dist/ask-command.js +18 -6
  29. package/dist/attestation-staleness.js +2 -2
  30. package/dist/changed.js +1 -1
  31. package/dist/check-command.js +13 -5
  32. package/dist/cli-support.d.ts +1 -1
  33. package/dist/cli-support.js +1 -1
  34. package/dist/cli.js +1 -1
  35. package/dist/compiler.d.ts +31 -3
  36. package/dist/compiler.js +321 -81
  37. package/dist/concept-drafting.d.ts +27 -0
  38. package/dist/concept-drafting.js +75 -0
  39. package/dist/core-contract.js +6 -1
  40. package/dist/deletion-drafting.d.ts +52 -0
  41. package/dist/deletion-drafting.js +100 -0
  42. package/dist/evidence.js +6 -1
  43. package/dist/graph-projection.d.ts +14 -0
  44. package/dist/graph-projection.js +4 -0
  45. package/dist/index.d.ts +8 -1
  46. package/dist/index.js +8 -1
  47. package/dist/interrogate-command.js +63 -17
  48. package/dist/kind-label.d.ts +4 -3
  49. package/dist/kind-label.js +4 -3
  50. package/dist/nesting.d.ts +15 -0
  51. package/dist/nesting.js +2 -0
  52. package/dist/notation/archimate.d.ts +1 -1
  53. package/dist/notation/archimate.js +108 -9
  54. package/dist/profile.d.ts +9 -12
  55. package/dist/profile.js +17 -26
  56. package/dist/projection.d.ts +62 -3
  57. package/dist/projection.js +127 -43
  58. package/dist/relationship-drafting.d.ts +51 -0
  59. package/dist/relationship-drafting.js +92 -0
  60. package/dist/relationship-matrix.d.ts +14 -0
  61. package/dist/relationship-matrix.js +74 -0
  62. package/dist/shipped-profile.d.ts +1 -1
  63. package/dist/shipped-profile.js +19 -5
  64. package/dist/source-store.d.ts +95 -0
  65. package/dist/source-store.js +170 -0
  66. package/dist/subject-references.js +1 -1
  67. package/dist/visual-app/assets/index-BLcpI8WN.js +394 -0
  68. package/dist/visual-app/assets/index-DLutIWES.css +1 -0
  69. package/dist/visual-app/index.html +2 -2
  70. package/dist/visual-app-lib/editor.d.ts +1 -0
  71. package/dist/visual-app-lib/editor.js +90968 -0
  72. package/dist/visual-app-lib/styles.css +2 -0
  73. package/dist/visual-app-lib/types/adapter-mapping.d.ts +40 -0
  74. package/dist/visual-app-lib/types/adapters/visual/protocol-contract.d.ts +455 -0
  75. package/dist/visual-app-lib/types/adapters/visual/view-identity.d.ts +135 -0
  76. package/dist/visual-app-lib/types/adapters/visual/wire.d.ts +141 -0
  77. package/dist/visual-app-lib/types/adapters/visual/workspace-model.d.ts +116 -0
  78. package/dist/visual-app-lib/types/apply-command.d.ts +93 -0
  79. package/dist/visual-app-lib/types/archimate-relationships.generated.d.ts +22 -0
  80. package/dist/visual-app-lib/types/brief.d.ts +5 -0
  81. package/dist/visual-app-lib/types/compiler.d.ts +155 -0
  82. package/dist/visual-app-lib/types/concept-drafting.d.ts +27 -0
  83. package/dist/visual-app-lib/types/deletion-drafting.d.ts +52 -0
  84. package/dist/visual-app-lib/types/evidence.d.ts +62 -0
  85. package/dist/visual-app-lib/types/graph-claims.d.ts +18 -0
  86. package/dist/visual-app-lib/types/graph-projection.d.ts +77 -0
  87. package/dist/visual-app-lib/types/kind-label.d.ts +9 -0
  88. package/dist/visual-app-lib/types/nesting.d.ts +15 -0
  89. package/dist/visual-app-lib/types/notation/archimate.d.ts +71 -0
  90. package/dist/visual-app-lib/types/operations.d.ts +157 -0
  91. package/dist/visual-app-lib/types/profile.d.ts +47 -0
  92. package/dist/visual-app-lib/types/projection.d.ts +113 -0
  93. package/dist/visual-app-lib/types/relationship-drafting.d.ts +51 -0
  94. package/dist/visual-app-lib/types/relationship-matrix.d.ts +14 -0
  95. package/dist/visual-app-lib/types/shipped-profile.d.ts +2 -0
  96. package/dist/visual-app-lib/types/source-document.d.ts +36 -0
  97. package/dist/visual-app-lib/types/source-store.d.ts +95 -0
  98. package/dist/visual-app-lib/types/subject-references.d.ts +92 -0
  99. package/dist/visual-app-lib/types/visual-app/App.d.ts +15 -0
  100. package/dist/visual-app-lib/types/visual-app/badges.d.ts +7 -0
  101. package/dist/visual-app-lib/types/visual-app/changeset-tray.d.ts +106 -0
  102. package/dist/visual-app-lib/types/visual-app/confirm-dialog.d.ts +14 -0
  103. package/dist/visual-app-lib/types/visual-app/connection-panel.d.ts +23 -0
  104. package/dist/visual-app-lib/types/visual-app/context-menu-model.d.ts +187 -0
  105. package/dist/visual-app-lib/types/visual-app/context-menu.d.ts +24 -0
  106. package/dist/visual-app-lib/types/visual-app/describe-query.d.ts +9 -0
  107. package/dist/visual-app-lib/types/visual-app/editor-host.d.ts +70 -0
  108. package/dist/visual-app-lib/types/visual-app/faults.d.ts +26 -0
  109. package/dist/visual-app-lib/types/visual-app/graph-canvas.d.ts +73 -0
  110. package/dist/visual-app-lib/types/visual-app/kind-icons.d.ts +3 -0
  111. package/dist/visual-app-lib/types/visual-app/local-host.d.ts +38 -0
  112. package/dist/visual-app-lib/types/visual-app/mount.d.ts +56 -0
  113. package/dist/visual-app-lib/types/visual-app/prompt-dialog.d.ts +24 -0
  114. package/dist/visual-app-lib/types/visual-app/query-fields.d.ts +69 -0
  115. package/dist/visual-app-lib/types/visual-app/query-panel.d.ts +142 -0
  116. package/dist/visual-app-lib/types/visual-app/quick-filter.d.ts +11 -0
  117. package/dist/visual-app-lib/types/visual-app/relationship-kind-options.d.ts +50 -0
  118. package/dist/visual-app-lib/types/visual-app/save-view.d.ts +86 -0
  119. package/dist/visual-app-lib/types/visual-app/section-stack.d.ts +59 -0
  120. package/dist/visual-app-lib/types/visual-app/session-client.d.ts +38 -0
  121. package/dist/visual-app-lib/types/visual-app/state.d.ts +328 -0
  122. package/dist/visual-app-lib/types/visual-app/subject-draft-panel.d.ts +22 -0
  123. package/dist/visual-app-lib/types/visual-app/subject-form.d.ts +42 -0
  124. package/dist/visual-app-lib/types/visual-app/view-tree-model.d.ts +122 -0
  125. package/dist/visual-app-lib/types/visual-app/view-tree.d.ts +32 -0
  126. package/dist/visual-app-lib/types/visual-app/workspace-state.d.ts +268 -0
  127. package/dist/visual-app-lib/types/workspace.d.ts +29 -0
  128. package/dist/workspace.js +7 -1
  129. package/docs/CONSUMING-YARRAMATE.md +51 -2
  130. package/package.json +9 -2
  131. package/schema/yarramate-adapter-mapping.schema.json +1 -1
  132. package/schema/yarramate-ask-result.schema.json +24 -3
  133. package/schema/yarramate-check-result.schema.json +9 -0
  134. package/schema/yarramate-diagnostic-result.schema.json +9 -0
  135. package/schema/yarramate-document.schema.json +6 -0
  136. package/schema/yarramate-evidence-report.schema.json +1 -1
  137. package/schema/yarramate-evidence.schema.json +1 -1
  138. package/schema/yarramate-graph-v2.schema.json +34 -9
  139. package/schema/yarramate-likec4-generated-project-v2.schema.json +1 -1
  140. package/schema/yarramate-likec4-generated-project.schema.json +1 -1
  141. package/schema/yarramate-likec4-project.schema.json +1 -1
  142. package/schema/yarramate-projection-result.schema.json +3 -7
  143. package/schema/yarramate-projection.schema.json +16 -16
  144. package/schema/yarramate-reconciliation-report.schema.json +2 -2
  145. package/schema/yarramate-rtm.schema.json +1 -1
  146. package/schema/yarramate-state-comparison.schema.json +1 -1
  147. package/schema/yarramate-visual-diagnostic-result.schema.json +9 -0
  148. package/schema/yarramate-visual-event.schema.json +40 -41
  149. package/schema/yarramate-visual-graph.schema.json +8 -0
  150. package/schema/yarramate-visual-handoff.schema.json +3 -3
  151. package/schema/yarramate-visual-session-descriptor.schema.json +6 -6
  152. package/schema/yarramate-visual-session-started.schema.json +10 -9
  153. package/schema/yarramate-visual-status.schema.json +3 -3
  154. package/skills/yarramate-architecture/SKILL.md +3 -3
  155. package/skills/yarramate-architecture/references/modelling-patterns.md +23 -44
  156. package/skills/yarramate-architecture/references/native-authoring.md +32 -49
  157. package/skills/yarramate-architecture/references/visual-conversations.md +13 -10
  158. package/dist/visual-app/assets/index-CRd1Khma.js +0 -354
  159. package/dist/visual-app/assets/index-tZSHlU-a.css +0 -1
package/README.md CHANGED
@@ -183,10 +183,19 @@ projections, evidence, and architecture states; and exposes a stable CLI for
183
183
  people, CI, skills, and agent harnesses.
184
184
 
185
185
  Optional adapters provide LikeC4 visualization from semantic projections,
186
- Graphify observations as evidence overlays, loopback-only visual
187
- conversations that render the native model and land reviewer edits through
188
- the same validated `apply` batch (beta), and separately governed
189
- compatibility profiles for external languages. Core depends on none of them.
186
+ Graphify observations as evidence overlays, and a visual editor that
187
+ renders the native model and lands reviewer edits through the same
188
+ validated `apply` batch (beta). The editor runs two ways: as the
189
+ loopback-only session `yarramate-visual start` serves, or mounted inside
190
+ another product from `yarramate/visual-app`, over a store that product
191
+ owns, with no Node process behind it. Core depends on none of them.
192
+
193
+ YarraMate's core profile implements the ArchiMate® 3.2 element vocabulary
194
+ and relationship table: a relationship between two kinds is valid exactly
195
+ when the table permits it. The custody layer YarraMate adds - evidence,
196
+ attestations, lifecycle status, ownership, architecture states - is
197
+ annotation that never changes what an ArchiMate element or relationship
198
+ means (ADR 0097).
190
199
 
191
200
  YarraMate is not affiliated with or certified by The Open Group. ArchiMate®
192
201
  is a registered trademark of The Open Group. LikeC4 and Graphify are
@@ -1,6 +1,6 @@
1
1
  format: yarramate/question-catalogue/v1
2
2
  id: core-enrichment
3
- version: "0.9"
3
+ version: "1.0"
4
4
  profile: yarramate/core@0.1
5
5
  presentation:
6
6
  title: Core enrichment interview
@@ -22,9 +22,9 @@ waves:
22
22
  - id: interaction
23
23
  name: Interaction
24
24
  description: >-
25
- Load-bearing hops: the behavior a component is assigned to, the
26
- serving/triggering/flow mechanism, payload, trust, reliability, and
27
- capacity. Hygiene waits.
25
+ Load-bearing hops: the behavior a component is assigned to or the
26
+ interface it composes, the serving/triggering/flow mechanism,
27
+ payload, trust, reliability, and capacity. Hygiene waits.
28
28
  - id: business
29
29
  name: Business
30
30
  description: Who acts, what is served, and what information matters.
@@ -287,9 +287,11 @@ questions:
287
287
  influences is what makes it enforceable in review.
288
288
  authority: either
289
289
  resolution: >-
290
- Add influence relationships to the decisions the principle governs,
291
- or realization from the elements that embody it.
292
-
290
+ Add influence from the principle to the goals, outcomes, or
291
+ requirements it shapes, or realization from the requirements and
292
+ constraints that make it concrete. Influence only points at
293
+ motivation elements; a decision is recorded as the requirement it
294
+ produced.
293
295
  - id: assessment-unlinked
294
296
  wave: motivation
295
297
  since: "0.3"
@@ -417,6 +419,7 @@ questions:
417
419
  counterpartKinds:
418
420
  - yarramate/core@0.1#applicationComponent
419
421
  - yarramate/core@0.1#applicationInterface
422
+ - yarramate/core@0.1#applicationService
420
423
  - yarramate/core@0.1#applicationProcess
421
424
  - yarramate/core@0.1#applicationFunction
422
425
  - yarramate/core@0.1#applicationInteraction
@@ -459,6 +462,7 @@ questions:
459
462
  counterpartKinds:
460
463
  - yarramate/core@0.1#applicationComponent
461
464
  - yarramate/core@0.1#applicationInterface
465
+ - yarramate/core@0.1#applicationService
462
466
  - yarramate/core@0.1#businessActor
463
467
  - condition: missing-linkage
464
468
  kinds:
@@ -469,24 +473,33 @@ questions:
469
473
  - yarramate/core@0.1#applicationFunction
470
474
  - yarramate/core@0.1#applicationInteraction
471
475
  - yarramate/core@0.1#applicationEvent
476
+ - condition: missing-linkage
477
+ kinds:
478
+ - yarramate/core@0.1#composition
479
+ - yarramate/core@0.1#aggregation
480
+ direction: outgoing
481
+ counterpartKinds:
472
482
  - yarramate/core@0.1#applicationInterface
473
483
  question: >-
474
484
  {subject.name} participates in an application interaction, but
475
- nothing it is assigned to is that interaction. What process,
476
- function, interaction, event, or interface is the hop?
485
+ nothing it is assigned to or composes is that interaction. What
486
+ process, function, interaction, event, or interface is the hop?
477
487
  askPlain: >-
478
488
  {subject.name} talks to something else, but the model never names
479
489
  the work it does in that talk. What is the actual step?
480
490
  materiality: >-
481
- A component-to-component edge with no assigned behavior is
482
- inventory. Protocol, trust, payload, and failure have nowhere to
483
- bind until the hop is a subject.
491
+ A component-to-component edge with no assigned behavior or composed
492
+ interface is inventory. Protocol, trust, payload, and failure have
493
+ nowhere to bind until the hop is a subject.
484
494
  authority: either
485
495
  resolution: >-
486
- Add an application process, function, interaction, event, or
487
- interface, assign this component to it, and relate that behavior
488
- with serving, triggering, or flow to its counterpart. Do not answer
489
- by deleting the component or adding a realization instead.
496
+ Add the application process, function, interaction, or event this
497
+ component performs and assign the component to it, or add the
498
+ application interface it exposes and compose it into the component;
499
+ then relate that behavior or interface with serving, triggering, or
500
+ flow to its counterpart. Realizing a service does not close this:
501
+ the service is what the hop offers, the process or interface is the
502
+ hop. Do not answer by deleting the component.
490
503
 
491
504
  - id: interaction-protocol-unbound
492
505
  wave: interaction
@@ -510,6 +523,7 @@ questions:
510
523
  counterpartKinds:
511
524
  - yarramate/core@0.1#applicationComponent
512
525
  - yarramate/core@0.1#applicationInterface
526
+ - yarramate/core@0.1#applicationService
513
527
  - yarramate/core@0.1#applicationProcess
514
528
  - yarramate/core@0.1#applicationFunction
515
529
  - yarramate/core@0.1#applicationInteraction
@@ -528,7 +542,7 @@ questions:
528
542
  hop fail, version, and authenticate differently.
529
543
  authority: either
530
544
  resolution: >-
531
- Bind a mechanism-constraint on this behavior (or a not-applicable
545
+ Bind a mechanism-constraint on this behavior or interface (or a not-applicable
532
546
  subject if the serving kind is already the whole answer).
533
547
 
534
548
  - id: interaction-content-unknown
@@ -569,6 +583,7 @@ questions:
569
583
  - yarramate/core@0.1#applicationInteraction
570
584
  - yarramate/core@0.1#applicationEvent
571
585
  - yarramate/core@0.1#applicationInterface
586
+ - yarramate/core@0.1#applicationService
572
587
  statuses:
573
588
  - planned
574
589
  - current
@@ -582,6 +597,7 @@ questions:
582
597
  counterpartKinds:
583
598
  - yarramate/core@0.1#applicationComponent
584
599
  - yarramate/core@0.1#applicationInterface
600
+ - yarramate/core@0.1#applicationService
585
601
  - yarramate/core@0.1#applicationProcess
586
602
  - yarramate/core@0.1#applicationFunction
587
603
  - yarramate/core@0.1#applicationInteraction
@@ -630,6 +646,7 @@ questions:
630
646
  counterpartKinds:
631
647
  - yarramate/core@0.1#applicationComponent
632
648
  - yarramate/core@0.1#applicationInterface
649
+ - yarramate/core@0.1#applicationService
633
650
  - yarramate/core@0.1#applicationProcess
634
651
  - yarramate/core@0.1#applicationFunction
635
652
  - yarramate/core@0.1#applicationInteraction
@@ -674,6 +691,7 @@ questions:
674
691
  counterpartKinds:
675
692
  - yarramate/core@0.1#applicationComponent
676
693
  - yarramate/core@0.1#applicationInterface
694
+ - yarramate/core@0.1#applicationService
677
695
  - yarramate/core@0.1#applicationProcess
678
696
  - yarramate/core@0.1#applicationFunction
679
697
  - yarramate/core@0.1#applicationInteraction
@@ -940,7 +958,6 @@ questions:
940
958
  - yarramate/core@0.1#businessFunction
941
959
  - yarramate/core@0.1#applicationService
942
960
  - yarramate/core@0.1#applicationComponent
943
- - yarramate/core@0.1#capability
944
961
  question: >-
945
962
  What actually delivers {subject.name}?
946
963
  askPlain: >-
@@ -952,10 +969,9 @@ questions:
952
969
  wrong.
953
970
  authority: either
954
971
  resolution: >-
955
- Add realization from the process, function, or application element
956
- that delivers it.
957
-
958
-
972
+ Add realization from the business process or function that delivers
973
+ it, or from the application service or component that automates it.
974
+ A capability is realized by the service, not the other way round.
959
975
  # ---- application ---------------------------------------------------------
960
976
  - id: app-service-unrealized
961
977
  wave: application
@@ -1033,8 +1049,7 @@ questions:
1033
1049
  counterpartKinds:
1034
1050
  - yarramate/core@0.1#applicationComponent
1035
1051
  - yarramate/core@0.1#applicationCollaboration
1036
- - yarramate/core@0.1#businessActor
1037
- - yarramate/core@0.1#businessRole
1052
+ - yarramate/core@0.1#applicationInterface
1038
1053
  question: >-
1039
1054
  Who or what performs {subject.name}?
1040
1055
  materiality: >-
@@ -1043,9 +1058,11 @@ questions:
1043
1058
  to put it.
1044
1059
  authority: either
1045
1060
  resolution: >-
1046
- Add assignment from the component, collaboration, or actor that
1047
- performs the behavior.
1048
-
1061
+ Add assignment from the application component, collaboration, or
1062
+ interface that performs the behavior. A business actor or role does
1063
+ not perform application behavior: assign the actor to the business
1064
+ process that uses it and let the application service serve that
1065
+ process.
1049
1066
  - id: event-triggers-nothing
1050
1067
  wave: application
1051
1068
  since: "0.3"
@@ -1132,14 +1149,15 @@ questions:
1132
1149
  trigger:
1133
1150
  - condition: missing-linkage
1134
1151
  kinds:
1152
+ - yarramate/core@0.1#realization
1135
1153
  - yarramate/core@0.1#serving
1136
- - yarramate/core@0.1#assignment
1137
1154
  direction: incoming
1138
1155
  counterpartKinds:
1139
1156
  - yarramate/core@0.1#node
1140
1157
  - yarramate/core@0.1#device
1141
1158
  - yarramate/core@0.1#systemSoftware
1142
1159
  - yarramate/core@0.1#technologyService
1160
+ - yarramate/core@0.1#artifact
1143
1161
  question: >-
1144
1162
  Where does {subject.name} run?
1145
1163
  materiality: >-
@@ -1150,9 +1168,12 @@ questions:
1150
1168
  hosting rather than answering separately.
1151
1169
  authority: either
1152
1170
  resolution: >-
1153
- Add the node, device, or system software that hosts it with a
1154
- serving or assignment relationship into the component.
1155
-
1171
+ Add realization or serving from the node, device, or system
1172
+ software that hosts it, or from the technology service it runs on;
1173
+ or add the artifact that materializes it, with realization to the
1174
+ component and assignment from the node that deploys the artifact.
1175
+ Technology is never assigned to a component: assignment runs from a
1176
+ node to the artifacts and technology behavior it carries.
1156
1177
  - id: node-serves-nothing
1157
1178
  wave: technology
1158
1179
  since: "0.4"
@@ -1166,6 +1187,7 @@ questions:
1166
1187
  - condition: missing-relationship
1167
1188
  kinds:
1168
1189
  - yarramate/core@0.1#serving
1190
+ - yarramate/core@0.1#realization
1169
1191
  - yarramate/core@0.1#assignment
1170
1192
  direction: outgoing
1171
1193
  question: >-
@@ -1176,9 +1198,9 @@ questions:
1176
1198
  deployment budget.
1177
1199
  authority: either
1178
1200
  resolution: >-
1179
- Add serving or assignment relationships to the applications and
1180
- behavior it hosts, or remove it.
1181
-
1201
+ Add realization or serving to the application components it hosts,
1202
+ or assignment to the artifacts it deploys and the technology
1203
+ behavior it performs, or remove it.
1182
1204
  - id: technology-service-unrealized
1183
1205
  wave: technology
1184
1206
  since: "0.4"
@@ -1232,9 +1254,9 @@ questions:
1232
1254
  starts from exactly these links.
1233
1255
  authority: either
1234
1256
  resolution: >-
1235
- Assign the artifact to the node that deploys it and add realization
1236
- to the component or data it materializes.
1237
-
1257
+ Add assignment from the node that deploys the artifact and
1258
+ realization from the artifact to the component or data object it
1259
+ materializes.
1238
1260
  # ---- implementation ------------------------------------------------------
1239
1261
  - id: workpackage-delivers-nothing
1240
1262
  wave: implementation
@@ -1341,7 +1363,6 @@ questions:
1341
1363
  - condition: missing-relationship
1342
1364
  kinds:
1343
1365
  - yarramate/core@0.1#association
1344
- - yarramate/core@0.1#realization
1345
1366
  direction: any
1346
1367
  question: >-
1347
1368
  What closes {subject.name}?
@@ -1350,9 +1371,10 @@ questions:
1350
1371
  work closes it or the acceptance of it should be on record.
1351
1372
  authority: human
1352
1373
  resolution: >-
1353
- Associate the gap with the plateaus it separates and the
1354
- deliverable that closes it, or record the decision to accept it.
1355
-
1374
+ Associate the gap with the plateaus it separates and with the
1375
+ deliverable or work package that closes it - a gap is only ever
1376
+ associated, never realized - or associate it with the assessment
1377
+ that records the decision to accept it.
1356
1378
  # ---- hygiene -------------------------------------------------------------
1357
1379
  - id: concept-isolated
1358
1380
  wave: hygiene
@@ -1503,25 +1525,27 @@ questions:
1503
1525
  - condition: unconstrained-kind
1504
1526
  question: >-
1505
1527
  Nothing in the model tests that {subject.name} is a structural element
1506
- at all: no behaviour is assigned to it, so reclassifying it as a
1507
- service, an object, or a goal would compile exactly the same. What
1508
- does it run, host, or perform?
1528
+ at all: every relationship it has would be just as legal if it were
1529
+ a service, an object, or a goal. What does it run, host, or perform?
1509
1530
  askPlain: >-
1510
1531
  What does {subject.name} actually do, or what runs on it? The model
1511
1532
  says what it is but nothing says what it takes part in.
1512
1533
  materiality: >-
1513
1534
  A structural kind is a promise that something behaves through this
1514
- element. Only four relationship kinds constrain the aspect of an
1515
- endpoint, so where none of them touches the subject the kind is a
1516
- label no check can contradict the choice between a node, a piece of
1517
- system software, and an application component stops carrying
1518
- information, and diagrams inherit a distinction the model never made.
1535
+ element. ArchiMate permits a different set of relationships for
1536
+ every pair of kinds, so a subject whose relationships would all
1537
+ survive reclassification to another aspect carries a kind no check
1538
+ can contradict the choice between a node, a piece of system
1539
+ software, and an application component stops carrying information,
1540
+ and diagrams inherit a distinction the model never made.
1519
1541
  authority: either
1520
1542
  resolution: >-
1521
1543
  Assign {subject.name} to the behaviour it performs — the process,
1522
- function, service, or capability it carries. Assignment is the one
1523
- claim whose source endpoint must be an active structure, so recording
1524
- it makes the classification falsifiable. If nothing in scope is
1525
- assigned to it, reclassify it to a kind that does carry a claim, or
1526
- retire it with a description saying why it sits outside this
1527
- architecture.
1544
+ function, or interaction it carries; an interface to the service it
1545
+ exposes; a node to the artifacts and system software it runs; a
1546
+ resource to the capability it supports. Assignment from an active
1547
+ structure is the claim no behavior, object, or motivation element
1548
+ could make in its place, so recording it makes the classification
1549
+ falsifiable. If nothing in scope is assigned to it, reclassify it
1550
+ to a kind that does carry a claim, or retire it with a description
1551
+ saying why it sits outside this architecture.
@@ -2,7 +2,12 @@ import Ajv2020Module from 'ajv/dist/2020.js';
2
2
  import { diagnosticOrder, loadSourceDocument, locateSourcePath, } from './source-document.js';
3
3
  import adapterMappingSchema from '../schema/yarramate-adapter-mapping.schema.json' with { type: 'json'
4
4
  };
5
- const Ajv2020 = Ajv2020Module.default;
5
+ // `.default ?? module`, not a bare `.default`: NodeNext sees the raw CJS
6
+ // `module.exports` and a bundler the unwrapped class. One shape for all of
7
+ // them, so which modules a browser happens to reach is not a thing anyone has
8
+ // to keep track of (#252).
9
+ const ajv2020Module = Ajv2020Module;
10
+ const Ajv2020 = ajv2020Module.default ?? ajv2020Module;
6
11
  const validateSchema = new Ajv2020({ allErrors: true }).compile(adapterMappingSchema);
7
12
  const mappingLocations = new WeakMap();
8
13
  export function loadAdapterMapping(source) {
@@ -23,6 +23,33 @@ const validateGeneratedProjectMarker = new Ajv2020({
23
23
  const validateGeneratedProjectV2Marker = new Ajv2020({
24
24
  allErrors: true,
25
25
  }).compile(generatedProjectV2Schema);
26
+ // A marker written before 1.0 flattened subject ids records a comparison's
27
+ // endpoints in the qualified `<document>#<local>` form, which `subjectIdentity`
28
+ // no longer admits in either marker version. Such a marker is still one of
29
+ // ours: those ids are recorded metadata, not addresses anything resolves, and
30
+ // regeneration rewrites them flat. So it is accepted where an existing project
31
+ // is read, exactly as a marker written before output digests existed is, and
32
+ // the upgrade happens on the next write with nothing for the reader to do.
33
+ // Each variant is derived from its own schema rather than copied, so a change
34
+ // to either cannot leave its variant behind: only the one pattern is relaxed.
35
+ const preFlattenSubjectIdentity = '^[a-z][a-z0-9]*(?:-[a-z0-9]+)*(?:#[a-z][a-z0-9]*(?:-[a-z0-9]+)*)?$';
36
+ const preFlattenVariant = (schema) => ({
37
+ ...schema,
38
+ $id: `${schema.$id}/pre-flatten-subject-ids`,
39
+ $defs: {
40
+ ...schema.$defs,
41
+ subjectIdentity: {
42
+ ...schema.$defs.subjectIdentity,
43
+ pattern: preFlattenSubjectIdentity,
44
+ },
45
+ },
46
+ });
47
+ const validateGeneratedProjectPreFlattenMarker = new Ajv2020({
48
+ allErrors: true,
49
+ }).compile(preFlattenVariant(generatedProjectSchema));
50
+ const validateGeneratedProjectV2PreFlattenMarker = new Ajv2020({
51
+ allErrors: true,
52
+ }).compile(preFlattenVariant(generatedProjectV2Schema));
26
53
  const generatedFileNames = [
27
54
  'likec4.config.json',
28
55
  'model.likec4',
@@ -199,12 +226,12 @@ const runLikeC4MapSync = (args, cwd) => {
199
226
  const additions = compilation.graph.subjects
200
227
  .filter(({ id }) => !mapped.has(id) && !architectureStates.has(id))
201
228
  .map((subject) => {
202
- const [documentId, localId] = subject.id.split('#');
203
- const local = lowerCamel(localId);
204
- let external = local;
205
- if (claimedExternal.has(external)) {
206
- external = `${lowerCamel(documentId)}_${local}`;
207
- }
229
+ // A subject id is the authored id, unique across the workspace, so it
230
+ // is the whole name. The document-prefixed fallback that used to break
231
+ // ties has nothing left to disambiguate; two ids can still collapse
232
+ // onto one camel-case name (`foo-bar` and `fooBar`), and the numeric
233
+ // suffix below has always been what separates those.
234
+ let external = lowerCamel(subject.id);
208
235
  let suffix = 2;
209
236
  const base = external;
210
237
  while (claimedExternal.has(external)) {
@@ -303,7 +330,9 @@ const readGeneratedProjectMarker = (markerPath) => {
303
330
  return undefined;
304
331
  }
305
332
  return validateGeneratedProjectMarker(marker) ||
306
- validateGeneratedProjectV2Marker(marker)
333
+ validateGeneratedProjectV2Marker(marker) ||
334
+ validateGeneratedProjectPreFlattenMarker(marker) ||
335
+ validateGeneratedProjectV2PreFlattenMarker(marker)
307
336
  ? marker
308
337
  : undefined;
309
338
  };
@@ -27,13 +27,13 @@ export declare const visualFailureDiagnostics: (cause: unknown) => readonly Visu
27
27
  * removed. Absence alone is not evidence: the stopped marker is written before
28
28
  * teardown and names the vanished session directory.
29
29
  */
30
- export declare const visualSessionAlreadyStopped: (path: string, cwd?: string) => Promise<boolean>;
30
+ export declare const visualSessionAlreadyStopped: (uri: string) => Promise<boolean>;
31
31
  /**
32
32
  * The agent's entry point into one live session, read the way a hostile file
33
33
  * has to be read. The descriptor is the only file carrying the agent
34
34
  * capability, so a redirected or planted one must never be spent.
35
35
  */
36
- export declare const readVisualSessionDescriptor: (path: string, cwd?: string) => Promise<ParseResult<VisualSessionDescriptor>>;
36
+ export declare const readVisualSessionDescriptor: (uri: string) => Promise<ParseResult<VisualSessionDescriptor>>;
37
37
  /** One JSON document the agent hands to a command, read from the filesystem. */
38
38
  export declare const readVisualJsonDocument: (path: string, cwd?: string) => Promise<ParseResult<unknown>>;
39
39
  /**
@@ -1,7 +1,7 @@
1
1
  import { constants } from 'node:fs';
2
2
  import { lstat, open, readFile, stat } from 'node:fs/promises';
3
3
  import { basename, dirname, join, resolve } from 'node:path';
4
- import { VISUAL_PROTOCOL_VERSION, parseVisualDiagnosticResult, parseVisualEvent, parseVisualHandoff, parseVisualSessionDescriptor, parseVisualStatus, } from './protocol.js';
4
+ import { VISUAL_PROTOCOL_VERSION, fromWireFileUri, parseVisualDiagnosticResult, parseVisualEvent, parseVisualHandoff, parseVisualSessionDescriptor, parseVisualStatus, toWireFileUri, } from './protocol.js';
5
5
  import { VISUAL_SERVER_LIMITS, } from './session-server.js';
6
6
  import { recoverVisualSession, removeVisualSession, visualSessionPaths, } from './session-store.js';
7
7
  /**
@@ -45,6 +45,33 @@ export const visualClientDiagnostic = (code, message, pointer = '/') => ({
45
45
  column: 1,
46
46
  });
47
47
  const refused = (diagnostics) => ({ ok: false, diagnostics });
48
+ /**
49
+ * How each way a wire path can be refused reads. One code carries all three,
50
+ * the way `YMVS401` already covers two distinct underlying causes.
51
+ */
52
+ const WIRE_URI_REFUSAL = {
53
+ malformed: 'is not a canonical file: URI',
54
+ nonlocal: 'names a nonlocal location',
55
+ noncanonical: 'is not the canonical encoding of its own target',
56
+ };
57
+ /**
58
+ * Decode one untrusted wire path to native, or refuse it.
59
+ *
60
+ * Nothing is resolved against `cwd`. A `file:` URI is inherently absolute, so
61
+ * the ambiguous, platform-dependent path string this representation retires
62
+ * cannot re-enter through the one argument an operator still passes by hand:
63
+ * `wait`/`respond`/`status`/`recover`/`stop` take the exact `descriptorPath`
64
+ * URI `start` published, copied back verbatim. A native path is refused here
65
+ * visibly rather than half-working.
66
+ */
67
+ const decodeWireUri = (label, uri) => {
68
+ const decoded = fromWireFileUri(uri);
69
+ return decoded.ok
70
+ ? { ok: true, value: decoded.value }
71
+ : refused([
72
+ visualClientDiagnostic('YMVS414', `${label} "${uri}" ${WIRE_URI_REFUSAL[decoded.reason]}`),
73
+ ]);
74
+ };
48
75
  export const visualFailureDiagnostics = (cause) => {
49
76
  const message = cause instanceof Error ? cause.message : String(cause);
50
77
  const named = STORE_FAILURE.exec(message);
@@ -111,8 +138,13 @@ const readsStoppedMarker = async (sessionRoot, sessionId) => {
111
138
  * removed. Absence alone is not evidence: the stopped marker is written before
112
139
  * teardown and names the vanished session directory.
113
140
  */
114
- export const visualSessionAlreadyStopped = async (path, cwd = process.cwd()) => {
115
- const target = resolve(cwd, path);
141
+ export const visualSessionAlreadyStopped = async (uri) => {
142
+ // A descriptor URI that will not decode names no session at all, so it is
143
+ // not evidence that one was stopped; the caller's own refusal stands.
144
+ const decoded = fromWireFileUri(uri);
145
+ if (!decoded.ok)
146
+ return false;
147
+ const target = decoded.value;
116
148
  const sessionRoot = dirname(target);
117
149
  const sessionId = basename(sessionRoot);
118
150
  return (basename(target) === 'descriptor.json' &&
@@ -125,8 +157,15 @@ export const visualSessionAlreadyStopped = async (path, cwd = process.cwd()) =>
125
157
  * has to be read. The descriptor is the only file carrying the agent
126
158
  * capability, so a redirected or planted one must never be spent.
127
159
  */
128
- export const readVisualSessionDescriptor = async (path, cwd = process.cwd()) => {
129
- const target = resolve(cwd, path);
160
+ export const readVisualSessionDescriptor = async (uri) => {
161
+ // The URI is proven to be one specific local file before that file is
162
+ // opened, and long before the capability inside it is spent. `target` is the
163
+ // native path `open()` needs; `uri` itself is already canonical past this
164
+ // point, so the ownership check below compares it directly.
165
+ const decoded = decodeWireUri('Session descriptor path', uri);
166
+ if (!decoded.ok)
167
+ return decoded;
168
+ const target = decoded.value;
130
169
  let raw;
131
170
  // One handle, opened once: the descriptor is the only file carrying the agent
132
171
  // capability, so the thing that is checked has to be the thing that is read.
@@ -171,17 +210,47 @@ export const readVisualSessionDescriptor = async (path, cwd = process.cwd()) =>
171
210
  const parsed = parseVisualSessionDescriptor(document);
172
211
  if (!parsed.ok)
173
212
  return parsed;
174
- const paths = visualSessionPaths(parsed.value.sessionRoot);
213
+ // The document's own path fields are untrusted too, and are decoded on the
214
+ // same terms as the argument: `sessionRoot` because it is about to be used
215
+ // as a filesystem path, `journalPath` so a refusal names the field that was
216
+ // malformed rather than reporting it as a vaguer ownership mismatch.
217
+ const root = decodeWireUri('Session root', parsed.value.sessionRoot);
218
+ if (!root.ok)
219
+ return root;
220
+ const journal = decodeWireUri('Session journal path', parsed.value.journalPath);
221
+ if (!journal.ok)
222
+ return journal;
223
+ const paths = visualSessionPaths(root.value);
175
224
  // A descriptor authorises work on the session it lives in and no other: this
176
225
  // is the same invariant the runtime enforced when it published the file, so a
177
226
  // copied or planted descriptor cannot direct a stop at another directory.
178
- if (paths.descriptor !== target || paths.journal !== parsed.value.journalPath) {
227
+ // Both sides of each compare are now canonical by construction, so a match
228
+ // proves the descriptor names the exact file that was opened rather than
229
+ // merely failing to disprove it.
230
+ if (toWireFileUri(paths.descriptor) !== uri ||
231
+ toWireFileUri(paths.journal) !== parsed.value.journalPath) {
179
232
  return refused([
180
233
  visualClientDiagnostic('YMVS403', `Session descriptor "${target}" names session artefacts outside its own directory`),
181
234
  ]);
182
235
  }
183
236
  return parsed;
184
237
  };
238
+ /**
239
+ * The session directory a verified descriptor names.
240
+ *
241
+ * Every descriptor that reaches the commands below came through
242
+ * `readVisualSessionDescriptor`, which already proved `sessionRoot` decodes to
243
+ * one canonical local path. The only way this can fail is a caller that
244
+ * skipped that gate, which is a programming error rather than a protocol
245
+ * fault, so it throws where the surrounding refusals return.
246
+ */
247
+ const sessionPathsOf = (descriptor) => {
248
+ const decoded = fromWireFileUri(descriptor.sessionRoot);
249
+ if (!decoded.ok) {
250
+ throw new Error(`Session root "${descriptor.sessionRoot}" was never decoded: ${decoded.reason}`);
251
+ }
252
+ return visualSessionPaths(decoded.value);
253
+ };
185
254
  /** One JSON document the agent hands to a command, read from the filesystem. */
186
255
  export const readVisualJsonDocument = async (path, cwd = process.cwd()) => {
187
256
  const target = resolve(cwd, path);
@@ -330,7 +399,7 @@ export const sendVisualResponse = async (descriptor, response) => {
330
399
  * marker that is present and unusable is a fault the caller has to see.
331
400
  */
332
401
  const localVisualStatus = async (descriptor) => {
333
- const paths = visualSessionPaths(descriptor.sessionRoot);
402
+ const paths = sessionPathsOf(descriptor);
334
403
  let lastSequence = 0;
335
404
  let transcriptBytes = 0;
336
405
  try {
@@ -389,7 +458,7 @@ export const recoverVisualSessionClient = async (descriptor, includeTranscript =
389
458
  try {
390
459
  return {
391
460
  ok: true,
392
- value: await recoverVisualSession(visualSessionPaths(descriptor.sessionRoot), includeTranscript),
461
+ value: await recoverVisualSession(sessionPathsOf(descriptor), includeTranscript),
393
462
  };
394
463
  }
395
464
  catch (cause) {
@@ -424,7 +493,7 @@ const closedHandoff = (answer) => {
424
493
  * repeated stop idempotent.
425
494
  */
426
495
  export const stopVisualSessionClient = async (descriptor, includeTranscript = false) => {
427
- const paths = visualSessionPaths(descriptor.sessionRoot);
496
+ const paths = sessionPathsOf(descriptor);
428
497
  if (!(await exists(paths.root)))
429
498
  return { ok: true, value: undefined };
430
499
  const recovered = await recoverVisualSessionClient(descriptor, includeTranscript);