@formicoidea/labre-framework-wardley 0.31.0 → 0.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.
Files changed (58) hide show
  1. package/dist/actions.d.ts +63 -20
  2. package/dist/actions.js +190 -57
  3. package/dist/audit-criteria.d.ts +31 -0
  4. package/dist/audit-criteria.js +90 -0
  5. package/dist/background.d.ts +14 -0
  6. package/dist/background.js +338 -0
  7. package/dist/commands.d.ts +9 -0
  8. package/dist/commands.js +352 -0
  9. package/dist/consts.d.ts +10 -4
  10. package/dist/consts.js +10 -9
  11. package/dist/descriptor.d.ts +8 -3
  12. package/dist/descriptor.js +6 -3
  13. package/dist/element-renderer.d.ts +8 -5
  14. package/dist/element-renderer.js +12 -147
  15. package/dist/element-view.d.ts +8 -4
  16. package/dist/element-view.js +30 -22
  17. package/dist/export.d.ts +211 -0
  18. package/dist/export.js +655 -0
  19. package/dist/gradient.d.ts +6 -11
  20. package/dist/gradient.js +59 -48
  21. package/dist/import.d.ts +116 -0
  22. package/dist/import.js +905 -0
  23. package/dist/index.d.ts +27 -1
  24. package/dist/index.js +31 -1
  25. package/dist/interchange.d.ts +80 -0
  26. package/dist/interchange.js +138 -0
  27. package/dist/legend.js +8 -0
  28. package/dist/natures.d.ts +50 -0
  29. package/dist/natures.js +93 -0
  30. package/dist/node/node-renderer.js +1 -1
  31. package/dist/nudges.d.ts +41 -0
  32. package/dist/nudges.js +69 -0
  33. package/dist/profiles.d.ts +2 -0
  34. package/dist/profiles.js +87 -0
  35. package/dist/reading.d.ts +3 -0
  36. package/dist/reading.js +129 -0
  37. package/dist/roles.d.ts +50 -0
  38. package/dist/roles.js +132 -0
  39. package/dist/rules.d.ts +2 -0
  40. package/dist/rules.js +286 -0
  41. package/dist/templates/index.js +66 -10
  42. package/dist/templates/maps.js +146 -22
  43. package/dist/toolbar/config.js +3 -1
  44. package/dist/toolbar/icons.d.ts +20 -0
  45. package/dist/toolbar/icons.js +34 -0
  46. package/dist/toolbar/senior-tool.js +1 -0
  47. package/dist/toolbar/wardley-menu.d.ts +8 -15
  48. package/dist/toolbar/wardley-menu.js +8 -136
  49. package/dist/toolbar/wardley-senior-button.js +12 -6
  50. package/dist/translations.d.ts +16 -0
  51. package/dist/translations.js +24 -0
  52. package/dist/view.d.ts +17 -0
  53. package/dist/view.js +127 -13
  54. package/package.json +2 -2
  55. package/dist/label-layout.d.ts +0 -20
  56. package/dist/label-layout.js +0 -72
  57. package/dist/shortcuts.d.ts +0 -2
  58. package/dist/shortcuts.js +0 -37
