@formicoidea/labre-framework-ddd-context-map 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.
@@ -0,0 +1,38 @@
1
+ import type { GfxController } from '@formicoidea/labre-core/std/gfx';
2
+ import { type ContextMapPatternKind } from './roles.js';
3
+ /** Create the board at the viewport centre, select it, return to the default tool. */
4
+ export declare function createContextMapBoard(gfx: GfxController): void;
5
+ /**
6
+ * Activate the native connector tool, pre-styled and TYPED for one Context Map
7
+ * pattern. The user then drags from one bounded context to another and the
8
+ * endpoints attach.
9
+ *
10
+ * ## Why this replaces the old palette entry
11
+ *
12
+ * Until WS2 each pattern entry dropped a free-floating GROUP at the viewport
13
+ * centre: a connector between two points in mid-air, an abbreviation tag and,
14
+ * for the U/D patterns, two letters. It looked like the notation and said
15
+ * nothing — the link was attached to nothing, so no rule could read its ends,
16
+ * and the user still had to drag both endpoints onto the contexts by hand.
17
+ *
18
+ * The gesture now IS the statement (`docs/adr/0010`): the tool announces which
19
+ * way to drag (the role's `gestureHint`), the drawn connector carries the
20
+ * pattern's role, and the endpoints are real element references — which is what
21
+ * makes the whole of `rules.ts` possible.
22
+ *
23
+ * ## What the style says, and what the role says
24
+ *
25
+ * Style is presentation: `dashed` for the two "no real integration" patterns
26
+ * (Separate Ways, Big Ball of Mud), a rear arrowhead for the five U/D ones so
27
+ * the sheet still reads at a glance. Meaning is the role, and only the role: a
28
+ * user restyling a link never changes what it means, and a link drawn before
29
+ * WS2 keeps its old look and stays neutral.
30
+ *
31
+ * The abbreviation TAG is not drawn any more. A label riding on the connector is
32
+ * `ConnectorToolOptions.label`, which was cut from v1 — the pattern reads from
33
+ * the hover reveal (M2) and the toolbar until it lands.
34
+ */
35
+ export declare function activateContextMapRelationship(gfx: GfxController, kind: ContextMapPatternKind, style: {
36
+ upDown: boolean;
37
+ dashed: boolean;
38
+ }): void;
@@ -0,0 +1,84 @@
1
+ import { backgroundSize, DefaultTool } from '@formicoidea/labre-core/blocks/surface';
2
+ import { ConnectorTool } from '@formicoidea/labre-core/gfx/connector';
3
+ import { LABEL_COLOR } from '@formicoidea/labre-ddd-shared';
4
+ import { ConnectorMode, PointStyle, StrokeStyle } from '@formicoidea/labre-core/model';
5
+ import { Bound } from '@formicoidea/labre-core/global/gfx';
6
+ import { CONTEXT_MAP_BACKGROUND } from './background.js';
7
+ import { CM_PATTERN_ROLE } from './roles.js';
8
+ /**
9
+ * Creation / activation actions for the Context Map toolbox — the BEHAVIOUR
10
+ * layer, depending on nothing but the {@link GfxController}.
11
+ *
12
+ * They emit no telemetry: since PF3 the single emission point is the command
13
+ * registry's `runCommand` (`docs/adr/0008`).
14
+ */
15
+ const RELATIONSHIP_STROKE_WIDTH = 2;
16
+ /** Create the board at the viewport centre, select it, return to the default tool. */
17
+ export function createContextMapBoard(gfx) {
18
+ if (!gfx.surface)
19
+ return;
20
+ const { width, height } = backgroundSize(CONTEXT_MAP_BACKGROUND);
21
+ const { centerX, centerY } = gfx.viewport;
22
+ const id = gfx.surface.addElement({
23
+ type: CONTEXT_MAP_BACKGROUND.type,
24
+ // The board is a first-class role: rules frame contexts against
25
+ // `context-map:board`, never against the `contextMap` element type. The
26
+ // declaration owns it, so a templated board and a hand-drawn one agree.
27
+ role: CONTEXT_MAP_BACKGROUND.role,
28
+ resizeEnabled: CONTEXT_MAP_BACKGROUND.geometry.resizable,
29
+ xywh: new Bound(centerX - width / 2, centerY - height / 2, width, height).serialize(),
30
+ });
31
+ gfx.doc.captureSync();
32
+ gfx.tool.setTool(DefaultTool);
33
+ gfx.selection.set({ elements: [id], editing: false });
34
+ }
35
+ /**
36
+ * Activate the native connector tool, pre-styled and TYPED for one Context Map
37
+ * pattern. The user then drags from one bounded context to another and the
38
+ * endpoints attach.
39
+ *
40
+ * ## Why this replaces the old palette entry
41
+ *
42
+ * Until WS2 each pattern entry dropped a free-floating GROUP at the viewport
43
+ * centre: a connector between two points in mid-air, an abbreviation tag and,
44
+ * for the U/D patterns, two letters. It looked like the notation and said
45
+ * nothing — the link was attached to nothing, so no rule could read its ends,
46
+ * and the user still had to drag both endpoints onto the contexts by hand.
47
+ *
48
+ * The gesture now IS the statement (`docs/adr/0010`): the tool announces which
49
+ * way to drag (the role's `gestureHint`), the drawn connector carries the
50
+ * pattern's role, and the endpoints are real element references — which is what
51
+ * makes the whole of `rules.ts` possible.
52
+ *
53
+ * ## What the style says, and what the role says
54
+ *
55
+ * Style is presentation: `dashed` for the two "no real integration" patterns
56
+ * (Separate Ways, Big Ball of Mud), a rear arrowhead for the five U/D ones so
57
+ * the sheet still reads at a glance. Meaning is the role, and only the role: a
58
+ * user restyling a link never changes what it means, and a link drawn before
59
+ * WS2 keeps its old look and stays neutral.
60
+ *
61
+ * The abbreviation TAG is not drawn any more. A label riding on the connector is
62
+ * `ConnectorToolOptions.label`, which was cut from v1 — the pattern reads from
63
+ * the hover reveal (M2) and the toolbar until it lands.
64
+ */
65
+ export function activateContextMapRelationship(gfx, kind, style) {
66
+ gfx.tool.setTool(ConnectorTool, {
67
+ mode: ConnectorMode.Straight,
68
+ role: CM_PATTERN_ROLE[kind],
69
+ // The look rides on the activation, never through the last-props store:
70
+ // the plain connector tool must keep the user's own style (#144 M1).
71
+ style: {
72
+ stroke: LABEL_COLOR,
73
+ strokeStyle: style.dashed ? StrokeStyle.Dash : StrokeStyle.Solid,
74
+ strokeWidth: RELATIONSHIP_STROKE_WIDTH,
75
+ frontEndpointStyle: PointStyle.None,
76
+ // The arrow points at the DOWNSTREAM end, which is the target: the
77
+ // role's verb is "is upstream of", so the source is the upstream
78
+ // context.
79
+ rearEndpointStyle: style.upDown ? PointStyle.Arrow : PointStyle.None,
80
+ },
81
+ });
82
+ // The Context Map palette stays open (native sub-menu behaviour): it only
83
+ // closes on re-click of the senior button, another senior tool, or Escape.
84
+ }
@@ -0,0 +1,19 @@
1
+ import type { FrameworkBackgroundDef } from '@formicoidea/labre-core/blocks/surface';
2
+ /**
3
+ * The Context Map board, DECLARED (the `FrameworkBackgroundDef` primitive).
4
+ *
5
+ * The emptiest declaration in the library, and deliberately so: **no axes, no
6
+ * zones**. A Context Map is a graph, not a chart — a bounded context drawn top
7
+ * left says nothing more than one drawn bottom right, and graduating the card
8
+ * would invent a frame of reference the framework does not have. What the
9
+ * declaration is for here is the ROLE and the geometry: `context-map:board` is
10
+ * what a rule frames its subjects against, and it is what a per-map validation
11
+ * profile is written on.
12
+ *
13
+ * The palette carries the notation's two boundary colours even though nothing in
14
+ * this file paints them. Same precedent as the Wardley tone convention: a
15
+ * palette entry is a declared REFERENCE, so the day a `tone-convention` rule
16
+ * asks "is this bubble drawn in the map's own blue" the answer is already
17
+ * written down, in one place, beside the card it belongs to.
18
+ */
19
+ export declare const CONTEXT_MAP_BACKGROUND: FrameworkBackgroundDef;
@@ -0,0 +1,51 @@
1
+ import { CLOUD, CM_BUBBLE, FONT_FAMILY } from '@formicoidea/labre-ddd-shared';
2
+ import { CONTEXT_MAP_ROLE } from './roles.js';
3
+ /**
4
+ * The Context Map board, DECLARED (the `FrameworkBackgroundDef` primitive).
5
+ *
6
+ * The emptiest declaration in the library, and deliberately so: **no axes, no
7
+ * zones**. A Context Map is a graph, not a chart — a bounded context drawn top
8
+ * left says nothing more than one drawn bottom right, and graduating the card
9
+ * would invent a frame of reference the framework does not have. What the
10
+ * declaration is for here is the ROLE and the geometry: `context-map:board` is
11
+ * what a rule frames its subjects against, and it is what a per-map validation
12
+ * profile is written on.
13
+ *
14
+ * The palette carries the notation's two boundary colours even though nothing in
15
+ * this file paints them. Same precedent as the Wardley tone convention: a
16
+ * palette entry is a declared REFERENCE, so the day a `tone-convention` rule
17
+ * asks "is this bubble drawn in the map's own blue" the answer is already
18
+ * written down, in one place, beside the card it belongs to.
19
+ */
20
+ export const CONTEXT_MAP_BACKGROUND = {
21
+ type: 'contextMap',
22
+ role: CONTEXT_MAP_ROLE.board,
23
+ geometry: {
24
+ // Wide and free: a context map grows sideways as contexts are found, so
25
+ // neither dimension is locked to the other and the handles are offered from
26
+ // the start — the opposite call from the Wardley map, which is a frame of
27
+ // reference you place things on rather than a sheet you spread out.
28
+ width: 1400,
29
+ height: 900,
30
+ lockAspectRatio: false,
31
+ resizable: true,
32
+ margin: { top: 24, right: 24, bottom: 24, left: 24 },
33
+ },
34
+ chrome: {
35
+ fontFamily: FONT_FAMILY,
36
+ palette: {
37
+ card: '#ffffff',
38
+ cardBorder: '#d5d9e0',
39
+ /** The bounded-context pill: the map's own blue. */
40
+ context: CM_BUBBLE.fill,
41
+ contextBorder: CM_BUBBLE.stroke,
42
+ /** The cloud / Big Ball of Mud: the map's own grey-violet. */
43
+ cloud: CLOUD.fill,
44
+ cloudBorder: CLOUD.stroke,
45
+ },
46
+ surface: {
47
+ fill: '@card',
48
+ border: { color: '@cardBorder', width: 1.5, radius: 12 },
49
+ },
50
+ },
51
+ };
@@ -0,0 +1,4 @@
1
+ import type { CommandDescriptor } from '@formicoidea/labre-core/std';
2
+ import { type TemplateResult } from 'lit';
3
+ export declare const contextMapCommands: CommandDescriptor[];
4
+ export declare const contextMapCommandIcons: Record<string, TemplateResult>;
@@ -0,0 +1,84 @@
1
+ import { addBubble, addCloud, CM_RELATIONSHIPS, placeDddElement, } from '@formicoidea/labre-ddd-shared';
2
+ import { GfxControllerIdentifier } from '@formicoidea/labre-core/std/gfx';
3
+ import { svg } from 'lit';
4
+ import { activateContextMapRelationship, createContextMapBoard, } from './actions.js';
5
+ import { CONTEXT_MAP_ROLE } from './roles.js';
6
+ /**
7
+ * The Context Map palette as commands: the board, the bounded-context bubble,
8
+ * the cloud and the nine relationship patterns (`docs/adr/0008`).
9
+ *
10
+ * Two entries changed shape in WS2 and neither changed its telemetry: the
11
+ * bubble now carries the `context-map:context` role, and the nine patterns arm
12
+ * the connector tool instead of dropping a drawing.
13
+ *
14
+ * The notation legend is deliberately NOT a palette entry any more (PO recette,
15
+ * 27/08/2026): the ONE legend is the automatic one on the selected board's
16
+ * contextual toolbar (`toolbar/board-config.ts`) — the same call Core Domain
17
+ * Chart makes. A palette that could also drop a second, static legend was two
18
+ * answers to one question.
19
+ */
20
+ const boardSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><rect x="2.5" y="4.5" width="19" height="15" rx="2" fill="#ffffff" stroke="currentColor" stroke-width="1.6"/><rect x="5.5" y="8" width="6" height="3.5" rx="1.75" fill="#e6f0fa" stroke="#2f6fb0" stroke-width="1.1"/><rect x="13" y="13" width="6" height="3.5" rx="1.75" fill="#e6f0fa" stroke="#2f6fb0" stroke-width="1.1"/><path d="M11.5 10.5 L13.5 13.8" stroke="currentColor" stroke-width="1.2"/></svg>`;
21
+ const bubbleSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><rect x="2" y="7" width="20" height="10" rx="5" fill="#e6f0fa" stroke="#2f6fb0" stroke-width="1.6"/></svg>`;
22
+ const cloudSwatch = svg `<svg viewBox="0 0 24 24" fill="none"><path d="M6 17 C3 17 2 14 4.5 12.5 C4 9 8 8 9.5 10 C11 6.5 16 7.5 16 11 C19 10.5 20.5 14 18 16 C18 17 16.5 17 15 17 Z" fill="#f0eef6" stroke="#6d6e71" stroke-width="1.4"/></svg>`;
23
+ const relationSwatch = (dashed, arrow) => svg `<svg viewBox="0 0 24 24" fill="none"><path d="M3 12 H${arrow ? 17 : 21}" stroke="currentColor" stroke-width="2" stroke-dasharray="${dashed ? '3 3' : '0'}"/>${arrow ? svg `<path d="M15 8 L21 12 L15 16" stroke="currentColor" stroke-width="2" fill="none"/>` : ''}</svg>`;
24
+ const SPECS = [
25
+ {
26
+ id: 'addBoard',
27
+ label: 'Context Map board',
28
+ iconKey: 'ddd-context-map.board',
29
+ // A NEW telemetry value, and the only one in this file: every other entry
30
+ // below keeps the `element` string it has emitted since ADR 0008.
31
+ element: 'board',
32
+ icon: boardSwatch,
33
+ run: std => createContextMapBoard(std.get(GfxControllerIdentifier)),
34
+ },
35
+ {
36
+ id: 'addBoundedContext',
37
+ label: 'Bounded Context',
38
+ iconKey: 'ddd-context-map.bubble',
39
+ element: 'bounded-context',
40
+ icon: bubbleSwatch,
41
+ run: std => placeDddElement(std, (surface, cx, cy) =>
42
+ // The role is what makes a bubble a bounded CONTEXT rather than a blue
43
+ // pill: every rule in `rules.ts` reads it, and a pill drawn before WS2
44
+ // carries none and is never evaluated (promesse #71).
45
+ addBubble(surface, cx, cy, 'Bounded Context', CONTEXT_MAP_ROLE.context)),
46
+ },
47
+ {
48
+ id: 'addCloud',
49
+ label: 'Cloud / System (Big Ball of Mud)',
50
+ iconKey: 'ddd-context-map.cloud',
51
+ element: 'cloud',
52
+ icon: cloudSwatch,
53
+ run: std => placeDddElement(std, (surface, cx, cy) => addCloud(surface, std, cx, cy, 'System')),
54
+ },
55
+ ...CM_RELATIONSHIPS.map((preset) => ({
56
+ id: `add${preset.kind[0].toUpperCase()}${preset.kind.slice(1)}`,
57
+ label: preset.label,
58
+ iconKey: `ddd-context-map.relationship.${preset.kind}`,
59
+ element: `relationship:${preset.kind}`,
60
+ icon: relationSwatch(preset.dashed, preset.upDown),
61
+ // No longer a placement: the nine patterns arm the connector tool and the
62
+ // user DRAWS the relation between two contexts. See
63
+ // `activateContextMapRelationship` for why the free-floating group had to
64
+ // go. The telemetry `element` value is untouched.
65
+ run: std => activateContextMapRelationship(std.get(GfxControllerIdentifier), preset.kind, { upDown: preset.upDown, dashed: preset.dashed }),
66
+ })),
67
+ ];
68
+ export const contextMapCommands = SPECS.map((spec, order) => ({
69
+ id: `ddd-context-map.${spec.id}`,
70
+ owner: 'ddd-context-map',
71
+ kind: 'artefact',
72
+ labelKey: `com.labre.commands.ddd-context-map.${spec.id}`,
73
+ labelFallback: spec.label,
74
+ category: 'map',
75
+ iconKey: spec.iconKey,
76
+ surfaces: ['senior-menu', 'catalogue', 'palette', 'agent'],
77
+ order,
78
+ scope: 'edgeless',
79
+ defaultKeys: { mac: [], other: [] },
80
+ availability: 'always',
81
+ run: spec.run,
82
+ telemetry: { framework: 'ddd-context-map', element: spec.element },
83
+ }));
84
+ export const contextMapCommandIcons = Object.fromEntries(SPECS.map(spec => [spec.iconKey, spec.icon]));
@@ -1,7 +1,12 @@
1
- import { DddContextMapViewExtension } from './view.js';
1
+ import { DddContextMapRenderViewExtension, DddContextMapViewExtension } from './view.js';
2
2
  /** Host wiring for the ddd-context-map framework. */
