yarramate 1.3.0 → 1.4.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/catalogues/core-enrichment.yaml +13 -1
- package/dist/adapters/visual/workspace-model.d.ts +14 -2
- package/dist/adapters/visual/workspace-model.js +19 -9
- package/dist/ask-command.js +8 -1
- package/dist/compiler.d.ts +13 -1
- package/dist/compiler.js +646 -0
- package/dist/design-command.js +14 -3
- package/dist/graph-projection.d.ts +10 -0
- package/dist/graph-projection.js +1 -0
- package/dist/interrogate-command.d.ts +17 -0
- package/dist/interrogate-command.js +72 -40
- package/dist/relationship-drafting.js +16 -1
- package/dist/visual-app/assets/{index-C3i9SxTe.js → index-yCHtmQUH.js} +1 -1
- package/dist/visual-app/index.html +1 -1
- package/dist/visual-app-lib/editor.js +22875 -22261
- package/dist/visual-app-lib/types/adapters/visual/workspace-model.d.ts +14 -2
- package/dist/visual-app-lib/types/compiler.d.ts +13 -1
- package/dist/visual-app-lib/types/graph-projection.d.ts +10 -0
- package/dist/visual-app-lib/types/interrogate-command.d.ts +17 -0
- package/dist/visual-app-lib/types/visual-app/local-host.d.ts +42 -0
- package/dist/visual-app-lib/types/workspace.d.ts +2 -0
- package/dist/workspace.d.ts +2 -0
- package/dist/workspace.js +1 -0
- package/docs/CONSUMING-YARRAMATE.md +41 -0
- package/package.json +2 -1
- package/schema/yarramate-design-step.schema.json +13 -0
- package/schema/yarramate-document.schema.json +14 -0
- package/schema/yarramate-interrogation-report.schema.json +18 -0
- package/schema/yarramate-pattern.schema.json +133 -0
- package/schema/yarramate-question-catalogue.schema.json +21 -0
- package/schema/yarramate-visual-graph.schema.json +9 -0
- package/schema/yarramate-workspace.schema.json +4 -0
package/dist/design-command.js
CHANGED
|
@@ -282,9 +282,20 @@ export function runDesignCommand(options, cwd) {
|
|
|
282
282
|
'',
|
|
283
283
|
];
|
|
284
284
|
if (step === null) {
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
285
|
+
// "No open questions" has two causes and only one of them is complete
|
|
286
|
+
// (#334). Every wave gated shut asks NOTHING, so a blank model reaches
|
|
287
|
+
// zero without a single question having been put - and claiming the
|
|
288
|
+
// model answers everything the catalogue asks is then flatly false
|
|
289
|
+
// about a catalogue that asked nothing. Completion inferred from an
|
|
290
|
+
// empty set is the same fault the wave rail and the report renderer
|
|
291
|
+
// each carried; this is the sentence an agent reads to decide it is
|
|
292
|
+
// done, so it is the worst place for it.
|
|
293
|
+
const asked = report.waves.some((wave) => wave.questions.length > 0);
|
|
294
|
+
lines.push(!asked
|
|
295
|
+
? 'No wave has opened yet: this catalogue asks nothing until the model has substance. Declare a subject and run this again.'
|
|
296
|
+
: subjectFilter === undefined
|
|
297
|
+
? 'Interview complete: no open questions. The model answers everything the catalogue asks.'
|
|
298
|
+
: `Interview complete for ${subjectFilter}: no open questions touch it.`);
|
|
288
299
|
}
|
|
289
300
|
else {
|
|
290
301
|
// --facilitate prefers the workshop phrasing and falls back to the
|
|
@@ -14,6 +14,16 @@ export interface CanvasNode {
|
|
|
14
14
|
* profile kind it was authored as.
|
|
15
15
|
*/
|
|
16
16
|
readonly coreKindLabel: string;
|
|
17
|
+
/**
|
|
18
|
+
* The core relationship kinds this node's PATTERN ports, or `[]` where its
|
|
19
|
+
* kind has no pattern with ports (#268 phase 3, ADR 0124).
|
|
20
|
+
*
|
|
21
|
+
* A macro edge needs both ends to port its kind, so an editor offering a
|
|
22
|
+
* palette between two instances intersects the two lists. Two raw groupings
|
|
23
|
+
* permit ten of the eleven kinds, which is no guidance at all; this is what
|
|
24
|
+
* restores the narrowing the relationship table gives everywhere else.
|
|
25
|
+
*/
|
|
26
|
+
readonly portKinds: readonly string[];
|
|
17
27
|
readonly layer: Layer | null;
|
|
18
28
|
readonly aspect: Aspect | null;
|
|
19
29
|
readonly name: string;
|
package/dist/graph-projection.js
CHANGED
|
@@ -119,6 +119,7 @@ const projectConcept = (subjectId, claims, profileContext) => {
|
|
|
119
119
|
kind,
|
|
120
120
|
kindLabel: kindLabelOf(kind),
|
|
121
121
|
coreKindLabel: kindLabelOf(profileContext.conceptKindLineages.get(kind)?.[0] ?? kind),
|
|
122
|
+
portKinds: profileContext.patternPortKinds.get(kind) ?? [],
|
|
122
123
|
layer: profileContext.conceptKindLayers.get(kind) ?? null,
|
|
123
124
|
aspect: profileContext.conceptKindAspects.get(kind) ?? null,
|
|
124
125
|
name: claimValue(nameClaim),
|
|
@@ -87,6 +87,8 @@ export type CatalogueCondition = {
|
|
|
87
87
|
readonly condition: 'unscoped-succession';
|
|
88
88
|
} | {
|
|
89
89
|
readonly condition: 'unchallenged-evidence';
|
|
90
|
+
} | {
|
|
91
|
+
readonly condition: 'has-any-subject';
|
|
90
92
|
};
|
|
91
93
|
/**
|
|
92
94
|
* One observation from the workspace's evidence overlay, reduced to what
|
|
@@ -131,6 +133,11 @@ export interface QuestionCatalogue {
|
|
|
131
133
|
readonly id: string;
|
|
132
134
|
readonly name: string;
|
|
133
135
|
readonly description?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Conditions that must all hold before this wave opens (#334, ADR 0125).
|
|
138
|
+
* Absent means always open, which is what every wave did before this.
|
|
139
|
+
*/
|
|
140
|
+
readonly opensWhen?: readonly CatalogueCondition[];
|
|
134
141
|
}[];
|
|
135
142
|
readonly questions: readonly CatalogueQuestion[];
|
|
136
143
|
}
|
|
@@ -161,6 +168,16 @@ export interface ReportQuestion {
|
|
|
161
168
|
export interface ReportWave {
|
|
162
169
|
readonly id: string;
|
|
163
170
|
readonly name: string;
|
|
171
|
+
/**
|
|
172
|
+
* Whether the wave's gate is met (#334, ADR 0125). A wave with no
|
|
173
|
+
* `opensWhen` is always open.
|
|
174
|
+
*
|
|
175
|
+
* A wave reported `false` carries NO questions and contributes nothing to
|
|
176
|
+
* the summary. Its questions are premature rather than answered, and a
|
|
177
|
+
* progress rail that counted them as answered would flatter itself exactly
|
|
178
|
+
* where someone is most likely to trust it.
|
|
179
|
+
*/
|
|
180
|
+
readonly opened: boolean;
|
|
164
181
|
readonly questions: readonly ReportQuestion[];
|
|
165
182
|
}
|
|
166
183
|
export interface InterrogationSummary {
|
|
@@ -238,6 +238,13 @@ const linkageHits = (index, condition, subjectId, profileContext) => {
|
|
|
238
238
|
};
|
|
239
239
|
const conditionHolds = (index, condition, subjectId, profileContext, evidence) => {
|
|
240
240
|
switch (condition.condition) {
|
|
241
|
+
case 'has-any-subject':
|
|
242
|
+
// The guard a late wave needs to say "only once the model has
|
|
243
|
+
// substance" (#334). An empty model is not an architecture at rest -
|
|
244
|
+
// ADR 0120's reading, which stays true for a model that HAS started -
|
|
245
|
+
// it has not begun, and asking it how the planned architecture becomes
|
|
246
|
+
// real greets someone ahead of question one.
|
|
247
|
+
return index.concepts.size > 0;
|
|
241
248
|
case 'unchallenged-evidence':
|
|
242
249
|
// Fires where the overlay records observations and every one is a
|
|
243
250
|
// frictionless confirmation: no contradicted, unknown, or
|
|
@@ -449,56 +456,71 @@ export function evaluateCatalogue(catalogue, graph, profileContext, evidence) {
|
|
|
449
456
|
let open = 0;
|
|
450
457
|
let openQuestions = 0;
|
|
451
458
|
const applicableQuestions = catalogue.questions.filter((question) => questionIsApplicable(question, graph.profiles));
|
|
459
|
+
const waveOpens = (wave) => wave.opensWhen === undefined ||
|
|
460
|
+
wave.opensWhen.every((condition) => conditionHolds(index, condition, undefined, profileContext, evidence));
|
|
452
461
|
const waves = catalogue.waves.map((wave) => ({
|
|
453
462
|
id: wave.id,
|
|
454
463
|
name: wave.name,
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
464
|
+
opened: waveOpens(wave),
|
|
465
|
+
// A closed wave asks nothing. Its questions are not evaluated at all,
|
|
466
|
+
// rather than evaluated and reported closed - the latter would say they
|
|
467
|
+
// had been asked and answered - so they reach neither the report nor the
|
|
468
|
+
// summary.
|
|
469
|
+
questions: !waveOpens(wave)
|
|
470
|
+
? []
|
|
471
|
+
: applicableQuestions
|
|
472
|
+
.filter((question) => question.wave === wave.id)
|
|
473
|
+
.map((question) => {
|
|
474
|
+
const base = {
|
|
475
|
+
id: question.id,
|
|
476
|
+
scope: question.scope,
|
|
477
|
+
authority: question.authority,
|
|
478
|
+
question: question.question.trim(),
|
|
479
|
+
materiality: question.materiality.trim(),
|
|
480
|
+
resolution: question.resolution.trim(),
|
|
481
|
+
trigger: question.trigger,
|
|
482
|
+
...(question.since === undefined ? {} : { since: question.since }),
|
|
483
|
+
};
|
|
484
|
+
if (question.scope === 'workspace') {
|
|
485
|
+
const isOpen = question.trigger.every((condition) => conditionHolds(index, condition, undefined, profileContext, evidence));
|
|
486
|
+
if (isOpen) {
|
|
487
|
+
open += 1;
|
|
488
|
+
openQuestions += 1;
|
|
489
|
+
}
|
|
490
|
+
return { ...base, open: isOpen };
|
|
473
491
|
}
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
};
|
|
494
|
-
}),
|
|
492
|
+
const matches = selectSubjects(index, question.subjects, profileContext).filter((id) => question.trigger.every((condition) => conditionHolds(index, condition, id, profileContext, evidence)));
|
|
493
|
+
if (matches.length === 0) {
|
|
494
|
+
return { ...base, open: false };
|
|
495
|
+
}
|
|
496
|
+
open += matches.length;
|
|
497
|
+
openQuestions += 1;
|
|
498
|
+
return {
|
|
499
|
+
...base,
|
|
500
|
+
open: true,
|
|
501
|
+
subjects: matches.map((id) => {
|
|
502
|
+
const name = index.nameOf.get(id);
|
|
503
|
+
return {
|
|
504
|
+
id,
|
|
505
|
+
...(name === undefined ? {} : { name }),
|
|
506
|
+
question: renderQuestion(question.question, id, name, describeCounterparts(index, question, id)),
|
|
507
|
+
};
|
|
508
|
+
}),
|
|
509
|
+
};
|
|
510
|
+
}),
|
|
495
511
|
}));
|
|
496
512
|
return {
|
|
497
513
|
format: 'yarramate/interrogation-report/v1',
|
|
498
514
|
catalogue: `${catalogue.id}@${catalogue.version}`,
|
|
499
515
|
semantics: INTERROGATION_SEMANTICS_VERSION,
|
|
500
516
|
summary: {
|
|
501
|
-
|
|
517
|
+
// Questions in OPENED waves only (#334, ADR 0125). A closed wave's
|
|
518
|
+
// questions have not been asked, so counting them in the denominator
|
|
519
|
+
// would report them as answered - "3 of 51" reading as forty-eight
|
|
520
|
+
// done when forty-eight were never put. The denominator grows as the
|
|
521
|
+
// model gains substance and waves open, which is the interview
|
|
522
|
+
// revealing itself rather than a rail filling up.
|
|
523
|
+
questions: waves.reduce((total, wave) => total + wave.questions.length, 0),
|
|
502
524
|
openQuestions,
|
|
503
525
|
open,
|
|
504
526
|
},
|
|
@@ -538,6 +560,16 @@ export function renderInterrogationReport(report) {
|
|
|
538
560
|
];
|
|
539
561
|
for (const wave of report.waves) {
|
|
540
562
|
lines.push('', `== ${wave.name} ==`);
|
|
563
|
+
// A wave that has not opened must not read like one whose questions are
|
|
564
|
+
// all closed (#334). Both carry no OPEN questions, and a bare heading with
|
|
565
|
+
// nothing under it is the more flattering of the two readings: "nothing
|
|
566
|
+
// outstanding here" rather than "nobody has been asked anything here".
|
|
567
|
+
// The same shape - completion inferred from an empty set - was found in a
|
|
568
|
+
// consuming product's wave rail on the same day.
|
|
569
|
+
if (!wave.opened) {
|
|
570
|
+
lines.push(' not yet — this wave has not opened');
|
|
571
|
+
continue;
|
|
572
|
+
}
|
|
541
573
|
for (const question of wave.questions) {
|
|
542
574
|
if (!question.open) {
|
|
543
575
|
lines.push(` closed ${question.id}`);
|
|
@@ -33,9 +33,24 @@ export const connectableKinds = (graph, fromId, toId) => {
|
|
|
33
33
|
!isCoreConceptKindId(to.coreKindLabel)) {
|
|
34
34
|
return [];
|
|
35
35
|
}
|
|
36
|
-
|
|
36
|
+
const permitted = [
|
|
37
37
|
...permittedRelationshipKinds(from.coreKindLabel, to.coreKindLabel),
|
|
38
38
|
].sort();
|
|
39
|
+
// Between two PATTERN INSTANCES the ports are the narrowing (#268 phase 3,
|
|
40
|
+
// ADR 0124). Two raw groupings permit ten of the eleven kinds, which is no
|
|
41
|
+
// guidance at all, and an edge between two instances is a macro edge -
|
|
42
|
+
// which phase 2 expands only where BOTH patterns port its kind, so an
|
|
43
|
+
// offer wider than the intersection would propose edges that expand into
|
|
44
|
+
// nothing. Where either end has no ports there is no macro grain to speak
|
|
45
|
+
// of, and the table's own answer stands.
|
|
46
|
+
if (from.portKinds.length === 0 || to.portKinds.length === 0)
|
|
47
|
+
return permitted;
|
|
48
|
+
const ported = new Set(to.portKinds);
|
|
49
|
+
const narrowed = permitted.filter((kind) => from.portKinds.includes(kind) && ported.has(kind));
|
|
50
|
+
// A pattern whose ports the table forbids between these two would narrow to
|
|
51
|
+
// nothing, and an empty palette makes the edge undrawable rather than
|
|
52
|
+
// guided. The table's answer is the honest fallback.
|
|
53
|
+
return narrowed.length === 0 ? permitted : narrowed;
|
|
39
54
|
};
|
|
40
55
|
/**
|
|
41
56
|
* An id for a new relationship, unique across the graph.
|