package/dist/index.d.ts CHANGED
@@ -1 +1,27 @@
1
- export { wardleyShortcuts } from './shortcuts.js';
1
+ export { WARDLEY_ROLE, WARDLEY_ROLES, type WardleyRole, type WardleyRoleId, } from './roles.js';
2
+ export { WARDLEY_AUDIT_CRITERIA } from './audit-criteria.js';
3
+ export { wardleyCommandIcons, wardleyCommands } from './commands.js';
4
+ export { wardleyTranslationEntries } from './translations.js';
5
+ export { WARDLEY_NATURE, WARDLEY_NATURE_TAG_ID, WARDLEY_TAG_DEFS, } from './natures.js';
6
+ export { WARDLEY_PROFILES } from './profiles.js';
7
+ export { WARDLEY_NUDGES } from './nudges.js';
8
+ export { WARDLEY_NAMING_CONVENTIONS, WARDLEY_READING } from './reading.js';
9
+ export { WARDLEY_RULES } from './rules.js';
10
+ /**
11
+ * The map's own frame, declared. Public because a host that lays elements out
12
+ * against the plot — labre-mcp does, and so does anything that generates a map
13
+ * without an editor — needs the margins the renderer actually uses, and a
14
+ * second copy of four numbers is a copy that drifts (`templates/maps.ts` says
15
+ * how that went the first time). P3's packaging obligation: a value both
16
+ * consumers read is reachable from the index, never by deep import.
17
+ */
18
+ export { WARDLEY_BACKGROUND } from './background.js';
19
+ /**
20
+ * The OWM DSL, both directions — pure functions of text and models, exported
21
+ * for the reason ADR 0012 § P3 gives: the editor command and labre-mcp call the
22
+ * SAME function, and no serialization logic for a Labre framework lives outside
23
+ * this repo. `exportWardleyOwm` is what replaces labre-mcp's own serializer.
24
+ */
25
+ export { exportWardleyOwm, exportWardleyOwmWithWarnings, OWM_SCOPE, type OwmPlot, owmCoordsOf, owmPlotOf, owmPointOf, WARDLEY_OWM_FORMAT_ID, type WardleyExportBoard, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
26
+ export { importWardleyOwm } from './import.js';
27
+ export { WARDLEY_INTERCHANGE, WARDLEY_OWM_EXPORT, WARDLEY_OWM_EXTENSION, WARDLEY_OWM_FORMAT, WARDLEY_OWM_IMPORT, WARDLEY_OWM_MIME, WARDLEY_SVG_FORMAT, WARDLEY_SVG_IMPORT, } from './interchange.js';
package/dist/index.js CHANGED
@@ -1 +1,31 @@
1
- export { wardleyShortcuts } from './shortcuts.js';
1
+ export { WARDLEY_ROLE, WARDLEY_ROLES, } from './roles.js';
2
+ export { WARDLEY_AUDIT_CRITERIA } from './audit-criteria.js';
3
+ export { wardleyCommandIcons, wardleyCommands } from './commands.js';
4
+ export { wardleyTranslationEntries } from './translations.js';
5
+ export { WARDLEY_NATURE, WARDLEY_NATURE_TAG_ID, WARDLEY_TAG_DEFS, } from './natures.js';
6
+ export { WARDLEY_PROFILES } from './profiles.js';
7
+ export { WARDLEY_NUDGES } from './nudges.js';
8
+ export { WARDLEY_NAMING_CONVENTIONS, WARDLEY_READING } from './reading.js';
9
+ export { WARDLEY_RULES } from './rules.js';
10
+ /**
11
+ * The map's own frame, declared. Public because a host that lays elements out
12
+ * against the plot — labre-mcp does, and so does anything that generates a map
13
+ * without an editor — needs the margins the renderer actually uses, and a
14
+ * second copy of four numbers is a copy that drifts (`templates/maps.ts` says
15
+ * how that went the first time). P3's packaging obligation: a value both
16
+ * consumers read is reachable from the index, never by deep import.
17
+ */
18
+ export { WARDLEY_BACKGROUND } from './background.js';
19
+ /**
20
+ * The OWM DSL, both directions — pure functions of text and models, exported
21
+ * for the reason ADR 0012 § P3 gives: the editor command and labre-mcp call the
22
+ * SAME function, and no serialization logic for a Labre framework lives outside
23
+ * this repo. `exportWardleyOwm` is what replaces labre-mcp's own serializer.
24
+ */
25
+ export { exportWardleyOwm, exportWardleyOwmWithWarnings, OWM_SCOPE, owmCoordsOf, owmPlotOf, owmPointOf, WARDLEY_OWM_FORMAT_ID, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
26
+ export { importWardleyOwm } from './import.js';
27
+ // Wardley's entries in the interchange registry (`docs/adr/0012`) — the OWM
28
+ // DSL both ways, and the visual-tier SVG fallback. Exported whole so a host can
29
+ // ask what Wardley can read and write without mounting an editor, and call it
30
+ // without one either (P3).
31
+ export { WARDLEY_INTERCHANGE, WARDLEY_OWM_EXPORT, WARDLEY_OWM_EXTENSION, WARDLEY_OWM_FORMAT, WARDLEY_OWM_IMPORT, WARDLEY_OWM_MIME, WARDLEY_SVG_FORMAT, WARDLEY_SVG_IMPORT, } from './interchange.js';
@@ -0,0 +1,80 @@
1
+ import type { InterchangeCapability, InterchangeExportCapability, InterchangeFormat, InterchangeImportCapability } from '@formicoidea/labre-core/blocks/surface';
2
+ /**
3
+ * Wardley's entries in the interchange registry (`docs/adr/0012`, P1).
4
+ *
5
+ * Two formats and three rows. Both directions of the OWM DSL — the export is
6
+ * the row the ADR records as **owed** (a Wardley serializer exists today in
7
+ * labre-mcp, outside this repo, and is the one violation of P3 the ADR names;
8
+ * it exists here now, so that repo becomes a caller and its copy is deleted),
9
+ * and the import is the row the ADR calls **the reference Wardley import**,
10
+ * because the OWM DSL is the settled Wardley vocabulary while mermaid's Wardley
11
+ * diagram type is still experimental upstream. Then SVG IN, the visual-tier
12
+ * FALLBACK, which promises recognition and nothing else.
13
+ *
14
+ * The file is laid out as one section per FORMAT, each holding its format
15
+ * object then its capabilities, with {@link WARDLEY_INTERCHANGE} at the bottom
16
+ * collecting them. A format is added by adding a section, not by editing one.
17
+ *
18
+ * Everything here is pure. No half has ever had a `std` in sight, and this file
19
+ * adds no editor to any of them: it picks the artefacts the writer speaks about
20
+ * out of a surface's elements, and hands a reader's output straight back.
21
+ */
22
+ /**
23
+ * The OnlineWardleyMaps DSL. **Semantic** — the file carries a model, not a
24
+ * picture: a `[visibility, evolution]` pair IS a position on the value chain
25
+ * and on the evolution axis, so the whole preservation contract applies and the
26
+ * import needs no invented axis (P2, and D4's "a format that carries
27
+ * coordinates but no pixels").
28
+ *
29
+ * `text/plain`, because that is what a DSL is, and `.owm` first — it is the
30
+ * extension a download is given. `.wm` rides behind it: the same bytes are
31
+ * written under both in the wild, and a picker that refused one would refuse a
32
+ * valid map for the sake of a filename. What the file actually IS is decided by
33
+ * the reader.
34
+ *
35
+ * The two directions share the FORMAT object, deliberately. `owm` is the id
36
+ * under which foreign matter rides on an element (D2), so a reader and a writer
37
+ * that disagreed about it would write payloads the other could not find.
38
+ */
39
+ export declare const WARDLEY_OWM_EXTENSION = ".owm";
40
+ export declare const WARDLEY_OWM_MIME = "text/plain";
41
+ export declare const WARDLEY_OWM_FORMAT: InterchangeFormat;
42
+ /** `wardley:owm:export` — the row that replaces labre-mcp's own serializer. */
43
+ export declare const WARDLEY_OWM_EXPORT: InterchangeExportCapability;
44
+ /** `wardley:owm:import` — an `.owm` file as a map. */
45
+ export declare const WARDLEY_OWM_IMPORT: InterchangeImportCapability;
46
+ /**
47
+ * SVG. **Visual** — the file carries a rendering, not a model, so it makes
48
+ * exactly one promise: the picture arrives as editable elements.
49
+ *
50
+ * Wardley's own format object, and NOT one shared with BPMN's, because ADR 0012
51
+ * rejects "one capability per format, with the framework inferred from the
52
+ * file": a `.svg` is read by several frameworks, and deciding which one a
53
+ * picture is a picture OF is the guess this platform refuses everywhere else.
54
+ * The three constants are the parser package's, so the declarations cannot
55
+ * drift into filtering a picker on different extensions.
56
+ */
57
+ export declare const WARDLEY_SVG_FORMAT: InterchangeFormat;
58
+ /**
59
+ * `wardley:svg:import` — an SVG as a sketch, best effort.
60
+ *
61
+ * **The heuristics statement and the known failure modes this capability owes
62
+ * (ADR 0012, open question 2) are the module documentation of
63
+ * `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** Written once
64
+ * there because Wardley and BPMN wrap the SAME parser and therefore make the
65
+ * same guesses — and because the ADR's question is about what a visual
66
+ * capability is ALLOWED to guess, which for both of them is: geometry, and
67
+ * nothing else. A circle is a circle; whether it is a component is the
68
+ * author's sentence, not this reader's.
69
+ *
70
+ * What lands is an ADR 0007 level-1 sketch — plain shapes, brush strokes and
71
+ * editable free text — which the author then PROMOTES onto a map. In
72
+ * particular the two axes and the evolution bands are NOT recovered: a map's
73
+ * coordinates are its meaning, and reading them off a picture would be
74
+ * inventing a position and presenting it as read. {@link WARDLEY_OWM_IMPORT}
75
+ * beside it is the route a user should be pointed at, exactly as P2 says —
76
+ * this one is for the picture somebody sent you from a tool that writes no OWM.
77
+ */
78
+ export declare const WARDLEY_SVG_IMPORT: InterchangeImportCapability;
79
+ /** Everything Wardley registers, in one list the view extension hands over. */
80
+ export declare const WARDLEY_INTERCHANGE: readonly InterchangeCapability[];
@@ -0,0 +1,138 @@
1
+ import { interchangeCapabilityId, parseSvgSketch, SVG_SKETCH_EXTENSION, SVG_SKETCH_FORMAT_ID, SVG_SKETCH_MIME, } from '@formicoidea/labre-core/blocks/surface';
2
+ import { exportWardleyOwmWithWarnings, WARDLEY_OWM_FORMAT_ID, wardleyBoardFrom, wardleySafeFilename, } from './export.js';
3
+ import { importWardleyOwm } from './import.js';
4
+ /**
5
+ * Wardley's entries in the interchange registry (`docs/adr/0012`, P1).
6
+ *
7
+ * Two formats and three rows. Both directions of the OWM DSL — the export is
8
+ * the row the ADR records as **owed** (a Wardley serializer exists today in
9
+ * labre-mcp, outside this repo, and is the one violation of P3 the ADR names;
10
+ * it exists here now, so that repo becomes a caller and its copy is deleted),
11
+ * and the import is the row the ADR calls **the reference Wardley import**,
12
+ * because the OWM DSL is the settled Wardley vocabulary while mermaid's Wardley
13
+ * diagram type is still experimental upstream. Then SVG IN, the visual-tier
14
+ * FALLBACK, which promises recognition and nothing else.
15
+ *
16
+ * The file is laid out as one section per FORMAT, each holding its format
17
+ * object then its capabilities, with {@link WARDLEY_INTERCHANGE} at the bottom
18
+ * collecting them. A format is added by adding a section, not by editing one.
19
+ *
20
+ * Everything here is pure. No half has ever had a `std` in sight, and this file
21
+ * adds no editor to any of them: it picks the artefacts the writer speaks about
22
+ * out of a surface's elements, and hands a reader's output straight back.
23
+ */
24
+ /* ── OWM (semantic) ───────────────────────────────────────────────────── */
25
+ /**
26
+ * The OnlineWardleyMaps DSL. **Semantic** — the file carries a model, not a
27
+ * picture: a `[visibility, evolution]` pair IS a position on the value chain
28
+ * and on the evolution axis, so the whole preservation contract applies and the
29
+ * import needs no invented axis (P2, and D4's "a format that carries
30
+ * coordinates but no pixels").
31
+ *
32
+ * `text/plain`, because that is what a DSL is, and `.owm` first — it is the
33
+ * extension a download is given. `.wm` rides behind it: the same bytes are
34
+ * written under both in the wild, and a picker that refused one would refuse a
35
+ * valid map for the sake of a filename. What the file actually IS is decided by
36
+ * the reader.
37
+ *
38
+ * The two directions share the FORMAT object, deliberately. `owm` is the id
39
+ * under which foreign matter rides on an element (D2), so a reader and a writer
40
+ * that disagreed about it would write payloads the other could not find.
41
+ */
42
+ export const WARDLEY_OWM_EXTENSION = '.owm';
43
+ export const WARDLEY_OWM_MIME = 'text/plain';
44
+ export const WARDLEY_OWM_FORMAT = {
45
+ id: WARDLEY_OWM_FORMAT_ID,
46
+ tier: 'semantic',
47
+ extensions: [WARDLEY_OWM_EXTENSION, '.wm'],
48
+ mime: WARDLEY_OWM_MIME,
49
+ };
50
+ /**
51
+ * The board as an OWM document.
52
+ *
53
+ * A thin adapter and nothing else: it picks the Wardley artefacts out of the
54
+ * surface, names the file, and passes the writer's losses straight through.
55
+ * There is no second door — `wardley.exportOwm` calls THIS, so the command and
56
+ * the registry cannot produce different bytes, filenames or warnings.
57
+ *
58
+ * `warnings` is omitted rather than empty when the map came out whole, so a
59
+ * caller can ask `if (result.warnings)` and mean it.
60
+ */
61
+ const runWardleyOwmExport = (elements, context) => {
62
+ const name = wardleySafeFilename(context.name);
63
+ const { text, warnings } = exportWardleyOwmWithWarnings(wardleyBoardFrom(elements), { name });
64
+ return {
65
+ text,
66
+ filename: `${name}${WARDLEY_OWM_EXTENSION}`,
67
+ mime: WARDLEY_OWM_MIME,
68
+ ...(warnings.length > 0 ? { warnings } : {}),
69
+ };
70
+ };
71
+ /** `wardley:owm:export` — the row that replaces labre-mcp's own serializer. */
72
+ export const WARDLEY_OWM_EXPORT = {
73
+ id: interchangeCapabilityId('wardley', WARDLEY_OWM_FORMAT.id, 'export'),
74
+ framework: 'wardley',
75
+ format: WARDLEY_OWM_FORMAT,
76
+ direction: 'export',
77
+ run: runWardleyOwmExport,
78
+ };
79
+ /** `wardley:owm:import` — an `.owm` file as a map. */
80
+ export const WARDLEY_OWM_IMPORT = {
81
+ id: interchangeCapabilityId('wardley', WARDLEY_OWM_FORMAT.id, 'import'),
82
+ framework: 'wardley',
83
+ format: WARDLEY_OWM_FORMAT,
84
+ direction: 'import',
85
+ run: importWardleyOwm,
86
+ };
87
+ /* ── SVG (visual) ─────────────────────────────────────────────────────── */
88
+ /**
89
+ * SVG. **Visual** — the file carries a rendering, not a model, so it makes
90
+ * exactly one promise: the picture arrives as editable elements.
91
+ *
92
+ * Wardley's own format object, and NOT one shared with BPMN's, because ADR 0012
93
+ * rejects "one capability per format, with the framework inferred from the
94
+ * file": a `.svg` is read by several frameworks, and deciding which one a
95
+ * picture is a picture OF is the guess this platform refuses everywhere else.
96
+ * The three constants are the parser package's, so the declarations cannot
97
+ * drift into filtering a picker on different extensions.
98
+ */
99
+ export const WARDLEY_SVG_FORMAT = {
100
+ id: SVG_SKETCH_FORMAT_ID,
101
+ tier: 'visual',
102
+ extensions: [SVG_SKETCH_EXTENSION],
103
+ mime: SVG_SKETCH_MIME,
104
+ };
105
+ /**
106
+ * `wardley:svg:import` — an SVG as a sketch, best effort.
107
+ *
108
+ * **The heuristics statement and the known failure modes this capability owes
109
+ * (ADR 0012, open question 2) are the module documentation of
110
+ * `packages/affine/blocks/surface/src/extensions/svg-sketch.ts`.** Written once
111
+ * there because Wardley and BPMN wrap the SAME parser and therefore make the
112
+ * same guesses — and because the ADR's question is about what a visual
113
+ * capability is ALLOWED to guess, which for both of them is: geometry, and
114
+ * nothing else. A circle is a circle; whether it is a component is the
115
+ * author's sentence, not this reader's.
116
+ *
117
+ * What lands is an ADR 0007 level-1 sketch — plain shapes, brush strokes and
118
+ * editable free text — which the author then PROMOTES onto a map. In
119
+ * particular the two axes and the evolution bands are NOT recovered: a map's
120
+ * coordinates are its meaning, and reading them off a picture would be
121
+ * inventing a position and presenting it as read. {@link WARDLEY_OWM_IMPORT}
122
+ * beside it is the route a user should be pointed at, exactly as P2 says —
123
+ * this one is for the picture somebody sent you from a tool that writes no OWM.
124
+ */
125
+ export const WARDLEY_SVG_IMPORT = {
126
+ id: interchangeCapabilityId('wardley', WARDLEY_SVG_FORMAT.id, 'import'),
127
+ framework: 'wardley',
128
+ format: WARDLEY_SVG_FORMAT,
129
+ direction: 'import',
130
+ run: parseSvgSketch,
131
+ };
132
+ /* ── The list the view extension registers ────────────────────────────── */
133
+ /** Everything Wardley registers, in one list the view extension hands over. */
134
+ export const WARDLEY_INTERCHANGE = [
135
+ WARDLEY_OWM_EXPORT,
136
+ WARDLEY_OWM_IMPORT,
137
+ WARDLEY_SVG_IMPORT,
138
+ ];
package/dist/legend.js CHANGED
@@ -110,6 +110,14 @@ export function createWardleyLegend(std, bg) {
110
110
  xywh: new Bound(x, y, w, h).serialize(),
111
111
  });
112
112
  // ── glyph builders (real, editable elements), centred on (cx, cy) ─────
113
+ //
114
+ // DELIBERATELY ROLE-LESS. These are real `wardleyNode` elements, but a
115
+ // legend documents the map — it is not part of it. Giving its glyphs
116
+ // `wardley:component` & co. would make every legend entry count as an
117
+ // artefact and skew any rule written against roles (a legend would add a
118
+ // phantom component, anchor, market…). Neutral is the semantics we want;
119
+ // `kind` still drives their rendering. Frozen by a test in
120
+ // `__tests__/roles.unit.spec.ts`.
113
121
  const ellipse = (kind, d, fill, sw, cx, cy) => surface.addElement({
114
122
  type: 'wardleyNode',
115
123
  kind,
@@ -0,0 +1,50 @@
1
+ import type { UniverseTagDefs } from '@formicoidea/labre-core/shared/services';
2
+ /**
3
+ * The Wardley **nature** tag — the framework's type-3 contextual qualification
4
+ * (PRD level 3, ADR 0007).
5
+ *
6
+ * A component's nature answers "what KIND of thing is this?", which is a
7
+ * different question from its role ("what is it, on a map?") and from its
8
+ * position ("how evolved is it?"). Simon Wardley's four are activity, data,
9
+ * practice and knowledge, and mapping practitioners routinely draw all four on
10
+ * one map — the same circle, the same axes, four different things.
11
+ *
12
+ * ## Why this ships as DATA, on the host's own mechanism
13
+ *
14
+ * The library fixes the FORMAT of tag definitions; the application seeds them.
15
+ * Nothing here is privileged: this pack is registered through the same
16
+ * `UniverseTagDefsExtension` a host uses for its own taxonomy, and a client's
17
+ * private extension of Wardley — say a `criticality` tag — is a second pack
18
+ * with a different `packId` that merges with this one, with no library release.
19
+ * Shipping one real pack is what keeps that mechanism honest.
20
+ *
21
+ * ## Why it applies to `wardley:component` and not to `'*'`
22
+ *
23
+ * A nature qualifies a component. `market` and `ecosystem` specialise
24
+ * `wardley:component`, so they get it for free through `roleIsA` — that is the
25
+ * entire reason role hierarchy is data. The `anchor` (a user / need) is
26
+ * deliberately NOT a child of `component` and is deliberately NOT qualified
27
+ * here: a need has no nature, it has a demand. The map itself, the change
28
+ * arrow, the inertia bar and the labels are chrome or annotations and are not
29
+ * candidates either.
30
+ *
31
+ * ## Why `cardinality: 'single'`
32
+ *
33
+ * A component is one of the four, not several. Where practitioners disagree —
34
+ * "is a data pipeline data or an activity?" — the disagreement is the finding,
35
+ * and forcing one answer is what makes the finding visible. A multi-valued
36
+ * nature would let the ambiguity hide inside the element.
37
+ *
38
+ * Labels are English fallbacks: the host localizes them. The library never
39
+ * pretends a def's `label` is already translated for someone else's locale, and
40
+ * a pack shipped as a `.json` asset carries whatever the host put in it.
41
+ */
42
+ export declare const WARDLEY_NATURE_TAG_ID = "wardley:nature";
43
+ /** The four natures, as value ids. Ids are forever; a def is only deprecated. */
44
+ export declare const WARDLEY_NATURE: {
45
+ readonly activity: "wardley:nature/activity";
46
+ readonly data: "wardley:nature/data";
47
+ readonly practice: "wardley:nature/practice";
48
+ readonly knowledge: "wardley:nature/knowledge";
49
+ };
50
+ export declare const WARDLEY_TAG_DEFS: UniverseTagDefs;
@@ -0,0 +1,93 @@
1
+ import { WARDLEY_ROLE } from './roles.js';
2
+ /**
3
+ * The Wardley **nature** tag — the framework's type-3 contextual qualification
4
+ * (PRD level 3, ADR 0007).
5
+ *
6
+ * A component's nature answers "what KIND of thing is this?", which is a
7
+ * different question from its role ("what is it, on a map?") and from its
8
+ * position ("how evolved is it?"). Simon Wardley's four are activity, data,
9
+ * practice and knowledge, and mapping practitioners routinely draw all four on
10
+ * one map — the same circle, the same axes, four different things.
11
+ *
12
+ * ## Why this ships as DATA, on the host's own mechanism
13
+ *
14
+ * The library fixes the FORMAT of tag definitions; the application seeds them.
15
+ * Nothing here is privileged: this pack is registered through the same
16
+ * `UniverseTagDefsExtension` a host uses for its own taxonomy, and a client's
17
+ * private extension of Wardley — say a `criticality` tag — is a second pack
18
+ * with a different `packId` that merges with this one, with no library release.
19
+ * Shipping one real pack is what keeps that mechanism honest.
20
+ *
21
+ * ## Why it applies to `wardley:component` and not to `'*'`
22
+ *
23
+ * A nature qualifies a component. `market` and `ecosystem` specialise
24
+ * `wardley:component`, so they get it for free through `roleIsA` — that is the
25
+ * entire reason role hierarchy is data. The `anchor` (a user / need) is
26
+ * deliberately NOT a child of `component` and is deliberately NOT qualified
27
+ * here: a need has no nature, it has a demand. The map itself, the change
28
+ * arrow, the inertia bar and the labels are chrome or annotations and are not
29
+ * candidates either.
30
+ *
31
+ * ## Why `cardinality: 'single'`
32
+ *
33
+ * A component is one of the four, not several. Where practitioners disagree —
34
+ * "is a data pipeline data or an activity?" — the disagreement is the finding,
35
+ * and forcing one answer is what makes the finding visible. A multi-valued
36
+ * nature would let the ambiguity hide inside the element.
37
+ *
38
+ * Labels are English fallbacks: the host localizes them. The library never
39
+ * pretends a def's `label` is already translated for someone else's locale, and
40
+ * a pack shipped as a `.json` asset carries whatever the host put in it.
41
+ */
42
+ export const WARDLEY_NATURE_TAG_ID = 'wardley:nature';
43
+ /** The four natures, as value ids. Ids are forever; a def is only deprecated. */
44
+ export const WARDLEY_NATURE = {
45
+ activity: `${WARDLEY_NATURE_TAG_ID}/activity`,
46
+ data: `${WARDLEY_NATURE_TAG_ID}/data`,
47
+ practice: `${WARDLEY_NATURE_TAG_ID}/practice`,
48
+ knowledge: `${WARDLEY_NATURE_TAG_ID}/knowledge`,
49
+ };
50
+ export const WARDLEY_TAG_DEFS = {
51
+ formatVersion: 1,
52
+ // The id of this PACK, not of the framework: several packs may extend
53
+ // Wardley, and re-registering this one replaces it rather than duplicating
54
+ // it.
55
+ packId: 'wardley-core',
56
+ framework: 'wardley',
57
+ label: 'Wardley',
58
+ tags: [
59
+ {
60
+ id: WARDLEY_NATURE_TAG_ID,
61
+ label: 'Nature',
62
+ description: 'What kind of thing this component is: an activity, data, a practice or knowledge.',
63
+ cardinality: 'single',
64
+ appliesTo: [WARDLEY_ROLE.component],
65
+ // No `order`: it is the only tag this pack declares, and an absent order
66
+ // sorts by SEED order, which is what puts the library's pack ahead of a
67
+ // client's extension without either having to know about the other. A
68
+ // number here would be a claim about packs that do not exist yet.
69
+ values: [
70
+ {
71
+ id: WARDLEY_NATURE.activity,
72
+ label: 'Activity',
73
+ description: 'Something that is DONE — a step, a service, a process.',
74
+ },
75
+ {
76
+ id: WARDLEY_NATURE.data,
77
+ label: 'Data',
78
+ description: 'Something that is RECORDED — a dataset, a register.',
79
+ },
80
+ {
81
+ id: WARDLEY_NATURE.practice,
82
+ label: 'Practice',
83
+ description: 'A way of doing — a method, a convention, an operating model.',
84
+ },
85
+ {
86
+ id: WARDLEY_NATURE.knowledge,
87
+ label: 'Knowledge',
88
+ description: 'Something that is KNOWN — a model, a theory, a rule.',
89
+ },
90
+ ],
91
+ },
92
+ ],
93
+ };
@@ -1,6 +1,6 @@
1
1
  import { ElementRendererExtension, } from '@formicoidea/labre-core/blocks/surface';
2
2
  import { shape as shapeRenderer } from '@formicoidea/labre-core/gfx/shape';
3
- import { DefaultTheme } from '@formicoidea/labre-core/model';
3
+ import { DefaultTheme, } from '@formicoidea/labre-core/model';
4
4
  import { ANCHOR, ECOSYSTEM, METHOD, NODE_FILL } from './consts.js';
5
5
  /**
6
6
  * Renderer for a Wardley node. The circle is drawn by REUSING the native shape
@@ -0,0 +1,41 @@
1
+ import type { QualityNudge } from '@formicoidea/labre-core/blocks/surface';
2
+ /**
3
+ * Wardley **map quality** — the checklist (PF13.9).
4
+ *
5
+ * Level 1 is `./rules.ts`: deterministic, decidable, real time. This file is
6
+ * level 2, and the split is the whole point of the taxonomy — a rule only enters
7
+ * the deterministic engine if an algorithm can decide it on persisted data
8
+ * inside the ~16 ms budget. Everything else is a NUDGE: an expectation offered
9
+ * as a checklist, never evaluated, never blocking anything. Ticking is assuming.
10
+ *
11
+ * ## The check-up rules are gone (PO decision, 02/08/2026)
12
+ *
13
+ * Q5 (tone convention) and Q6 (phase nomenclature) used to live beside these,
14
+ * as on-demand rules behind a "Run check-up" button. The panel is now the
15
+ * checklist and nothing else: the PO's recette found that a second verdict, a
16
+ * button and a scope line asked the reader to hold three different kinds of
17
+ * statement in their head over a map that mostly wanted a title. Nothing was
18
+ * deleted from the platform — the on-demand MOMENT (PF5.14) and the
19
+ * `tone-convention` / `majority-fact` families are still in the engine, still
20
+ * tested, and the next framework that wants a check-up declares one. Wardley
21
+ * simply stopped exposing one.
22
+ *
23
+ * Registered from the flag-gated `WardleyViewExtension`, beside the rules and
24
+ * the profiles: a checklist is tooling. Switching the flag off takes it away and
25
+ * leaves the ticks written on the map, unread, until it comes back (PF7.10).
26
+ */
27
+ /**
28
+ * **Q1–Q4** — the four things a Wardley map needs in order to do its job, and
29
+ * that no algorithm can check.
30
+ *
31
+ * Every one of them is about whether the map can be DISCUSSED. A map with no
32
+ * title is a diagram nobody can situate; one with no legend is a private
33
+ * notation; one whose evolution axis is drawn but not used is a value chain
34
+ * wearing a Wardley costume. The tool can put all four on screen and it cannot
35
+ * judge a single one — "the title contextualises the study" is a statement about
36
+ * meaning, and a rule claiming to have verified it would be lying.
37
+ *
38
+ * The wordings are the PO's own, from the review of 01/08/2026, carried as
39
+ * `fallback` so a host with no catalogue reads them exactly as written.
40
+ */
41
+ export declare const WARDLEY_NUDGES: readonly QualityNudge[];
package/dist/nudges.js ADDED
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Wardley **map quality** — the checklist (PF13.9).
3
+ *
4
+ * Level 1 is `./rules.ts`: deterministic, decidable, real time. This file is
5
+ * level 2, and the split is the whole point of the taxonomy — a rule only enters
6
+ * the deterministic engine if an algorithm can decide it on persisted data
7
+ * inside the ~16 ms budget. Everything else is a NUDGE: an expectation offered
8
+ * as a checklist, never evaluated, never blocking anything. Ticking is assuming.
9
+ *
10
+ * ## The check-up rules are gone (PO decision, 02/08/2026)
11
+ *
12
+ * Q5 (tone convention) and Q6 (phase nomenclature) used to live beside these,
13
+ * as on-demand rules behind a "Run check-up" button. The panel is now the
14
+ * checklist and nothing else: the PO's recette found that a second verdict, a
15
+ * button and a scope line asked the reader to hold three different kinds of
16
+ * statement in their head over a map that mostly wanted a title. Nothing was
17
+ * deleted from the platform — the on-demand MOMENT (PF5.14) and the
18
+ * `tone-convention` / `majority-fact` families are still in the engine, still
19
+ * tested, and the next framework that wants a check-up declares one. Wardley
20
+ * simply stopped exposing one.
21
+ *
22
+ * Registered from the flag-gated `WardleyViewExtension`, beside the rules and
23
+ * the profiles: a checklist is tooling. Switching the flag off takes it away and
24
+ * leaves the ticks written on the map, unread, until it comes back (PF7.10).
25
+ */
26
+ /**
27
+ * **Q1–Q4** — the four things a Wardley map needs in order to do its job, and
28
+ * that no algorithm can check.
29
+ *
30
+ * Every one of them is about whether the map can be DISCUSSED. A map with no
31
+ * title is a diagram nobody can situate; one with no legend is a private
32
+ * notation; one whose evolution axis is drawn but not used is a value chain
33
+ * wearing a Wardley costume. The tool can put all four on screen and it cannot
34
+ * judge a single one — "the title contextualises the study" is a statement about
35
+ * meaning, and a rule claiming to have verified it would be lying.
36
+ *
37
+ * The wordings are the PO's own, from the review of 01/08/2026, carried as
38
+ * `fallback` so a host with no catalogue reads them exactly as written.
39
+ */
40
+ export const WARDLEY_NUDGES = [
41
+ {
42
+ id: 'wardley.q1-title',
43
+ framework: 'wardley',
44
+ labelKey: 'com.labre.wardley.quality.title',
45
+ fallback: 'The map has a title that frames the study (scope, objective) and states what kind of map it is.',
46
+ order: 1,
47
+ },
48
+ {
49
+ id: 'wardley.q2-context',
50
+ framework: 'wardley',
51
+ labelKey: 'com.labre.wardley.quality.context',
52
+ fallback: 'The context of the map is stated.',
53
+ order: 2,
54
+ },
55
+ {
56
+ id: 'wardley.q3-legend',
57
+ framework: 'wardley',
58
+ labelKey: 'com.labre.wardley.quality.legend',
59
+ fallback: 'The map is legended.',
60
+ order: 3,
61
+ },
62
+ {
63
+ id: 'wardley.q4-evolution-axis',
64
+ framework: 'wardley',
65
+ labelKey: 'com.labre.wardley.quality.evolution-axis',
66
+ fallback: 'The evolution axis is used and legended.',
67
+ order: 4,
68
+ },
69
+ ];
@@ -0,0 +1,2 @@
1
+ import type { ValidationProfile } from '@formicoidea/labre-core/blocks/surface';
2
+ export declare const WARDLEY_PROFILES: readonly ValidationProfile[];
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Wardley validation profiles (PF9).
3
+ *
4
+ * DATA owned by the framework, like its rules, its roles and its background:
5
+ * the engine knows how to APPLY a profile, never which ones Wardley has. Adding
6
+ * a level of requirement is adding an entry to this array.
7
+ *
8
+ * A profile is chosen per MAP, not per document (PF9.1) — a rough sketch and a
9
+ * deliverable diagram coexist on the same canvas with different requirements,
10
+ * and the choice rides on the background element itself.
11
+ *
12
+ * Registered from the flag-gated `WardleyViewExtension`, beside the rules:
13
+ * switching the Wardley flag off takes the choice away with the rest of the
14
+ * tooling, and a map already set to `strict` simply stops being checked until
15
+ * it comes back — the id stays written, untouched.
16
+ */
17
+ /**
18
+ * Learning: every rule is demoted to `audit`, so findings still reach
19
+ * `violations$` — a host panel and a conformance report see them — and the
20
+ * canvas says nothing at all. Nobody drawing gets interrupted.
21
+ *
22
+ * The DEFAULT, and deliberately so: the sketch wins (PRD principle 3). Somebody
23
+ * opening a Wardley map for the first time is exploring, not filing a
24
+ * deliverable, and the tool has no business telling them off for an arrow they
25
+ * have not finished turning round. Being the default also means it is the one
26
+ * profile that WRITES NOTHING: a map on `sketch` carries no profile key, so
27
+ * every map ever drawn is on it, with no migration and no backfill.
28
+ *
29
+ * Silencing ALL THREE is the architect's recommendation and is written here for
30
+ * the PO to confirm or overturn — it is one word per line either way.
31
+ */
32
+ const sketch = {
33
+ id: 'wardley.sketch',
34
+ framework: 'wardley',
35
+ labelKey: 'com.labre.wardley.profile.sketch',
36
+ fallback: 'Sketch',
37
+ isDefault: true,
38
+ rules: {
39
+ 'wardley.change-arrow-against-evolution': 'audit',
40
+ 'wardley.inertia-off-transition': 'audit',
41
+ 'wardley.overlapping-artefacts': 'audit',
42
+ // W4 too, and it is the one where the demotion matters most: a value chain
43
+ // is drawn before it is arranged, so half the links are momentarily
44
+ // upside-down while somebody thinks. The finding still reaches a host panel
45
+ // and a conformance report; the canvas says nothing.
46
+ 'wardley.provider-above-consumer': 'audit',
47
+ },
48
+ };
49
+ /**
50
+ * Strict: the deliverable level. Every rule bites, and every severity a user
51
+ * gets is spelled out here rather than left absent — PF9.4 wants the answer
52
+ * readable in one place, and a profile that says "warning" out loud cannot be
53
+ * misread as "whatever the rule happens to declare this quarter".
54
+ *
55
+ * ## Why W1 and W2 are not `blocking-overridable`
56
+ *
57
+ * They should be: pointing a change arrow backwards and parking an inertia bar
58
+ * in the middle of a phase are both statements that are simply false, and the
59
+ * architect's recommendation is that strict refuse the gesture and offer the
60
+ * way out.
61
+ *
62
+ * Nothing implements that yet. `blocking-overridable` is carried by the engine
63
+ * and read by nobody: no gesture is refused anywhere in this library. Declaring
64
+ * it here would be data claiming an effect that does not exist, and the honest
65
+ * move is a `warning` plus this paragraph. When the refusal lands, this is a
66
+ * two-word change and the profile is the only file that moves.
67
+ *
68
+ * W3 stays `warning` on its own merits: an overlap is a readability problem,
69
+ * and refusing a drag because two labels touch would be the tool fighting the
70
+ * hand.
71
+ */
72
+ const strict = {
73
+ id: 'wardley.strict',
74
+ framework: 'wardley',
75
+ labelKey: 'com.labre.wardley.profile.strict',
76
+ fallback: 'Strict',
77
+ rules: {
78
+ 'wardley.change-arrow-against-evolution': 'warning',
79
+ 'wardley.inertia-off-transition': 'warning',
80
+ 'wardley.overlapping-artefacts': 'warning',
81
+ // W4 is a `warning` for the same reason W1 and W2 are, plus one of its own:
82
+ // its two honest resolutions are a MOVE and a REVERSAL, and both are the
83
+ // user's call. A rule that refused the gesture would be picking one.
84
+ 'wardley.provider-above-consumer': 'warning',
85
+ },
86
+ };
87
+ export const WARDLEY_PROFILES = [sketch, strict];