3
3
  export declare const dddContextMapFramework: {
4
4
  readonly flag: "ddd-context-map";
5
- readonly telemetry: "ddd-context-map";
6
- readonly viewExtension: typeof DddContextMapViewExtension;
5
+ readonly telemetryKey: "context-map";
6
+ readonly extensions: readonly [{
7
+ readonly viewExtension: typeof DddContextMapRenderViewExtension;
8
+ }, {
9
+ readonly flag: "ddd-context-map";
10
+ readonly viewExtension: typeof DddContextMapViewExtension;
11
+ }];
7
12
  };
@@ -1,7 +1,10 @@
1
- import { DddContextMapViewExtension } from './view.js';
1
+ import { DddContextMapRenderViewExtension, DddContextMapViewExtension } from './view.js';
2
2
  /** Host wiring for the ddd-context-map framework. */
3
3
  export const dddContextMapFramework = {
4
4
  flag: 'ddd-context-map',
5
- telemetry: 'ddd-context-map',
6
- viewExtension: DddContextMapViewExtension,
5
+ telemetryKey: 'context-map',
6
+ extensions: [
7
+ { viewExtension: DddContextMapRenderViewExtension },
8
+ { flag: 'ddd-context-map', viewExtension: DddContextMapViewExtension },
9
+ ],
7
10
  };
