yarramate 1.32.0 → 1.33.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 +70 -0
- package/dist/adapters/mcp-cli.js +15 -2
- package/dist/brief.js +4 -1
- package/dist/cli-support.d.ts +1 -1
- package/dist/cli-support.js +1 -1
- package/dist/compiler.js +70 -50
- package/dist/export-command.js +30 -4
- package/dist/graph-projection.d.ts +12 -0
- package/dist/graph-projection.js +7 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/projection.d.ts +5 -0
- package/dist/projection.js +4 -0
- package/dist/relationship-reading.d.ts +12 -1
- package/dist/relationship-reading.js +28 -3
- package/dist/responsibility-kinds.d.ts +23 -0
- package/dist/responsibility-kinds.js +43 -0
- package/dist/responsibility.d.ts +99 -0
- package/dist/responsibility.js +239 -0
- package/dist/schema-validators.generated.js +37 -25
- package/dist/shipped-catalogue.generated.d.ts +1 -1
- package/dist/shipped-catalogue.generated.js +1 -1
- package/dist/shipped-profile.d.ts +21 -0
- package/dist/shipped-profile.js +33 -0
- package/dist/tools/export.d.ts +11 -0
- package/dist/tools/export.js +26 -0
- package/dist/tools/table.js +12 -6
- package/dist/tools-entry.d.ts +3 -1
- package/dist/tools-entry.js +3 -1
- package/dist/visual-app/assets/elk-worker.min-B0rP1gRk.js +22 -0
- package/dist/visual-app/assets/elk.bundled-NyuRbCog.js +24 -0
- package/dist/visual-app/assets/index-Bg4LA2rt.js +373 -0
- package/dist/visual-app/index.html +1 -1
- package/dist/visual-app-lib/editor.js +30866 -30043
- package/dist/visual-app-lib/types/graph-projection.d.ts +12 -0
- package/dist/visual-app-lib/types/projection.d.ts +5 -0
- package/dist/visual-app-lib/types/relationship-reading.d.ts +12 -1
- package/dist/visual-app-lib/types/responsibility-kinds.d.ts +23 -0
- package/dist/visual-app-lib/types/shipped-catalogue.generated.d.ts +1 -1
- package/dist/visual-app-lib/types/shipped-profile.d.ts +21 -0
- package/dist/visual-app-lib/types/visual-app/elk-layout.d.ts +2 -0
- package/dist/visual-app-lib/types/visual-app/graph-canvas.d.ts +10 -1
- package/dist/visual-app-lib/types/visual-app/query-fields.d.ts +3 -2
- package/dist/visual-app-lib/types/visual-app/query-panel.d.ts +3 -1
- package/dist/visual-app-lib/types/visual-app/subject-form.d.ts +5 -0
- package/dist/visual-app-lib/types/visual-app/workspace-state.d.ts +4 -1
- package/docs/CONSUMING-YARRAMATE.md +1 -1
- package/package.json +10 -9
- package/schema/yarramate-projection.schema.json +4 -0
- package/schema/yarramate-responsibility.schema.json +123 -0
- package/schema/yarramate-visual-graph.schema.json +8 -0
- package/skills/yarramate-architecture/SKILL.md +1 -0
- package/dist/visual-app/assets/elk-worker.min-D8OVqK8T.js +0 -22
- package/dist/visual-app/assets/elk.bundled-DwTh4wCo.js +0 -24
- package/dist/visual-app/assets/index-DJYV9FNm.js +0 -373
|
@@ -830,6 +830,76 @@ questions:
|
|
|
830
830
|
Add an owner reference to an accountable actor (evidence such as
|
|
831
831
|
CODEOWNERS may propose it; a human confirms accountability).
|
|
832
832
|
|
|
833
|
+
- id: responsible-missing
|
|
834
|
+
wave: business
|
|
835
|
+
since: "1.33"
|
|
836
|
+
scope: subject
|
|
837
|
+
subjects:
|
|
838
|
+
kinds:
|
|
839
|
+
- yarramate/core@0.1#businessService
|
|
840
|
+
- yarramate/core@0.1#applicationService
|
|
841
|
+
- yarramate/core@0.1#applicationComponent
|
|
842
|
+
- yarramate/core@0.1#capability
|
|
843
|
+
trigger:
|
|
844
|
+
- condition: missing-linkage
|
|
845
|
+
kinds:
|
|
846
|
+
- yarramate/policy@0.2#responsible
|
|
847
|
+
direction: incoming
|
|
848
|
+
counterpartKinds:
|
|
849
|
+
- yarramate/core@0.1#businessActor
|
|
850
|
+
- yarramate/core@0.1#businessRole
|
|
851
|
+
- yarramate/core@0.1#businessCollaboration
|
|
852
|
+
- yarramate/core@0.1#stakeholder
|
|
853
|
+
question: >-
|
|
854
|
+
Who is responsible for {subject.name}?
|
|
855
|
+
askPlain: >-
|
|
856
|
+
Who actually builds, runs or delivers "{subject.name}" day to day?
|
|
857
|
+
materiality: >-
|
|
858
|
+
Accountability says whose desk a failure lands on; responsibility says
|
|
859
|
+
whose hands are on it. A subject with nobody responsible has nobody to
|
|
860
|
+
hand the work to, and a RACI row with no R is a gap the matrix reports.
|
|
861
|
+
authority: either
|
|
862
|
+
resolution: >-
|
|
863
|
+
Add a `responsible` relationship from the actor, role or collaboration
|
|
864
|
+
that does the work to the subject (a support contract or CODEOWNERS may
|
|
865
|
+
propose it; a person confirms it).
|
|
866
|
+
- id: role-idle
|
|
867
|
+
wave: business
|
|
868
|
+
since: "1.33"
|
|
869
|
+
scope: subject
|
|
870
|
+
subjects:
|
|
871
|
+
kinds:
|
|
872
|
+
- yarramate/core@0.1#businessActor
|
|
873
|
+
- yarramate/core@0.1#businessRole
|
|
874
|
+
- yarramate/core@0.1#businessCollaboration
|
|
875
|
+
trigger:
|
|
876
|
+
- condition: missing-reference
|
|
877
|
+
predicate: yarramate/ownership/owner
|
|
878
|
+
direction: incoming
|
|
879
|
+
- condition: missing-relationship
|
|
880
|
+
kinds:
|
|
881
|
+
- yarramate/policy@0.2#responsible
|
|
882
|
+
- yarramate/policy@0.2#consulted
|
|
883
|
+
- yarramate/policy@0.2#informed
|
|
884
|
+
direction: outgoing
|
|
885
|
+
- condition: missing-relationship
|
|
886
|
+
kinds:
|
|
887
|
+
- yarramate/core@0.1#serving
|
|
888
|
+
direction: incoming
|
|
889
|
+
question: >-
|
|
890
|
+
What does {subject.name} answer for?
|
|
891
|
+
askPlain: >-
|
|
892
|
+
"{subject.name}" is in the model but owns nothing, is responsible for
|
|
893
|
+
nothing, and is neither consulted nor informed about anything. What is
|
|
894
|
+
their part, or should they go?
|
|
895
|
+
materiality: >-
|
|
896
|
+
A person with no letter is either missing the edges a delivery depends
|
|
897
|
+
on or a name that outlived its role. A served actor is a consumer, not
|
|
898
|
+
a responsibility holder, and is not asked.
|
|
899
|
+
authority: human
|
|
900
|
+
resolution: >-
|
|
901
|
+
Give the person a letter (an owner claim on what they answer for, or a
|
|
902
|
+
responsible, consulted or informed relationship) or retire the subject.
|
|
833
903
|
- id: actor-unassigned
|
|
834
904
|
wave: business
|
|
835
905
|
since: "0.1"
|
package/dist/adapters/mcp-cli.js
CHANGED
|
@@ -148,8 +148,8 @@ const runExport = (input, tool, root) => {
|
|
|
148
148
|
stderr: '',
|
|
149
149
|
};
|
|
150
150
|
}
|
|
151
|
-
// A text kind under `out`: markdown and graph are one file, rtm
|
|
152
|
-
// briefs a directory, as the CLI lays them out.
|
|
151
|
+
// A text kind under `out`: markdown and graph are one file, rtm,
|
|
152
|
+
// responsibility and briefs a directory, as the CLI lays them out.
|
|
153
153
|
if (kind === 'markdown' || kind === 'graph') {
|
|
154
154
|
mkdirSync(dirname(target), { recursive: true });
|
|
155
155
|
writeFileSync(target, outcome.text, 'utf8');
|
|
@@ -172,6 +172,19 @@ const runExport = (input, tool, root) => {
|
|
|
172
172
|
stderr: '',
|
|
173
173
|
};
|
|
174
174
|
}
|
|
175
|
+
if (kind === 'responsibility') {
|
|
176
|
+
const result = outcome.result;
|
|
177
|
+
mkdirSync(target, { recursive: true });
|
|
178
|
+
writeFileSync(join(target, 'RESPONSIBILITY.md'), outcome.text, 'utf8');
|
|
179
|
+
if (result !== undefined) {
|
|
180
|
+
writeFileSync(join(target, 'responsibility.json'), `${JSON.stringify(result.matrix, null, 2)}\n`, 'utf8');
|
|
181
|
+
}
|
|
182
|
+
return {
|
|
183
|
+
exitCode: 0,
|
|
184
|
+
stdout: `Wrote RESPONSIBILITY.md and responsibility.json to ${out}\n`,
|
|
185
|
+
stderr: '',
|
|
186
|
+
};
|
|
187
|
+
}
|
|
175
188
|
if (kind === 'briefs') {
|
|
176
189
|
const result = outcome.result;
|
|
177
190
|
mkdirSync(target, { recursive: true });
|
package/dist/brief.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { conceptKinds } from './profile.js';
|
|
2
|
-
import { RELATIONSHIP_READING, humanizeKind } from './relationship-reading.js';
|
|
2
|
+
import { EXTENSION_READING, RELATIONSHIP_READING, humanizeKind } from './relationship-reading.js';
|
|
3
3
|
const coreKindNames = new Map(conceptKinds.map(({ id, name }) => [id, name]));
|
|
4
4
|
const motivationKindIds = new Set(conceptKinds
|
|
5
5
|
.filter(({ layer }) => layer === 'motivation')
|
|
@@ -66,6 +66,9 @@ const relationshipPhrase = (coreKind, fallbackKind, mode, content) => {
|
|
|
66
66
|
if (coreKind === 'flow') {
|
|
67
67
|
return content === undefined ? 'flows to' : `sends ${content} to`;
|
|
68
68
|
}
|
|
69
|
+
const extension = EXTENSION_READING[fallbackKind];
|
|
70
|
+
if (extension !== undefined)
|
|
71
|
+
return extension;
|
|
69
72
|
const reading = coreKind === undefined ? undefined : RELATIONSHIP_READING[coreKind];
|
|
70
73
|
return reading ?? humanizeKind(fallbackKind);
|
|
71
74
|
};
|
package/dist/cli-support.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export interface CliResult {
|
|
|
7
7
|
export declare const isMainModule: (moduleUrl: string, entrypoint: string | undefined) => boolean;
|
|
8
8
|
export declare const packageVersion: string;
|
|
9
9
|
export declare const versionResult: (binary: string) => CliResult;
|
|
10
|
-
export declare const usage = "Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <subject-id>] [--catalogue <catalogue.yaml>] [--facilitate] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> \"<free text>\" | <subject-id> ... | <projection.yaml> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise \"<topic>\" [--budget <tokens>] [--neighbours <n>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --where \"<free text>\" | <subject-id> ... [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml> [--json | --text]\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export rtm <workspace.yaml> --out <directory>\n yarramate export xlsx <projection.yaml> <workspace.yaml> --out <file>\n yarramate import xlsx <workbook.xlsx> <workspace.yaml> [--json]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n";
|
|
10
|
+
export declare const usage = "Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <subject-id>] [--catalogue <catalogue.yaml>] [--facilitate] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> \"<free text>\" | <subject-id> ... | <projection.yaml> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise \"<topic>\" [--budget <tokens>] [--neighbours <n>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --where \"<free text>\" | <subject-id> ... [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml> [--json | --text]\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export rtm <workspace.yaml> --out <directory>\n yarramate export responsibility <projection.yaml> <workspace.yaml> --out <directory>\n yarramate export xlsx <projection.yaml> <workspace.yaml> --out <file>\n yarramate import xlsx <workbook.xlsx> <workspace.yaml> [--json]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n";
|
|
11
11
|
export declare const diagnosticJson: (diagnostics: unknown) => string;
|
|
12
12
|
export declare const checkResultJson: (ok: boolean, diagnostics: unknown, counted?: {
|
|
13
13
|
readonly documents: number;
|
package/dist/cli-support.js
CHANGED
|
@@ -22,7 +22,7 @@ export const versionResult = (binary) => ({
|
|
|
22
22
|
stdout: `${binary} ${packageVersion}\n`,
|
|
23
23
|
stderr: '',
|
|
24
24
|
});
|
|
25
|
-
export const usage = 'Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <subject-id>] [--catalogue <catalogue.yaml>] [--facilitate] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> "<free text>" | <subject-id> ... | <projection.yaml> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise "<topic>" [--budget <tokens>] [--neighbours <n>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --where "<free text>" | <subject-id> ... [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml> [--json | --text]\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export rtm <workspace.yaml> --out <directory>\n yarramate export xlsx <projection.yaml> <workspace.yaml> --out <file>\n yarramate import xlsx <workbook.xlsx> <workspace.yaml> [--json]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n';
|
|
25
|
+
export const usage = 'Usage:\n yarramate init <directory> [--no-pointer]\n yarramate design <workspace.yaml> [--subject <subject-id>] [--catalogue <catalogue.yaml>] [--facilitate] [--json]\n yarramate apply <operations.yaml> <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> [--json]\n yarramate ask <workspace.yaml> "<free text>" | <subject-id> ... | <projection.yaml> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate ask <workspace.yaml> --subjects [--kind <term>] [--status <status>] [--json]\n yarramate ask <workspace.yaml> --kinds [--json]\n yarramate ask <workspace.yaml> --advise "<topic>" [--budget <tokens>] [--neighbours <n>] [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --where "<free text>" | <subject-id> ... [--json]\n yarramate ask <workspace.yaml> --next [--json]\n yarramate ask <workspace.yaml> --open [--catalogue <catalogue.yaml>] [--json]\n yarramate ask <workspace.yaml> --compare <from-state> <to-state> [--json]\n yarramate ask <workspace.yaml> --changed <git-range> [--budget <tokens>] [--neighbours <n>] [--json]\n yarramate check <source.yaml> [source.yaml ...] [--json] [--strict]\n yarramate reconcile <workspace.yaml> [--json | --text]\n yarramate export graph <workspace.yaml> [--out <file>]\n yarramate export markdown <projection.yaml> <workspace.yaml> [--out <file>]\n yarramate export markdown --changed <git-range> <workspace.yaml> [--out <file>]\n yarramate export briefs <projection.yaml> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export briefs --changed <git-range> <workspace.yaml> --out <directory> [--budget <tokens>]\n yarramate export rtm <workspace.yaml> --out <directory>\n yarramate export responsibility <projection.yaml> <workspace.yaml> --out <directory>\n yarramate export xlsx <projection.yaml> <workspace.yaml> --out <file>\n yarramate import xlsx <workbook.xlsx> <workspace.yaml> [--json]\n yarramate export likec4 <likec4-project.yaml> <output-dir> <workspace.yaml> [--changed <git-range>]\n';
|
|
26
26
|
export const diagnosticJson = (diagnostics) => `${JSON.stringify({
|
|
27
27
|
format: 'yarramate/diagnostic-result/v1',
|
|
28
28
|
diagnostics,
|
package/dist/compiler.js
CHANGED
|
@@ -3,7 +3,7 @@ import { conceptKinds, relationshipPolicies, } from './profile.js';
|
|
|
3
3
|
import { isCoreConceptKindId, matrixEndpointAspects, permittedRelationshipKinds as tablePermittedKinds, } from './relationship-matrix.js';
|
|
4
4
|
import { closestCandidate, describeSchemaViolation, } from './source-document.js';
|
|
5
5
|
import { ATTESTATION_PREDICATE_PREFIX, attestationClaimValue } from './graph-claims.js';
|
|
6
|
-
import {
|
|
6
|
+
import { shippedProfileOf } from './shipped-profile.js';
|
|
7
7
|
import { validateDocument, validateProfile, validatePattern } from './schema-validation.js';
|
|
8
8
|
const coreProfile = 'yarramate/core@0.1';
|
|
9
9
|
/**
|
|
@@ -371,58 +371,78 @@ function compileWorkspaceResolved(parsed) {
|
|
|
371
371
|
const identity = `${value.id}@${value.version}`;
|
|
372
372
|
pendingProfiles.push({ input, value, identity, positionFor });
|
|
373
373
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
const
|
|
394
|
-
if (
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
374
|
+
// The shipped optional profiles (ADR 0095; policy@0.2 per ADR 0159). Each
|
|
375
|
+
// is injected when a document selects it or a profile extends it, and a
|
|
376
|
+
// shipped profile's own parent follows it in, so `extends:
|
|
377
|
+
// yarramate/policy@0.2` brings 0.1 along. A workspace file that declares
|
|
378
|
+
// the same identity wins; the shipped copy is not added beside it.
|
|
379
|
+
//
|
|
380
|
+
// This probe runs BEFORE the document gate that rejects a source whose
|
|
381
|
+
// schema check failed, so it has to hold its own precondition: a source
|
|
382
|
+
// that composes to anything but a mapping - an empty file, a comment-only
|
|
383
|
+
// one, a bare scalar - selects no profile at all. It used to read
|
|
384
|
+
// `.profile` through an `as` cast, which is what hid the null from the
|
|
385
|
+
// typechecker, and an empty document crashed the whole compile with a
|
|
386
|
+
// `TypeError` instead of the `YM201 must be object` its schema already
|
|
387
|
+
// produces. Every other consumer of a parsed entry checks its diagnostics
|
|
388
|
+
// first (the profile walk above, the pattern walk below); this one could
|
|
389
|
+
// not, because it runs before that gate exists, so it narrows instead.
|
|
390
|
+
const declaredIdentities = new Set(pendingProfiles.map(({ identity }) => identity));
|
|
391
|
+
const requestedIdentities = new Set();
|
|
392
|
+
for (const { entry } of documentInputs) {
|
|
393
|
+
const value = entry.value;
|
|
394
|
+
if (typeof value !== 'object' || value === null)
|
|
395
|
+
continue;
|
|
396
|
+
const profile = value.profile;
|
|
397
|
+
if (typeof profile === 'string')
|
|
398
|
+
requestedIdentities.add(profile);
|
|
399
|
+
}
|
|
400
|
+
for (const { value } of pendingProfiles)
|
|
401
|
+
requestedIdentities.add(value.extends);
|
|
402
|
+
const wantedShipped = [];
|
|
403
|
+
const want = (identity) => {
|
|
404
|
+
if (declaredIdentities.has(identity) || wantedShipped.includes(identity))
|
|
405
|
+
return;
|
|
406
|
+
const shipped = shippedProfileOf(identity);
|
|
407
|
+
if (shipped === undefined)
|
|
408
|
+
return;
|
|
409
|
+
wantedShipped.push(identity);
|
|
410
|
+
want(shipped.extends);
|
|
411
|
+
};
|
|
412
|
+
for (const identity of requestedIdentities)
|
|
413
|
+
want(identity);
|
|
414
|
+
for (const identity of wantedShipped) {
|
|
415
|
+
const shipped = shippedProfileOf(identity);
|
|
416
|
+
const input = {
|
|
417
|
+
path: `yarramate:profile:${identity}`,
|
|
418
|
+
source: shipped.source,
|
|
419
|
+
};
|
|
420
|
+
const { entry, fresh } = parseWorkspaceSource(input);
|
|
421
|
+
const value = entry.value;
|
|
422
|
+
if (entry.schemaDiagnostics.length > 0) {
|
|
423
|
+
profileDiagnostics.push(...entry.schemaDiagnostics);
|
|
424
|
+
}
|
|
425
|
+
else if (!validateProfile(value)) {
|
|
426
|
+
for (const error of validateProfile.errors ?? []) {
|
|
427
|
+
profileDiagnostics.push({
|
|
428
|
+
severity: 'error',
|
|
429
|
+
code: 'YM201',
|
|
430
|
+
message: `Profile schema violation: ${describeSchemaViolation(error)}`,
|
|
431
|
+
path: input.path,
|
|
432
|
+
pointer: error.instancePath || '/',
|
|
433
|
+
line: 1,
|
|
434
|
+
column: 1,
|
|
423
435
|
});
|
|
424
436
|
}
|
|
425
437
|
}
|
|
438
|
+
else {
|
|
439
|
+
pendingProfiles.push({
|
|
440
|
+
input,
|
|
441
|
+
value,
|
|
442
|
+
identity,
|
|
443
|
+
positionFor: positionReader(input.source, entry.positions, fresh),
|
|
444
|
+
});
|
|
445
|
+
}
|
|
426
446
|
}
|
|
427
447
|
let unresolvedProfiles = pendingProfiles.sort((left, right) => left.identity.localeCompare(right.identity) ||
|
|
428
448
|
left.input.path.localeCompare(right.input.path));
|
package/dist/export-command.js
CHANGED
|
@@ -8,7 +8,7 @@ import { humanDiagnostics, usage, } from './cli-support.js';
|
|
|
8
8
|
import { evaluateProjection, renderProjectionMarkdown } from './projection.js';
|
|
9
9
|
import { createFileSystemStore } from './source-store.js';
|
|
10
10
|
import { posixDirectoryOf } from './apply-command.js';
|
|
11
|
-
import { briefsFromResult, exportBriefs, exportGraph, exportMarkdown, exportRtm, exportWorkbook, } from './tools/export.js';
|
|
11
|
+
import { briefsFromResult, exportBriefs, exportGraph, exportMarkdown, exportResponsibility, exportRtm, exportWorkbook, } from './tools/export.js';
|
|
12
12
|
import { compileOf, readSource, } from './tools/workspace.js';
|
|
13
13
|
import { loadWorkspaceManifest } from './workspace.js';
|
|
14
14
|
// Every kind is derived in `tools/export.ts` (ADR 0156): this command
|
|
@@ -70,7 +70,15 @@ const parseExportOptions = (options) => {
|
|
|
70
70
|
export function runExportCommand(options, cwd) {
|
|
71
71
|
const [kind, ...rest] = options;
|
|
72
72
|
if (kind === undefined ||
|
|
73
|
-
![
|
|
73
|
+
![
|
|
74
|
+
'graph',
|
|
75
|
+
'markdown',
|
|
76
|
+
'briefs',
|
|
77
|
+
'rtm',
|
|
78
|
+
'responsibility',
|
|
79
|
+
'likec4',
|
|
80
|
+
'xlsx',
|
|
81
|
+
].includes(kind)) {
|
|
74
82
|
return { exitCode: 2, stdout: '', stderr: usage };
|
|
75
83
|
}
|
|
76
84
|
const parsed = parseExportOptions(rest);
|
|
@@ -121,9 +129,13 @@ export function runExportCommand(options, cwd) {
|
|
|
121
129
|
if (parsed.positionals.length !== expectedPositionals ||
|
|
122
130
|
workspacePath === undefined ||
|
|
123
131
|
parsed.json ||
|
|
124
|
-
(usesChanged &&
|
|
132
|
+
(usesChanged &&
|
|
133
|
+
(kind === 'graph' || kind === 'rtm' || kind === 'responsibility')) ||
|
|
125
134
|
(parsed.budget !== undefined && kind !== 'briefs') ||
|
|
126
|
-
((kind === 'briefs' ||
|
|
135
|
+
((kind === 'briefs' ||
|
|
136
|
+
kind === 'rtm' ||
|
|
137
|
+
kind === 'responsibility' ||
|
|
138
|
+
kind === 'xlsx') &&
|
|
127
139
|
parsed.out === undefined)) {
|
|
128
140
|
return { exitCode: 2, stdout: '', stderr: usage };
|
|
129
141
|
}
|
|
@@ -171,6 +183,20 @@ export function runExportCommand(options, cwd) {
|
|
|
171
183
|
stderr: '',
|
|
172
184
|
};
|
|
173
185
|
}
|
|
186
|
+
if (kind === 'responsibility') {
|
|
187
|
+
const exported = exportResponsibility(tool, projectionPath);
|
|
188
|
+
if (!exported.ok)
|
|
189
|
+
return failedTool(exported);
|
|
190
|
+
const { markdown, matrix } = exported.result;
|
|
191
|
+
writeText(join(parsed.out, 'RESPONSIBILITY.md'), markdown);
|
|
192
|
+
writeText(join(parsed.out, 'responsibility.json'), `${JSON.stringify(matrix, null, 2)}\n`);
|
|
193
|
+
const gaps = matrix.summary.noAccountable + matrix.summary.noResponsible;
|
|
194
|
+
return {
|
|
195
|
+
exitCode: 0,
|
|
196
|
+
stdout: `Wrote RESPONSIBILITY.md and responsibility.json (${matrix.summary.rows} row${matrix.summary.rows === 1 ? '' : 's'}, ${gaps} gap${gaps === 1 ? '' : 's'}) to ${parsed.out}\n`,
|
|
197
|
+
stderr: '',
|
|
198
|
+
};
|
|
199
|
+
}
|
|
174
200
|
if (kind === 'graph') {
|
|
175
201
|
const exported = exportGraph(tool);
|
|
176
202
|
if (!exported.ok)
|
|
@@ -67,6 +67,17 @@ export interface CanvasEdge {
|
|
|
67
67
|
readonly kind: string;
|
|
68
68
|
readonly kindLabel: string;
|
|
69
69
|
readonly coreKindLabel: string;
|
|
70
|
+
/**
|
|
71
|
+
* The kind whose reading the edge label speaks (ADR 0159): an extension
|
|
72
|
+
* identity with a reading of its own, else `coreKindLabel`.
|
|
73
|
+
*/
|
|
74
|
+
readonly readingKind?: string;
|
|
75
|
+
/**
|
|
76
|
+
* The responsibility letter this edge carries (#557): R, C or I for the
|
|
77
|
+
* shipped responsibility kinds and their subkinds, null for every other
|
|
78
|
+
* kind. The canvas draws these only when the view asks (`showResponsibility`).
|
|
79
|
+
*/
|
|
80
|
+
readonly responsibility?: ResponsibilityLetter | null;
|
|
70
81
|
readonly from: string;
|
|
71
82
|
readonly to: string;
|
|
72
83
|
readonly name: string | null;
|
|
@@ -84,4 +95,5 @@ export interface CanvasGraph {
|
|
|
84
95
|
readonly nodes: readonly CanvasNode[];
|
|
85
96
|
readonly edges: readonly CanvasEdge[];
|
|
86
97
|
}
|
|
98
|
+
import { type ResponsibilityLetter } from './responsibility-kinds.js';
|
|
87
99
|
export declare function projectGraphForCanvas(graph: SemanticGraph, profileContext: ResolvedProfileContext): CanvasGraph;
|
package/dist/graph-projection.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { ATTESTATION_PREDICATE_PREFIX, parseAttestationClaimValue, parseConstraintExpectsValue, } from './graph-claims.js';
|
|
2
2
|
import { kindLabelOf } from './kind-label.js';
|
|
3
|
+
import { readingKindOf } from './relationship-reading.js';
|
|
4
|
+
import { responsibilityLetterOf } from './responsibility-kinds.js';
|
|
3
5
|
const CONCEPT_KIND_PREDICATE = 'yarramate/concept/kind';
|
|
4
6
|
const CONCEPT_NAME_PREDICATE = 'yarramate/concept/name';
|
|
5
7
|
const CONCEPT_DESCRIPTION_PREDICATE = 'yarramate/concept/description';
|
|
@@ -170,6 +172,8 @@ const projectRelationship = (relationshipId, allClaims, ownClaims, profileContex
|
|
|
170
172
|
throw new Error(`Relationship "${relationshipId}" is missing its defining claim`);
|
|
171
173
|
}
|
|
172
174
|
const kind = definingClaim.predicate;
|
|
175
|
+
const lineage = profileContext.relationshipKindLineages.get(kind);
|
|
176
|
+
const coreKindLabel = kindLabelOf(lineage?.[0] ?? kind);
|
|
173
177
|
const nameClaim = ownClaims.find((claim) => claim.predicate === RELATIONSHIP_NAME_PREDICATE);
|
|
174
178
|
const descriptionClaim = ownClaims.find((claim) => claim.predicate === RELATIONSHIP_DESCRIPTION_PREDICATE);
|
|
175
179
|
const modeClaim = ownClaims.find((claim) => claim.predicate === ACCESS_MODE_PREDICATE);
|
|
@@ -181,7 +185,9 @@ const projectRelationship = (relationshipId, allClaims, ownClaims, profileContex
|
|
|
181
185
|
document: definingClaim.source.path,
|
|
182
186
|
kind,
|
|
183
187
|
kindLabel: kindLabelOf(kind),
|
|
184
|
-
coreKindLabel
|
|
188
|
+
coreKindLabel,
|
|
189
|
+
readingKind: readingKindOf(lineage, coreKindLabel),
|
|
190
|
+
responsibility: responsibilityLetterOf(lineage, kind),
|
|
185
191
|
from: definingClaim.subject,
|
|
186
192
|
to: claimRef(definingClaim),
|
|
187
193
|
name: nameClaim === undefined ? null : claimValue(nameClaim),
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export { constraintExpectsPredicate, reconcileEvidenceReports, type AssertedRela
|
|
|
10
10
|
export { deriveAttestationStaleness } from './attestation-staleness.js';
|
|
11
11
|
export { deriveArtifactCoverage, type ArtifactCoverage, type CoverageScopePattern, } from './artifact-coverage.js';
|
|
12
12
|
export { buildRtm, renderRtmMarkdown, type RequirementsTraceabilityMatrix, type RtmAttestation, type RtmContextEntry, type RtmDescopedEntry, type RtmEvidenceVerdict, type RtmLineageEntry, type RtmRealizer, type RtmRow, type RtmSource, } from './rtm.js';
|
|
13
|
+
export { buildResponsibilityMatrix, renderResponsibilityMarkdown, type RaciLetter, type ResponsibilityCell, type ResponsibilityCellSource, type ResponsibilityMatrix, type ResponsibilityOptions, type ResponsibilityPerson, type ResponsibilityRow, type ResponsibilitySource, } from './responsibility.js';
|
|
14
|
+
export { PEOPLE_KINDS, RESPONSIBILITY_KINDS, RESPONSIBILITY_PROFILE, responsibilityLetterOf, type ResponsibilityLetter, } from './responsibility-kinds.js';
|
|
13
15
|
export type { CompilationCache, CompilationResult, ContextualCompilationResult, IncrementalCompilationResult, ParsedWorkspaceSource, PatternMembership, PatternPortShape, PatternShape, PatternSlotShape, PatternVacancy, PatternWireShape, Diagnostic, GraphClaim, GraphSource, SemanticGraph, ResolvedProfileContext, WorkspaceSource, } from './compiler.js';
|
|
14
16
|
export { canonicalProjection, evaluateProjection, explainProjection, instanceClosureOf, loadProjection, renderProjectionMarkdown, type ConceptFacet, type ProjectionExclusion, } from './projection.js';
|
|
15
17
|
export { loadAdapterMapping, validateAdapterMapping, validateAdapterMappings, type AdapterMapping, type AdapterMappingLoadResult, type AdapterMappingValidationResult, type AdapterMappingsValidationResult, type AdapterSubjectMapping, } from './adapter-mapping.js';
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,8 @@ export { constraintExpectsPredicate, reconcileEvidenceReports, } from './reconci
|
|
|
10
10
|
export { deriveAttestationStaleness } from './attestation-staleness.js';
|
|
11
11
|
export { deriveArtifactCoverage, } from './artifact-coverage.js';
|
|
12
12
|
export { buildRtm, renderRtmMarkdown, } from './rtm.js';
|
|
13
|
+
export { buildResponsibilityMatrix, renderResponsibilityMarkdown, } from './responsibility.js';
|
|
14
|
+
export { PEOPLE_KINDS, RESPONSIBILITY_KINDS, RESPONSIBILITY_PROFILE, responsibilityLetterOf, } from './responsibility-kinds.js';
|
|
13
15
|
export { canonicalProjection, evaluateProjection, explainProjection, instanceClosureOf, loadProjection, renderProjectionMarkdown, } from './projection.js';
|
|
14
16
|
export { loadAdapterMapping, validateAdapterMapping, validateAdapterMappings, } from './adapter-mapping.js';
|
|
15
17
|
export { createFileSystemStore, } from './source-store.js';
|
package/dist/projection.d.ts
CHANGED
|
@@ -84,6 +84,11 @@ export interface ProjectionDefinition {
|
|
|
84
84
|
readonly showLifecycle?: boolean;
|
|
85
85
|
readonly showEvidence?: boolean;
|
|
86
86
|
readonly showOwnership?: boolean;
|
|
87
|
+
/**
|
|
88
|
+
* Whether responsibility edges draw on the canvas (#557, ADR 0159). Off
|
|
89
|
+
* when absent: the subject's properties read the letters either way.
|
|
90
|
+
*/
|
|
91
|
+
readonly showResponsibility?: boolean;
|
|
87
92
|
/**
|
|
88
93
|
* Whether an unnamed relationship is labelled with its reading - "serves",
|
|
89
94
|
* "served by", "realizes" - or left to its line style and arrowhead
|
package/dist/projection.js
CHANGED
|
@@ -71,6 +71,7 @@ export function canonicalProjection(projection) {
|
|
|
71
71
|
...(presentation.showLifecycle === undefined ? {} : { showLifecycle: presentation.showLifecycle }),
|
|
72
72
|
...(presentation.showEvidence === undefined ? {} : { showEvidence: presentation.showEvidence }),
|
|
73
73
|
...(presentation.showOwnership === undefined ? {} : { showOwnership: presentation.showOwnership }),
|
|
74
|
+
...(presentation.showResponsibility === undefined ? {} : { showResponsibility: presentation.showResponsibility }),
|
|
74
75
|
...(presentation.showKindLabels === undefined ? {} : { showKindLabels: presentation.showKindLabels }),
|
|
75
76
|
...(presentation.notation === undefined ? {} : { notation: presentation.notation }),
|
|
76
77
|
},
|
|
@@ -637,6 +638,9 @@ export function evaluateProjection(graph, projection, profileContext, membership
|
|
|
637
638
|
...(projection.presentation.showOwnership === undefined
|
|
638
639
|
? {}
|
|
639
640
|
: { showOwnership: projection.presentation.showOwnership }),
|
|
641
|
+
...(projection.presentation.showResponsibility === undefined
|
|
642
|
+
? {}
|
|
643
|
+
: { showResponsibility: projection.presentation.showResponsibility }),
|
|
640
644
|
...(projection.presentation.showKindLabels === undefined
|
|
641
645
|
? {}
|
|
642
646
|
: { showKindLabels: projection.presentation.showKindLabels }),
|
|
@@ -13,6 +13,17 @@
|
|
|
13
13
|
* reads an access.
|
|
14
14
|
*/
|
|
15
15
|
export declare const RELATIONSHIP_READING: Readonly<Record<string, string>>;
|
|
16
|
+
/**
|
|
17
|
+
* Readings for the extension kinds the package ships (ADR 0159), keyed by
|
|
18
|
+
* their full identity: a profile's subkind of one of these reads the same,
|
|
19
|
+
* which `readingKindOf` resolves through the lineage.
|
|
20
|
+
*/
|
|
21
|
+
export declare const EXTENSION_READING: Readonly<Record<string, string>>;
|
|
22
|
+
/**
|
|
23
|
+
* The kind whose reading an edge speaks: the most specific member of the
|
|
24
|
+
* lineage (ancestor-first) that has a reading of its own, else the core kind.
|
|
25
|
+
*/
|
|
26
|
+
export declare const readingKindOf: (lineage: readonly string[] | undefined, coreKind: string) => string;
|
|
16
27
|
export declare const REVERSED_READING: Readonly<Record<string, string>>;
|
|
17
28
|
/**
|
|
18
29
|
* `acme/p@1#applicationComponent` reads "application component" and
|
|
@@ -25,4 +36,4 @@ export declare const humanizeKind: (kind: string) => string;
|
|
|
25
36
|
* and gets it only where one exists; a kind with no passive reading keeps its
|
|
26
37
|
* active one, so a caller can pass the layering's answer straight through.
|
|
27
38
|
*/
|
|
28
|
-
export declare const relationshipReading: (
|
|
39
|
+
export declare const relationshipReading: (kind: string, reversed?: boolean) => string;
|
|
@@ -25,6 +25,30 @@ export const RELATIONSHIP_READING = {
|
|
|
25
25
|
influence: 'influences',
|
|
26
26
|
association: 'is associated with',
|
|
27
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* Readings for the extension kinds the package ships (ADR 0159), keyed by
|
|
30
|
+
* their full identity: a profile's subkind of one of these reads the same,
|
|
31
|
+
* which `readingKindOf` resolves through the lineage.
|
|
32
|
+
*/
|
|
33
|
+
export const EXTENSION_READING = {
|
|
34
|
+
'yarramate/policy@0.2#responsible': 'is responsible for',
|
|
35
|
+
'yarramate/policy@0.2#consulted': 'is consulted on',
|
|
36
|
+
'yarramate/policy@0.2#informed': 'is informed of',
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* The kind whose reading an edge speaks: the most specific member of the
|
|
40
|
+
* lineage (ancestor-first) that has a reading of its own, else the core kind.
|
|
41
|
+
*/
|
|
42
|
+
export const readingKindOf = (lineage, coreKind) => {
|
|
43
|
+
if (lineage !== undefined) {
|
|
44
|
+
for (let index = lineage.length - 1; index >= 0; index -= 1) {
|
|
45
|
+
const member = lineage[index];
|
|
46
|
+
if (EXTENSION_READING[member] !== undefined)
|
|
47
|
+
return member;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return coreKind;
|
|
51
|
+
};
|
|
28
52
|
export const REVERSED_READING = {
|
|
29
53
|
serving: 'served by',
|
|
30
54
|
realization: 'realized by',
|
|
@@ -47,6 +71,7 @@ export const humanizeKind = (kind) => {
|
|
|
47
71
|
* and gets it only where one exists; a kind with no passive reading keeps its
|
|
48
72
|
* active one, so a caller can pass the layering's answer straight through.
|
|
49
73
|
*/
|
|
50
|
-
export const relationshipReading = (
|
|
51
|
-
|
|
52
|
-
|
|
74
|
+
export const relationshipReading = (kind, reversed = false) => (reversed ? REVERSED_READING[kind] : undefined) ??
|
|
75
|
+
EXTENSION_READING[kind] ??
|
|
76
|
+
RELATIONSHIP_READING[kind] ??
|
|
77
|
+
humanizeKind(kind);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three responsibility relationship kinds and the letters they carry
|
|
3
|
+
* (#557, ADR 0159): `yarramate/policy@0.2#responsible`, `#consulted` and
|
|
4
|
+
* `#informed`, each a subkind of core `association` from a person to the
|
|
5
|
+
* subject they answer for. Accountable is not a kind: it is the existing
|
|
6
|
+
* `yarramate/ownership/owner` claim. Pure, so the canvas projection, the
|
|
7
|
+
* matrix builder and the editor read one table.
|
|
8
|
+
*/
|
|
9
|
+
export declare const RESPONSIBILITY_PROFILE = "yarramate/policy@0.2";
|
|
10
|
+
export type ResponsibilityLetter = 'R' | 'C' | 'I';
|
|
11
|
+
export declare const RESPONSIBILITY_KINDS: Readonly<Record<'responsible' | 'consulted' | 'informed', string>>;
|
|
12
|
+
export declare const RESPONSIBILITY_LETTERS: Readonly<Record<string, ResponsibilityLetter>>;
|
|
13
|
+
export declare const OWNER_PREDICATE = "yarramate/ownership/owner";
|
|
14
|
+
/** The core kinds a person subject may be, ancestors of any profile's own. */
|
|
15
|
+
export declare const PEOPLE_KINDS: readonly string[];
|
|
16
|
+
/**
|
|
17
|
+
* The letter a relationship kind carries, read through its lineage
|
|
18
|
+
* (ancestor-first) so a profile's own subkind of `responsible` is still an
|
|
19
|
+
* R; `null` for every other kind.
|
|
20
|
+
*/
|
|
21
|
+
export declare const responsibilityLetterOf: (lineage: readonly string[] | undefined, kind: string) => ResponsibilityLetter | null;
|
|
22
|
+
/** Whether a concept kind is a person, read through its lineage. */
|
|
23
|
+
export declare const isPeopleKind: (lineage: readonly string[] | undefined, kind: string) => boolean;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The three responsibility relationship kinds and the letters they carry
|
|
3
|
+
* (#557, ADR 0159): `yarramate/policy@0.2#responsible`, `#consulted` and
|
|
4
|
+
* `#informed`, each a subkind of core `association` from a person to the
|
|
5
|
+
* subject they answer for. Accountable is not a kind: it is the existing
|
|
6
|
+
* `yarramate/ownership/owner` claim. Pure, so the canvas projection, the
|
|
7
|
+
* matrix builder and the editor read one table.
|
|
8
|
+
*/
|
|
9
|
+
export const RESPONSIBILITY_PROFILE = 'yarramate/policy@0.2';
|
|
10
|
+
export const RESPONSIBILITY_KINDS = {
|
|
11
|
+
responsible: `${RESPONSIBILITY_PROFILE}#responsible`,
|
|
12
|
+
consulted: `${RESPONSIBILITY_PROFILE}#consulted`,
|
|
13
|
+
informed: `${RESPONSIBILITY_PROFILE}#informed`,
|
|
14
|
+
};
|
|
15
|
+
export const RESPONSIBILITY_LETTERS = {
|
|
16
|
+
[RESPONSIBILITY_KINDS.responsible]: 'R',
|
|
17
|
+
[RESPONSIBILITY_KINDS.consulted]: 'C',
|
|
18
|
+
[RESPONSIBILITY_KINDS.informed]: 'I',
|
|
19
|
+
};
|
|
20
|
+
export const OWNER_PREDICATE = 'yarramate/ownership/owner';
|
|
21
|
+
/** The core kinds a person subject may be, ancestors of any profile's own. */
|
|
22
|
+
export const PEOPLE_KINDS = [
|
|
23
|
+
'yarramate/core@0.1#businessActor',
|
|
24
|
+
'yarramate/core@0.1#businessRole',
|
|
25
|
+
'yarramate/core@0.1#businessCollaboration',
|
|
26
|
+
'yarramate/core@0.1#stakeholder',
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* The letter a relationship kind carries, read through its lineage
|
|
30
|
+
* (ancestor-first) so a profile's own subkind of `responsible` is still an
|
|
31
|
+
* R; `null` for every other kind.
|
|
32
|
+
*/
|
|
33
|
+
export const responsibilityLetterOf = (lineage, kind) => {
|
|
34
|
+
for (const member of lineage ?? [kind]) {
|
|
35
|
+
const letter = RESPONSIBILITY_LETTERS[member];
|
|
36
|
+
if (letter !== undefined)
|
|
37
|
+
return letter;
|
|
38
|
+
}
|
|
39
|
+
return RESPONSIBILITY_LETTERS[kind] ?? null;
|
|
40
|
+
};
|
|
41
|
+
/** Whether a concept kind is a person, read through its lineage. */
|
|
42
|
+
export const isPeopleKind = (lineage, kind) => (lineage ?? [kind]).some((member) => PEOPLE_KINDS.includes(member)) ||
|
|
43
|
+
PEOPLE_KINDS.includes(kind);
|