@@ -0,0 +1,17 @@
1
+ import { type ElementRenderer } from '@formicoidea/labre-core/blocks/surface';
2
+ import type { ContextMapBoardElementModel } from '@formicoidea/labre-core/model';
3
+ /**
4
+ * Canvas renderer for the Context Map board.
5
+ *
6
+ * There is no Context Map drawing code: the board is an INSTANTIATION of the
7
+ * framework-background primitive, configured by the `CONTEXT_MAP_BACKGROUND`
8
+ * declaration — which, having no axes and no zones, paints the primitive's own
9
+ * default: a white card with a hairline border.
10
+ *
11
+ * Exported as a function as well as an extension so a test can drive it with a
12
+ * canvas stub.
13
+ */
14
+ export declare const contextMap: ElementRenderer<ContextMapBoardElementModel>;
15
+ export declare const ContextMapRendererExtension: import("@formicoidea/labre-core/store").ExtensionType & {
16
+ identifier: import("@formicoidea/labre-core/_pkgs/global/di").ServiceIdentifier<ElementRenderer<ContextMapBoardElementModel>>;
17
+ };
@@ -0,0 +1,15 @@
1
+ import { createFrameworkBackgroundRenderer, ElementRendererExtension, } from '@formicoidea/labre-core/blocks/surface';
2
+ import { CONTEXT_MAP_BACKGROUND } from './background.js';
3
+ /**
4
+ * Canvas renderer for the Context Map board.
5
+ *
6
+ * There is no Context Map drawing code: the board is an INSTANTIATION of the
7
+ * framework-background primitive, configured by the `CONTEXT_MAP_BACKGROUND`
8
+ * declaration — which, having no axes and no zones, paints the primitive's own
9
+ * default: a white card with a hairline border.
10
+ *
11
+ * Exported as a function as well as an extension so a test can drive it with a
12
+ * canvas stub.
13
+ */
14
+ export const contextMap = createFrameworkBackgroundRenderer(CONTEXT_MAP_BACKGROUND);
15
+ export const ContextMapRendererExtension = ElementRendererExtension(CONTEXT_MAP_BACKGROUND.type, contextMap);
@@ -0,0 +1,17 @@
1
+ import type { ContextMapBoardElementModel } from '@formicoidea/labre-core/model';
2
+ import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
3
+ /**
4
+ * View for the Context Map board. Registering it ensures `gfx.view.get(model)`
5
+ * returns a view (required so move / select interactions work).
6
+ *
7
+ * No double-click label editor, unlike the Wardley map: the declaration carries
8
+ * no text at all, so there is nothing on the card to hit-test.
9
+ */
10
+ export declare class ContextMapView extends GfxElementModelView<ContextMapBoardElementModel> {
11
+ static type: string;
12
+ }
13
+ /**
14
+ * Resize gating, from the primitive: the handles follow `resizeEnabled`, which
15
+ * the declaration seeds to `true` — a board is a sheet you spread out.
16
+ */
17
+ export declare const ContextMapInteraction: import("@formicoidea/labre-core/store").ExtensionType;
@@ -0,0 +1,18 @@
1
+ import { FrameworkBackgroundInteractionExtension } from '@formicoidea/labre-core/blocks/surface';
2
+ import { GfxElementModelView } from '@formicoidea/labre-core/std/gfx';
3
+ import { CONTEXT_MAP_BACKGROUND } from './background.js';
4
+ /**
5
+ * View for the Context Map board. Registering it ensures `gfx.view.get(model)`
6
+ * returns a view (required so move / select interactions work).
7
+ *
8
+ * No double-click label editor, unlike the Wardley map: the declaration carries
9
+ * no text at all, so there is nothing on the card to hit-test.
10
+ */
11
+ export class ContextMapView extends GfxElementModelView {
12
+ static { this.type = 'contextMap'; }
13
+ }
14
+ /**
15
+ * Resize gating, from the primitive: the handles follow `resizeEnabled`, which
16
+ * the declaration seeds to `true` — a board is a sheet you spread out.
17
+ */
18
+ export const ContextMapInteraction = FrameworkBackgroundInteractionExtension(CONTEXT_MAP_BACKGROUND);
package/dist/index.d.ts CHANGED
@@ -1,4 +1,11 @@
1
+ export { contextMapCommandIcons, contextMapCommands } from './commands.js';
2
+ export { CONTEXT_MAP_BACKGROUND } from './background.js';
3
+ export { CONTEXT_MAP_NUDGES } from './nudges.js';
4
+ export { CONTEXT_MAP_PROFILES } from './profiles.js';
5
+ export { CM_PATTERN_ROLE, CONTEXT_MAP_ROLE, CONTEXT_MAP_ROLES, type ContextMapPatternKind, type ContextMapRoleId, } from './roles.js';
6
+ export { CONTEXT_MAP_RULES } from './rules.js';
7
+ export { contextMapTranslationEntries } from './translations.js';
1
8
  export { contextMapTemplateCategory } from './templates.js';
2
9
  export { contextMapSeniorTool } from './toolbar/senior-tool.js';
3
10
  export { EdgelessDddContextMapSeniorButton } from './toolbar/senior-button.js';
4
- export { DddContextMapViewExtension } from './view.js';
11
+ export { DddContextMapRenderViewExtension, DddContextMapViewExtension, } from './view.js';
package/dist/index.js CHANGED
@@ -1,4 +1,11 @@
1
+ export { contextMapCommandIcons, contextMapCommands } from './commands.js';
2
+ export { CONTEXT_MAP_BACKGROUND } from './background.js';
3
+ export { CONTEXT_MAP_NUDGES } from './nudges.js';
4
+ export { CONTEXT_MAP_PROFILES } from './profiles.js';
5
+ export { CM_PATTERN_ROLE, CONTEXT_MAP_ROLE, CONTEXT_MAP_ROLES, } from './roles.js';
6
+ export { CONTEXT_MAP_RULES } from './rules.js';
7
+ export { contextMapTranslationEntries } from './translations.js';
1
8
  export { contextMapTemplateCategory } from './templates.js';
2
9
  export { contextMapSeniorTool } from './toolbar/senior-tool.js';
3
10
  export { EdgelessDddContextMapSeniorButton } from './toolbar/senior-button.js';
4
- export { DddContextMapViewExtension } from './view.js';
11
+ export { DddContextMapRenderViewExtension, DddContextMapViewExtension, } from './view.js';
@@ -0,0 +1,20 @@
1
+ import { type AutoLegendSpec } from '@formicoidea/labre-ddd-shared';
2
+ /**
3
+ * What the Context Map board's automatic legend can say — a TABLE, and nothing
4
+ * else: the scan, the placement and the box are `createAutoLegend`'s job.
5
+ *
6
+ * Every row is DERIVED from the presets the palette itself draws from
7
+ * ({@link CM_RELATIONSHIPS}, {@link CM_BUBBLE}) and from the role vocabulary's
8
+ * own labels, never restated. A tenth pattern added to `CM_RELATIONSHIPS` gets
9
+ * its legend row here with no edit, the same way it gets its role.
10
+ *
11
+ * ## What is missing, and why
12
+ *
13
+ * The **cloud** (the "System / Big Ball of Mud" blob) carries no role: it is
14
+ * created neutral by `commands.ts`, deliberately — the endpoint grammar treats a
15
+ * relationship drawn onto a cloud as a sketch and stays silent on it. Detection
16
+ * is by role and only by role, so the automatic legend cannot list the cloud and
17
+ * does not pretend to. The palette's static Legend entry still documents it, and
18
+ * the day the cloud earns a role its row lands here in one line.
19
+ */
20
+ export declare const CONTEXT_MAP_AUTO_LEGEND: AutoLegendSpec;
package/dist/legend.js ADDED
@@ -0,0 +1,56 @@
1
+ import { CM_BUBBLE, CM_RELATIONSHIPS, LABEL_COLOR, roleLabel, } from '@formicoidea/labre-ddd-shared';
2
+ import { CM_PATTERN_ROLE, CONTEXT_MAP_ROLE, CONTEXT_MAP_ROLES } from './roles.js';
3
+ /**
4
+ * What the Context Map board's automatic legend can say — a TABLE, and nothing
5
+ * else: the scan, the placement and the box are `createAutoLegend`'s job.
6
+ *
7
+ * Every row is DERIVED from the presets the palette itself draws from
8
+ * ({@link CM_RELATIONSHIPS}, {@link CM_BUBBLE}) and from the role vocabulary's
9
+ * own labels, never restated. A tenth pattern added to `CM_RELATIONSHIPS` gets
10
+ * its legend row here with no edit, the same way it gets its role.
11
+ *
12
+ * ## What is missing, and why
13
+ *
14
+ * The **cloud** (the "System / Big Ball of Mud" blob) carries no role: it is
15
+ * created neutral by `commands.ts`, deliberately — the endpoint grammar treats a
16
+ * relationship drawn onto a cloud as a sketch and stays silent on it. Detection
17
+ * is by role and only by role, so the automatic legend cannot list the cloud and
18
+ * does not pretend to. The palette's static Legend entry still documents it, and
19
+ * the day the cloud earns a role its row lands here in one line.
20
+ */
21
+ export const CONTEXT_MAP_AUTO_LEGEND = {
22
+ title: 'Legend',
23
+ width: 290,
24
+ roles: CONTEXT_MAP_ROLES,
25
+ sections: [
26
+ {
27
+ title: 'Boundaries',
28
+ entries: [
29
+ {
30
+ role: CONTEXT_MAP_ROLE.context,
31
+ row: {
32
+ swatch: 'square',
33
+ color: CM_BUBBLE.fill,
34
+ label: roleLabel(CONTEXT_MAP_ROLES, CONTEXT_MAP_ROLE.context),
35
+ },
36
+ },
37
+ ],
38
+ },
39
+ {
40
+ title: 'Relationships',
41
+ // One entry per PATTERN, not one for `context-map:relationship`: a legend
42
+ // that said "Relationship" would document nothing a reader could use. The
43
+ // dashed sample marks the two "no real integration" patterns, exactly as
44
+ // the board draws them.
45
+ entries: CM_RELATIONSHIPS.map(preset => ({
46
+ role: CM_PATTERN_ROLE[preset.kind],
47
+ row: {
48
+ swatch: 'line',
49
+ color: LABEL_COLOR,
50
+ dashed: preset.dashed,
51
+ label: `${preset.abbrev} — ${preset.label}`,
52
+ },
53
+ })),
54
+ },
55
+ ],
56
+ };
@@ -0,0 +1,19 @@
1
+ import type { QualityNudge } from '@formicoidea/labre-core/blocks/surface';
2
+ /**
3
+ * Context Mapping **map quality** — the checklist (WS2, level 2).
4
+ *
5
+ * `./rules.ts` is level 1: deterministic, decidable, real time. This file is
6
+ * everything a context map needs that no algorithm can decide. The split is the
7
+ * taxonomy's whole point — ticking is assuming, never verifying.
8
+ *
9
+ * Every one of the four is about whether a PATTERN WAS CHOSEN rather than
10
+ * defaulted to. That is the failure mode of context mapping in practice: the
11
+ * team draws nine links because there are nine integrations, picks the arrow
12
+ * that looks right, and ships a map that records the current wiring instead of
13
+ * the relationships. Nothing on the canvas can tell those two maps apart.
14
+ *
15
+ * Registered from the flag-gated `DddContextMapViewExtension`: a checklist is
16
+ * tooling. Switching the flag off takes it away and leaves the ticks written on
17
+ * the board, unread, until it comes back.
18
+ */
19
+ export declare const CONTEXT_MAP_NUDGES: readonly QualityNudge[];
package/dist/nudges.js ADDED
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Context Mapping **map quality** — the checklist (WS2, level 2).
3
+ *
4
+ * `./rules.ts` is level 1: deterministic, decidable, real time. This file is
5
+ * everything a context map needs that no algorithm can decide. The split is the
6
+ * taxonomy's whole point — ticking is assuming, never verifying.
7
+ *
8
+ * Every one of the four is about whether a PATTERN WAS CHOSEN rather than
9
+ * defaulted to. That is the failure mode of context mapping in practice: the
10
+ * team draws nine links because there are nine integrations, picks the arrow
11
+ * that looks right, and ships a map that records the current wiring instead of
12
+ * the relationships. Nothing on the canvas can tell those two maps apart.
13
+ *
14
+ * Registered from the flag-gated `DddContextMapViewExtension`: a checklist is
15
+ * tooling. Switching the flag off takes it away and leaves the ticks written on
16
+ * the board, unread, until it comes back.
17
+ */
18
+ export const CONTEXT_MAP_NUDGES = [
19
+ {
20
+ id: 'context-map.q1-pattern-discussed',
21
+ framework: 'ddd-context-map',
22
+ labelKey: 'com.labre.ddd-context-map.quality.pattern-discussed',
23
+ fallback: 'Every relationship carries a justified, discussed pattern — not the one that was easiest to draw.',
24
+ order: 1,
25
+ },
26
+ {
27
+ id: 'context-map.q2-separate-ways-documented',
28
+ framework: 'ddd-context-map',
29
+ labelKey: 'com.labre.ddd-context-map.quality.separate-ways',
30
+ fallback: 'Separate Ways are documented: it is written down why there is no integration.',
31
+ order: 2,
32
+ },
33
+ {
34
+ /**
35
+ * The rule this nudge replaces. "Every downstream of a Big Ball of Mud is
36
+ * protected" is decidable in principle — walk the edges out of the cloud and
37
+ * look for an ACL — and undecidable in practice on THIS canvas: the cloud
38
+ * carries no role (a v1 cut), so there is nothing for a rule to walk from,
39
+ * and a shape somebody drew a mess with is not a claim that it IS one.
40
+ * Level 2 is the honest home for it until the cloud has a role.
41
+ */
42
+ id: 'context-map.q3-bbom-protected',
43
+ framework: 'ddd-context-map',
44
+ labelKey: 'com.labre.ddd-context-map.quality.bbom-protected',
45
+ fallback: 'Every downstream of a Big Ball of Mud is protected by an Anticorruption Layer.',
46
+ order: 3,
47
+ },
48
+ {
49
+ id: 'context-map.q4-legend',
50
+ framework: 'ddd-context-map',
51
+ labelKey: 'com.labre.ddd-context-map.quality.legend',
52
+ fallback: 'The map has a legend: a reader who does not know the notation can read it.',
53
+ order: 4,
54
+ },
55
+ ];
@@ -0,0 +1,2 @@
1
+ import type { ValidationProfile } from '@formicoidea/labre-core/blocks/surface';
2
+ export declare const CONTEXT_MAP_PROFILES: readonly ValidationProfile[];